VideoTools
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
grimagedata.h
Go to the documentation of this file.
1 //
2 // Copyright (C) 2017 Graeme Walker
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
16 // ===
17 ///
18 /// \file grimagedata.h
19 ///
20 
21 #ifndef GR_IMAGE_DATA__H
22 #define GR_IMAGE_DATA__H
23 
24 #include "gdef.h"
25 #include "grdef.h"
26 #include "grcolour.h"
27 #include "grimagebuffer.h"
28 #include "gexception.h"
29 #include <vector>
30 
31 namespace Gr
32 {
33  class ImageData ;
34  class ImageDataWrapper ;
35  class ImageDataWriter ;
36 }
37 
38 /// \class Gr::ImageData
39 /// A holder for image data, having eight bits per sample and one or three
40 /// channels. The data can be either contiguous or allocated row by row.
41 ///
42 /// This class is primarily intended as an output target for the various
43 /// decoders, and a data source for their encoders. See also Gr::JpegReader,
44 /// Gr::PngReader, Gr::PnmReader.
45 ///
47 {
48 public:
49  G_EXCEPTION( Error , "image data error" ) ;
50  enum Type // a type-safe boolean indicating contiguous or row-by-row storage
51  { Segmented , Contiguous } ;
52 
53  explicit ImageData( Type = Segmented ) ;
54  ///< Default constructor for a zero-size image. After contstruction the
55  ///< object should normally be resize()d. The Contiguous/Segmented type
56  ///< does not change across resize(). A Contiguous object has a usable
57  ///< p() method that returns a single pointer to the whole image.
58 
59  ImageData( ImageBuffer & image_buffer , Type = Segmented ) ;
60  ///< Constructor for an empty ImageData object that wraps an empty
61  ///< ImageBuffer.
62  ///< Precondition: image_buffer.empty()
63 
64  ImageData( ImageBuffer & , int dx , int dy , int channels ) ;
65  ///< Constructor for an ImageData object that wraps the given ImageBuffer.
66  ///< The image buffer can be empty, but its dimensions must always match
67  ///< the other parameters. This ImageData object type() will be contiguous
68  ///< or segmented to match the supplied image buffer, or contiguous by
69  ///< default if dy is less than two.
70 
71  ~ImageData() ;
72  ///< Destructor.
73 
74  Type type() const ;
75  ///< Returns the contiguous/segmented enumeration. Contiguous objects
76  ///< have a usable p() method that returns a pointer to the whole image.
77 
78  int dx() const ;
79  ///< Returns the width.
80 
81  int dy() const ;
82  ///< Returns the height.
83 
84  int channels() const ;
85  ///< Returns the number of channels (zero, one or three).
86 
87  bool empty() const ;
88  ///< Returns true if the size() is zero.
89 
90  size_t size() const ;
91  ///< Returns the total image size, ie. dx()*dy()*channels().
92 
93  size_t rowsize() const ;
94  ///< Returns the row size, ie. dx()*channels().
95 
96  void resize( int dx , int dy , int channels ) ;
97  ///< Resizes the image data.
98 
99  unsigned char r( int x , int y ) const ;
100  ///< Returns the R-value for a point.
101 
102  unsigned char g( int x , int y ) const ;
103  ///< Returns the G-value for a point. Returns the R-value if there is only one channel.
104 
105  unsigned char b( int x , int y ) const ;
106  ///< Returns the B-value for a point. Returns the R-value if there is only one channel.
107 
108  unsigned int rgb( int x , int y ) const ;
109  ///< Returns the colour of a pixel as rgb values packed into one integer.
110 
111  void rgb( int x , int y , unsigned char r , unsigned char g , unsigned char b ) ;
112  ///< Sets a pixel colour. The trailing 'g' and 'b' values are ignored if there is
113  ///< only one channel.
114 
115  void fill( unsigned char r , unsigned char g , unsigned char b ) ;
116  ///< Fills the image with a solid colour as if calling rgb() for every pixel.
117 
118  ImageDataWriter writer( int x , int y , Colour foreground , Colour background ,
119  bool draw_background , bool wrap_on_nl ) ;
120  ///< Returns a functor that calls write().
121 
122  void write( char c , int x , int y , Colour foreground , Colour background ,
123  bool draw_background ) ;
124  ///< Draws a latin-1 character into the image at the given position.
125 
126  unsigned char * row( int y ) ;
127  ///< Returns a pointer to the y'th row.
128 
129  const unsigned char * row( int y ) const ;
130  ///< Returns a const pointer to the y'th row.
131 
132  unsigned char ** rowPointers() ;
133  ///< Returns a pointer to the array of row pointers.
134 
135  const unsigned char * const * rowPointers() const ;
136  ///< Returns a pointer to the array of const row pointers.
137 
138  char ** rowPointers( int ) ;
139  ///< An overload returning a char pointer array.
140 
141  const unsigned char * p() const ;
142  ///< Returns a const pointer to the image data, but throws if the data is not
143  ///< contiguous.
144 
145  unsigned char * p() ;
146  ///< Returns a pointer to the image data, but throws if the data is not
147  ///< contiguous.
148 
149  void copyRowIn( int y , const unsigned char * row_buffer_in , size_t row_buffer_in_size , int channels_in ,
150  bool use_colourspace = false , int scale = 1 ) ;
151  ///< Sets a row of pixels by copying, with channel-count adjustment and
152  ///< optional scaling.
153  ///<
154  ///< If the number of channels is reduced then there is the option to
155  ///< either take the first channel or do a colourspace transform.
156  ///< Prefer a direct memcpy() to row() for speed where possible.
157 
158  void copyIn( const char * data_in , size_t data_size_in , int dx_in , int dy_in , int channels_in ,
159  bool use_colourspace = false , int scale = 1 ) ;
160  ///< Copies the image in from a raw buffer, with channel-count adjustment
161  ///< and optional scaling, but no resize(). The 'monochrome-out' parameter
162  ///< is implicit in the current number of channels and the number of channels
163  ///< passed in.
164  ///<
165  ///< If the number of channels is reduced then there is the option to
166  ///< just take the first channel or do a colourspace transform.
167  ///< Prefer a direct memcpy()s to row()s for speed where possible.
168 
169  void copyIn( const ImageBuffer & data_in , int dx_in , int dy_in , int channels_in ,
170  bool use_colourspace = false , int scale = 1 ) ;
171  ///< Overload that copies from an ImageBuffer. The dx and dy parameters are used
172  ///< as a sanity check against the dimensions of the ImageBuffer.
173 
174  void copyRowOut( int y , std::vector<char> & out , int scale = 1 , bool monochrome_out = false , bool use_colourspace = true ) const ;
175  ///< Copies a row into the given output buffer, resizing the output vector
176  ///< as necessary.
177 
178  void copyTo( std::vector<char> & out ) const ;
179  ///< Copies the image to the given output buffer, resizing the output vector
180  ///< as necessary.
181 
182  void copyTo( ImageBuffer & out ) const ;
183  ///< Copies the image to the given ImageBuffer, resizing the output
184  ///< as necessary.
185 
186  void scale( int factor , bool monochrome , bool use_colourspace ) ;
187  ///< Scales-down the image by sub-sampling.
188 
189  void dim( unsigned int shift ) ;
190  ///< Dims the image by right-shifting all pixel values.
191 
192  void dim( unsigned int numerator , unsigned int denominator ) ;
193  ///< Dims the image by multiplying all pixel values by the given fraction.
194  ///< Use small numbers to avoid arithmetic overflow.
195 
196  void mix( const ImageData & _1 , const ImageData & _2 , unsigned int numerator_1 , unsigned int numerator_2 , unsigned int denominator ) ;
197  ///< Creates a mixed image from two equally-shaped sources images.
198  ///< There is no colourspace subtelty; mixing is done separately
199  ///< for each channel so arithmetic overflow will create colour
200  ///< distortion.
201 
202  void add( const ImageData & other ) ;
203  ///< Adds the given image data to this.
204 
205  void subtract( const ImageData & other ) ;
206  ///< Subtracts the given image data from this.
207 
208  void crop( int dx , int dy ) ;
209  ///< Crops the image so that it fits inside the given dimensions.
210  ///< Does nothing if the image is already small enough.
211 
212  void expand( int dx , int dy ) ;
213  ///< Expands the image so that the new image has the dimensions given,
214  ///< with the original image centered inside using black borders.
215  ///< Does nothing if the image is already big enough.
216 
217 private:
218  ImageData( const ImageData & ) ;
219  void operator=( const ImageData & ) ;
220  void copyRowInImp( unsigned char * , const unsigned char * , int , bool , int ) ;
221  unsigned char * storerow( int y ) ;
222  const unsigned char * storerow( int y ) const ;
223  void setRows() const ;
224  bool valid() const ;
225  bool contiguous() const ;
226  template <typename Fn> void modify( Fn fn ) ;
227  template <typename Fn> void modify( const Gr::ImageData & other , Fn fn ) ;
228  template <typename Fn> void modify( const Gr::ImageData & , const Gr::ImageData & , Fn fn ) ;
229 
230 private:
231  const Type m_type ;
232  int m_dx ;
233  int m_dy ;
234  int m_channels ;
235  ImageBuffer m_data_store ;
236  ImageBuffer & m_data ;
237  mutable bool m_rows_set ;
238  mutable std::vector<unsigned char*> m_rows ;
239 } ;
240 
241 /// \class Gr::ImageDataWrapper
242 /// A class that wraps a read-only image buffer with a few methods that are
243 /// similar to those of Gr::ImageData.
244 ///
246 {
247 public:
248  ImageDataWrapper( const ImageBuffer & , int dx , int dy , int channels ) ;
249  ///< Constructor.
250 
251  int dx() const ;
252  ///< Returns the width.
253 
254  int dy() const ;
255  ///< Returns the height.
256 
257  int channels() const ;
258  ///< Returns the number of channels.
259 
260  const unsigned char * row( int y ) const ;
261  ///< Returns a pointer to the y-th row.
262 
263  unsigned char r( int x , int y ) const ;
264  ///< Returns the R-value for a point.
265 
266  unsigned char g( int x , int y ) const ;
267  ///< Returns the G-value for a point. Returns the R-value if there is only one channel.
268 
269  unsigned char b( int x , int y ) const ;
270  ///< Returns the B-value for a point. Returns the R-value if there is only one channel.
271 
272  unsigned int rgb( int x , int y ) const ;
273  ///< Returns the colour of a pixel as rgb values packed into one integer.
274 
275 private:
277  void operator=( const ImageDataWrapper & ) ;
278 
279 private:
280  const ImageBuffer & m_image_buffer ;
281  int m_dx ;
282  int m_dy ;
283  int m_channels ;
284 } ;
285 
287 {
288 public:
289  ImageDataWriter( Gr::ImageData & data , int x , int y ,
290  Gr::Colour foreground , Gr::Colour background ,
291  bool draw_background , bool wrap_on_nl ) ;
292  ///< Constructor.
293 
294  template <typename T> void write( T p , T end ) ;
295  ///< Calls ImageData::write() for each character in the range.
296 
297 private:
298  bool pre( char ) ;
299  void post( char ) ;
300 
301 private:
302  Gr::ImageData * m_data ;
303  int m_dx ;
304  int m_dy ;
305  int m_x0 ;
306  int m_x ;
307  int m_y ;
308  Gr::Colour m_foreground ;
309  Gr::Colour m_background ;
310  bool m_draw_background ;
311  bool m_wrap_on_nl ;
312 } ;
313 
314 template <typename T>
315 void Gr::ImageDataWriter::write( T p , T end )
316 {
317  for( ; p != end ; ++p )
318  {
319  if( pre(*p) )
320  {
321  m_data->write( *p , m_x , m_y , m_foreground , m_background , m_draw_background ) ;
322  post( *p ) ;
323  }
324  }
325 }
326 
327 
328 inline
329 int Gr::ImageData::dx() const
330 {
331  return m_dx ;
332 }
333 
334 inline
335 int Gr::ImageData::dy() const
336 {
337  return m_dy ;
338 }
339 
340 inline
342 {
343  return m_channels ;
344 }
345 
346 inline
347 unsigned char * Gr::ImageData::storerow( int y )
348 {
349  return reinterpret_cast<unsigned char*>( &(m_data[y])[0] ) ;
350 }
351 
352 inline
353 const unsigned char * Gr::ImageData::storerow( int y ) const
354 {
355  return reinterpret_cast<const unsigned char*>( &(m_data[y])[0] ) ;
356 }
357 
358 inline
359 const unsigned char * Gr::ImageData::row( int y ) const
360 {
361  return
362  m_type == Contiguous ?
363  ( storerow(0) + sizet(y,m_dx,m_channels) ) :
364  storerow( y ) ;
365 }
366 
367 inline
368 unsigned char * Gr::ImageData::row( int y )
369 {
370  return
371  m_type == Contiguous ?
372  ( storerow(0) + sizet(y,m_dx,m_channels) ) :
373  storerow( y ) ;
374 }
375 
376 inline
377 void Gr::ImageData::rgb( int x , int y , unsigned char r , unsigned char g , unsigned char b )
378 {
379  int x_offset = m_channels == 1 ? x : (x*3) ;
380  unsigned char * out_p = row(y) + x_offset ;
381  *out_p++ = r ;
382  if( m_channels != 1 )
383  {
384  *out_p++ = g ;
385  *out_p++ = b ;
386  }
387 }
388 
389 inline
390 unsigned char Gr::ImageData::r( int x , int y ) const
391 {
392  const unsigned char * row_p = m_rows_set ? m_rows[y] : row(y) ;
393  return m_channels == 1 ? row_p[x] : row_p[x*3] ;
394 }
395 
396 inline
397 unsigned char Gr::ImageData::g( int x , int y ) const
398 {
399  const unsigned char * row_p = m_rows_set ? m_rows[y] : row(y) ;
400  return m_channels == 1 ? row_p[x] : row_p[x*3+1] ;
401 }
402 
403 inline
404 unsigned char Gr::ImageData::b( int x , int y ) const
405 {
406  const unsigned char * row_p = m_rows_set ? m_rows[y] : row(y) ;
407  return m_channels == 1 ? row_p[x] : row_p[x*3+2] ;
408 }
409 
410 inline
411 unsigned int Gr::ImageData::rgb( int x , int y ) const
412 {
413  return
414  ( static_cast<unsigned int>(r(x,y)) << 16 ) |
415  ( static_cast<unsigned int>(g(x,y)) << 8 ) |
416  ( static_cast<unsigned int>(r(x,y)) << 0 ) ;
417 }
418 
419 
420 inline
421 Gr::ImageDataWrapper::ImageDataWrapper( const ImageBuffer & image_buffer , int dx , int dy , int channels ) :
422  m_image_buffer(image_buffer) ,
423  m_dx(dx) ,
424  m_dy(dy) ,
425  m_channels(channels)
426 {
427  if( dx <= 0 || dy <= 0 || (channels != 1 && channels != 3) ||
428  ( image_buffer.size() != 1U && image_buffer.size() != sizet(dy) ) ||
429  imagebuffer::size_of(image_buffer) != sizet(dx,dy,channels) )
430  throw ImageData::Error() ;
431 }
432 
433 inline
435 {
436  return m_dx ;
437 }
438 
439 inline
441 {
442  return m_dy ;
443 }
444 
445 inline
447 {
448  return m_channels ;
449 }
450 
451 inline
452 const unsigned char * Gr::ImageDataWrapper::row( int y ) const
453 {
454  if( m_image_buffer.size() == 1U && y > 0 && y < m_dy )
455  return reinterpret_cast<const unsigned char*>(&(m_image_buffer.at(0))[0]) + sizet(y,m_dx,m_channels) ;
456  else
457  return reinterpret_cast<const unsigned char*>(&(m_image_buffer.at(y))[0]) ;
458 }
459 
460 inline
461 unsigned char Gr::ImageDataWrapper::r( int x , int y ) const
462 {
463  const unsigned char * row_p = row( y ) ;
464  return m_channels == 1 ? row_p[x] : row_p[x*3] ;
465 }
466 
467 inline
468 unsigned char Gr::ImageDataWrapper::g( int x , int y ) const
469 {
470  const unsigned char * row_p = row( y ) ;
471  return m_channels == 1 ? row_p[x] : row_p[x*3+1] ;
472 }
473 
474 inline
475 unsigned char Gr::ImageDataWrapper::b( int x , int y ) const
476 {
477  const unsigned char * row_p = row( y ) ;
478  return m_channels == 1 ? row_p[x] : row_p[x*3+2] ;
479 }
480 
481 inline
482 unsigned int Gr::ImageDataWrapper::rgb( int x , int y ) const
483 {
484  return
485  ( static_cast<unsigned int>(r(x,y)) << 16 ) |
486  ( static_cast<unsigned int>(g(x,y)) << 8 ) |
487  ( static_cast<unsigned int>(r(x,y)) << 0 ) ;
488 }
489 
490 #endif
unsigned char b(int x, int y) const
Returns the B-value for a point. Returns the R-value if there is only one channel.
Definition: grimagedata.h:475
size_t rowsize() const
Returns the row size, ie. dx()*channels().
int dx() const
Returns the width.
Definition: grimagedata.h:329
A holder for image data, having eight bits per sample and one or three channels.
Definition: grimagedata.h:46
void mix(const ImageData &_1, const ImageData &_2, unsigned int numerator_1, unsigned int numerator_2, unsigned int denominator)
Creates a mixed image from two equally-shaped sources images.
void write(T p, T end)
Calls ImageData::write() for each character in the range.
Definition: grimagedata.h:315
size_t size() const
Returns the total image size, ie. dx()*dy()*channels().
void resize(int dx, int dy, int channels)
Resizes the image data.
Definition: grimagedata.cpp:89
unsigned char r(int x, int y) const
Returns the R-value for a point.
Definition: grimagedata.h:390
void expand(int dx, int dy)
Expands the image so that the new image has the dimensions given, with the original image centered in...
Type type() const
Returns the contiguous/segmented enumeration.
Definition: grimagedata.cpp:79
unsigned char * row(int y)
Returns a pointer to the y'th row.
Definition: grimagedata.h:368
const unsigned char * row(int y) const
Returns a pointer to the y-th row.
Definition: grimagedata.h:452
void scale(int factor, bool monochrome, bool use_colourspace)
Scales-down the image by sub-sampling.
A simple rgb colour structure.
Definition: grcolour.h:36
Vectors ImageBuffer
An ImageBuffer is used to hold raw image data, typically in more than one chunk.
Definition: grimagebuffer.h:47
unsigned char r(int x, int y) const
Returns the R-value for a point.
Definition: grimagedata.h:461
bool empty() const
Returns true if the size() is zero.
Definition: grimagedata.cpp:84
unsigned char g(int x, int y) const
Returns the G-value for a point. Returns the R-value if there is only one channel.
Definition: grimagedata.h:397
unsigned char g(int x, int y) const
Returns the G-value for a point. Returns the R-value if there is only one channel.
Definition: grimagedata.h:468
void subtract(const ImageData &other)
Subtracts the given image data from this.
unsigned int rgb(int x, int y) const
Returns the colour of a pixel as rgb values packed into one integer.
Definition: grimagedata.h:482
~ImageData()
Destructor.
Definition: grimagedata.cpp:75
unsigned char ** rowPointers()
Returns a pointer to the array of row pointers.
void copyTo(std::vector< char > &out) const
Copies the image to the given output buffer, resizing the output vector as necessary.
int channels() const
Returns the number of channels.
Definition: grimagedata.h:446
unsigned char b(int x, int y) const
Returns the B-value for a point. Returns the R-value if there is only one channel.
Definition: grimagedata.h:404
int dy() const
Returns the height.
Definition: grimagedata.h:440
ImageDataWriter(Gr::ImageData &data, int x, int y, Gr::Colour foreground, Gr::Colour background, bool draw_background, bool wrap_on_nl)
Constructor.
void copyIn(const char *data_in, size_t data_size_in, int dx_in, int dy_in, int channels_in, bool use_colourspace=false, int scale=1)
Copies the image in from a raw buffer, with channel-count adjustment and optional scaling...
int channels() const
Returns the number of channels (zero, one or three).
Definition: grimagedata.h:341
void copyRowIn(int y, const unsigned char *row_buffer_in, size_t row_buffer_in_size, int channels_in, bool use_colourspace=false, int scale=1)
Sets a row of pixels by copying, with channel-count adjustment and optional scaling.
A class that wraps a read-only image buffer with a few methods that are similar to those of Gr::Image...
Definition: grimagedata.h:245
void dim(unsigned int shift)
Dims the image by right-shifting all pixel values.
const unsigned char * p() const
Returns a const pointer to the image data, but throws if the data is not contiguous.
unsigned int rgb(int x, int y) const
Returns the colour of a pixel as rgb values packed into one integer.
Definition: grimagedata.h:411
ImageData(Type=Segmented)
Default constructor for a zero-size image.
Definition: grimagedata.cpp:30
void fill(unsigned char r, unsigned char g, unsigned char b)
Fills the image with a solid colour as if calling rgb() for every pixel.
ImageDataWriter writer(int x, int y, Colour foreground, Colour background, bool draw_background, bool wrap_on_nl)
Returns a functor that calls write().
void crop(int dx, int dy)
Crops the image so that it fits inside the given dimensions.
void copyRowOut(int y, std::vector< char > &out, int scale=1, bool monochrome_out=false, bool use_colourspace=true) const
Copies a row into the given output buffer, resizing the output vector as necessary.
ImageDataWrapper(const ImageBuffer &, int dx, int dy, int channels)
Constructor.
Definition: grimagedata.h:421
void add(const ImageData &other)
Adds the given image data to this.
int dy() const
Returns the height.
Definition: grimagedata.h:335
int dx() const
Returns the width.
Definition: grimagedata.h:434
void write(char c, int x, int y, Colour foreground, Colour background, bool draw_background)
Draws a latin-1 character into the image at the given position.