Boost GIL


image.hpp
1 //
2 // Copyright 2005-2007 Adobe Systems Incorporated
3 //
4 // Distributed under the Boost Software License, Version 1.0
5 // See accompanying file LICENSE_1_0.txt or copy at
6 // http://www.boost.org/LICENSE_1_0.txt
7 //
8 #ifndef BOOST_GIL_IMAGE_HPP
9 #define BOOST_GIL_IMAGE_HPP
10 
11 #include <boost/gil/algorithm.hpp>
12 #include <boost/gil/image_view.hpp>
13 #include <boost/gil/metafunctions.hpp>
14 
15 #include <boost/mpl/arithmetic.hpp>
16 #include <boost/mpl/bool.hpp>
17 #include <boost/mpl/if.hpp>
18 
19 #include <cstddef>
20 #include <memory>
21 
22 namespace boost { namespace gil {
23 
37 
38 template< typename Pixel, bool IsPlanar = false, typename Alloc=std::allocator<unsigned char> >
39 class image {
40 public:
41 #if defined(BOOST_NO_CXX11_ALLOCATOR)
42  using allocator_type = typename Alloc::template rebind<unsigned char>::other;
43 #else
44  using allocator_type = typename std::allocator_traits<Alloc>::template rebind_alloc<unsigned char>;
45 #endif
46  using view_t = typename view_type_from_pixel<Pixel, IsPlanar>::type;
47  using const_view_t = typename view_t::const_t;
48  using point_t = typename view_t::point_t;
49  using coord_t = typename view_t::coord_t;
50  using value_type = typename view_t::value_type;
51  using x_coord_t = coord_t;
52  using y_coord_t = coord_t;
53 
54  const point_t& dimensions() const { return _view.dimensions(); }
55  x_coord_t width() const { return _view.width(); }
56  y_coord_t height() const { return _view.height(); }
57 
58  explicit image(std::size_t alignment=0,
59  const Alloc alloc_in = Alloc()) :
60  _memory(nullptr), _align_in_bytes(alignment), _alloc(alloc_in), _allocated_bytes( 0 ) {}
61 
62  // Create with dimensions and optional initial value and alignment
63  image(const point_t& dimensions,
64  std::size_t alignment=0,
65  const Alloc alloc_in = Alloc()) : _memory(nullptr), _align_in_bytes(alignment), _alloc(alloc_in)
66  , _allocated_bytes( 0 ) {
67  allocate_and_default_construct(dimensions);
68  }
69 
70  image(x_coord_t width, y_coord_t height,
71  std::size_t alignment=0,
72  const Alloc alloc_in = Alloc()) : _memory(nullptr), _align_in_bytes(alignment), _alloc(alloc_in)
73  , _allocated_bytes( 0 ) {
74  allocate_and_default_construct(point_t(width,height));
75  }
76 
77  image(const point_t& dimensions,
78  const Pixel& p_in,
79  std::size_t alignment,
80  const Alloc alloc_in = Alloc()) : _memory(nullptr), _align_in_bytes(alignment), _alloc(alloc_in)
81  , _allocated_bytes( 0 ) {
82  allocate_and_fill(dimensions, p_in);
83  }
84  image(x_coord_t width, y_coord_t height,
85  const Pixel& p_in,
86  std::size_t alignment = 0,
87  const Alloc alloc_in = Alloc()) : _memory(nullptr), _align_in_bytes(alignment), _alloc(alloc_in)
88  , _allocated_bytes ( 0 ) {
89  allocate_and_fill(point_t(width,height),p_in);
90  }
91 
92  image(const image& img) : _memory(nullptr), _align_in_bytes(img._align_in_bytes), _alloc(img._alloc)
93  , _allocated_bytes( img._allocated_bytes ) {
94  allocate_and_copy(img.dimensions(),img._view);
95  }
96 
97  template <typename P2, bool IP2, typename Alloc2>
98  image(const image<P2,IP2,Alloc2>& img) : _memory(nullptr), _align_in_bytes(img._align_in_bytes), _alloc(img._alloc)
99  , _allocated_bytes( img._allocated_bytes ) {
100  allocate_and_copy(img.dimensions(),img._view);
101  }
102 
103  image& operator=(const image& img) {
104  if (dimensions() == img.dimensions())
105  copy_pixels(img._view,_view);
106  else {
107  image tmp(img);
108  swap(tmp);
109  }
110  return *this;
111  }
112 
113  template <typename Img>
114  image& operator=(const Img& img) {
115  if (dimensions() == img.dimensions())
116  copy_pixels(img._view,_view);
117  else {
118  image tmp(img);
119  swap(tmp);
120  }
121  return *this;
122  }
123 
124  ~image() {
125  destruct_pixels(_view);
126  deallocate();
127  }
128 
129  Alloc& allocator() { return _alloc; }
130  Alloc const& allocator() const { return _alloc; }
131 
132  void swap(image& img) { // required by MutableContainerConcept
133  using std::swap;
134  swap(_align_in_bytes, img._align_in_bytes);
135  swap(_memory, img._memory);
136  swap(_view, img._view);
137  swap(_alloc, img._alloc);
138  swap(_allocated_bytes, img._allocated_bytes );
139  }
140 
142  // recreate
144 
145  // without Allocator
146 
147  void recreate( const point_t& dims, std::size_t alignment = 0 )
148  {
149  if( dims == _view.dimensions() && _align_in_bytes == alignment )
150  {
151  return;
152  }
153 
154  _align_in_bytes = alignment;
155 
156  if( _allocated_bytes >= total_allocated_size_in_bytes( dims ) )
157  {
158  destruct_pixels( _view );
159 
160  create_view( dims
161  , typename mpl::bool_<IsPlanar>()
162  );
163 
164  default_construct_pixels( _view );
165  }
166  else
167  {
168  image tmp( dims, alignment );
169  swap( tmp );
170  }
171  }
172 
173  void recreate( x_coord_t width, y_coord_t height, std::size_t alignment = 0 )
174  {
175  recreate( point_t( width, height ), alignment );
176  }
177 
178 
179  void recreate( const point_t& dims, const Pixel& p_in, std::size_t alignment = 0 )
180  {
181  if( dims == _view.dimensions() && _align_in_bytes == alignment )
182  {
183  return;
184  }
185 
186  _align_in_bytes = alignment;
187 
188  if( _allocated_bytes >= total_allocated_size_in_bytes( dims ) )
189  {
190  destruct_pixels( _view );
191 
192  create_view( dims
193  , typename mpl::bool_<IsPlanar>()
194  );
195 
196  uninitialized_fill_pixels(_view, p_in);
197  }
198  else
199  {
200  image tmp( dims, p_in, alignment );
201  swap( tmp );
202  }
203  }
204 
205  void recreate( x_coord_t width, y_coord_t height, const Pixel& p_in, std::size_t alignment = 0 )
206  {
207  recreate( point_t( width, height ), p_in, alignment );
208  }
209 
210 
211  // with Allocator
212  void recreate(const point_t& dims, std::size_t alignment, const Alloc alloc_in )
213  {
214  if( dims == _view.dimensions()
215  && _align_in_bytes == alignment
216  && alloc_in == _alloc
217  )
218  {
219  return;
220  }
221 
222  _align_in_bytes = alignment;
223 
224  if( _allocated_bytes >= total_allocated_size_in_bytes( dims ) )
225  {
226  destruct_pixels( _view );
227 
228  create_view( dims
229  , typename mpl::bool_<IsPlanar>()
230  );
231 
232  default_construct_pixels( _view );
233  }
234  else
235  {
236  image tmp( dims, alignment, alloc_in );
237  swap( tmp );
238  }
239  }
240 
241  void recreate( x_coord_t width, y_coord_t height, std::size_t alignment, const Alloc alloc_in )
242  {
243  recreate( point_t( width, height ), alignment, alloc_in );
244  }
245 
246  void recreate(const point_t& dims, const Pixel& p_in, std::size_t alignment, const Alloc alloc_in )
247  {
248  if( dims == _view.dimensions()
249  && _align_in_bytes == alignment
250  && alloc_in == _alloc
251  )
252  {
253  return;
254  }
255 
256  _align_in_bytes = alignment;
257 
258  if( _allocated_bytes >= total_allocated_size_in_bytes( dims ) )
259  {
260  destruct_pixels( _view );
261 
262  create_view( dims
263  , typename mpl::bool_<IsPlanar>()
264  );
265 
266  uninitialized_fill_pixels(_view, p_in);
267  }
268  else
269  {
270  image tmp( dims, p_in, alignment, alloc_in );
271  swap( tmp );
272  }
273  }
274 
275  void recreate(x_coord_t width, y_coord_t height, const Pixel& p_in, std::size_t alignment, const Alloc alloc_in )
276  {
277  recreate( point_t( width, height ), p_in,alignment, alloc_in );
278  }
279 
280 
281 
282  view_t _view; // contains pointer to the pixels, the image size and ways to navigate pixels
283 private:
284  unsigned char* _memory;
285  std::size_t _align_in_bytes;
286  allocator_type _alloc;
287 
288  std::size_t _allocated_bytes;
289 
290 
291  void allocate_and_default_construct(const point_t& dimensions) {
292  try {
293  allocate_(dimensions,mpl::bool_<IsPlanar>());
295  } catch(...) { deallocate(); throw; }
296  }
297 
298  void allocate_and_fill(const point_t& dimensions, const Pixel& p_in) {
299  try {
300  allocate_(dimensions,mpl::bool_<IsPlanar>());
301  uninitialized_fill_pixels(_view, p_in);
302  } catch(...) { deallocate(); throw; }
303  }
304 
305  template <typename View>
306  void allocate_and_copy(const point_t& dimensions, const View& v) {
307  try {
308  allocate_(dimensions,mpl::bool_<IsPlanar>());
309  uninitialized_copy_pixels(v,_view);
310  } catch(...) { deallocate(); throw; }
311  }
312 
313  void deallocate() {
314  if (_memory && _allocated_bytes > 0 )
315  {
316  _alloc.deallocate(_memory, _allocated_bytes );
317  }
318  }
319 
320  std::size_t is_planar_impl( const std::size_t size_in_units
321  , const std::size_t channels_in_image
322  , mpl::true_
323  ) const
324  {
325  return size_in_units * channels_in_image;
326  }
327 
328  std::size_t is_planar_impl( const std::size_t size_in_units
329  , const std::size_t
330  , mpl::false_
331  ) const
332  {
333  return size_in_units;
334  }
335 
336  std::size_t total_allocated_size_in_bytes(const point_t& dimensions) const {
337 
338  using x_iterator = typename view_t::x_iterator;
339 
340  // when value_type is a non-pixel, like int or float, num_channels< ... > doesn't work.
341  const std::size_t _channels_in_image = mpl::eval_if< is_pixel< value_type >
343  , mpl::int_< 1 >
344  >::type::value;
345 
346  std::size_t size_in_units = is_planar_impl( get_row_size_in_memunits( dimensions.x ) * dimensions.y
347  , _channels_in_image
348  , typename mpl::bool_<IsPlanar>()
349  );
350 
351  // return the size rounded up to the nearest byte
352  return ( size_in_units + byte_to_memunit< x_iterator >::value - 1 )
354  + ( _align_in_bytes > 0 ? _align_in_bytes - 1 : 0 ); // add extra padding in case we need to align the first image pixel
355  }
356 
357  std::size_t get_row_size_in_memunits(x_coord_t width) const { // number of units per row
358  std::size_t size_in_memunits = width*memunit_step(typename view_t::x_iterator());
359  if (_align_in_bytes>0) {
360  std::size_t alignment_in_memunits=_align_in_bytes*byte_to_memunit<typename view_t::x_iterator>::value;
361  return align(size_in_memunits, alignment_in_memunits);
362  }
363  return size_in_memunits;
364  }
365 
366  void allocate_(const point_t& dimensions, mpl::false_) { // if it throws and _memory!=0 the client must deallocate _memory
367 
368  _allocated_bytes = total_allocated_size_in_bytes(dimensions);
369  _memory=_alloc.allocate( _allocated_bytes );
370 
371  unsigned char* tmp=(_align_in_bytes>0) ? (unsigned char*)align((std::size_t)_memory,_align_in_bytes) : _memory;
372  _view=view_t(dimensions,typename view_t::locator(typename view_t::x_iterator(tmp),get_row_size_in_memunits(dimensions.x)));
373  }
374 
375  void allocate_(const point_t& dimensions, mpl::true_) { // if it throws and _memory!=0 the client must deallocate _memory
376  std::size_t row_size=get_row_size_in_memunits(dimensions.x);
377  std::size_t plane_size=row_size*dimensions.y;
378 
379  _allocated_bytes = total_allocated_size_in_bytes( dimensions );
380 
381  _memory = _alloc.allocate( _allocated_bytes );
382 
383  unsigned char* tmp=(_align_in_bytes>0) ? (unsigned char*)align((std::size_t)_memory,_align_in_bytes) : _memory;
384  typename view_t::x_iterator first;
385  for (int i=0; i<num_channels<view_t>::value; ++i) {
386  dynamic_at_c(first,i) = (typename channel_type<view_t>::type*)tmp;
387  memunit_advance(dynamic_at_c(first,i), plane_size*i);
388  }
389  _view=view_t(dimensions, typename view_t::locator(first, row_size));
390  }
391 
392  void create_view( const point_t& dims
393  , mpl::true_ // is planar
394  )
395  {
396  std::size_t row_size=get_row_size_in_memunits(dims.x);
397  std::size_t plane_size=row_size*dims.y;
398 
399  unsigned char* tmp = ( _align_in_bytes > 0 ) ? (unsigned char*) align( (std::size_t) _memory
400  ,_align_in_bytes
401  )
402  : _memory;
403  typename view_t::x_iterator first;
404 
405  for (int i = 0; i < num_channels< view_t >::value; ++i )
406  {
407  dynamic_at_c( first, i ) = (typename channel_type<view_t>::type*) tmp;
408 
409  memunit_advance( dynamic_at_c(first,i)
410  , plane_size*i
411  );
412  }
413 
414  _view=view_t( dims
415  , typename view_t::locator( first
416  , row_size
417  )
418  );
419  }
420 
421  void create_view( const point_t& dims
422  , mpl::false_ // is planar
423  )
424  {
425  unsigned char* tmp = ( _align_in_bytes > 0 ) ? ( unsigned char* ) align( (std::size_t) _memory
426  , _align_in_bytes
427  )
428  : _memory;
429 
430  _view = view_t( dims
431  , typename view_t::locator( typename view_t::x_iterator( tmp )
432  , get_row_size_in_memunits( dims.x )
433  )
434  );
435  }
436 };
437 
438 template <typename Pixel, bool IsPlanar, typename Alloc>
440  im1.swap(im2);
441 }
442 
443 template <typename Pixel1, bool IsPlanar1, typename Alloc1, typename Pixel2, bool IsPlanar2, typename Alloc2>
444 bool operator==(const image<Pixel1,IsPlanar1,Alloc1>& im1,const image<Pixel2,IsPlanar2,Alloc2>& im2) {
445  if ((void*)(&im1)==(void*)(&im2)) return true;
446  if (const_view(im1).dimensions()!=const_view(im2).dimensions()) return false;
447  return equal_pixels(const_view(im1),const_view(im2));
448 }
449 template <typename Pixel1, bool IsPlanar1, typename Alloc1, typename Pixel2, bool IsPlanar2, typename Alloc2>
450 bool operator!=(const image<Pixel1,IsPlanar1,Alloc1>& im1,const image<Pixel2,IsPlanar2,Alloc2>& im2) {return !(im1==im2);}
451 
455 
457 
459 template <typename Pixel, bool IsPlanar, typename Alloc> inline
460 const typename image<Pixel,IsPlanar,Alloc>::view_t& view(image<Pixel,IsPlanar,Alloc>& img) { return img._view; }
461 
463 template <typename Pixel, bool IsPlanar, typename Alloc> inline
464 const typename image<Pixel,IsPlanar,Alloc>::const_view_t const_view(const image<Pixel,IsPlanar,Alloc>& img) {
465  return static_cast<const typename image<Pixel,IsPlanar,Alloc>::const_view_t>(img._view);
466 }
468 
470 // PixelBasedConcept
472 
473 template <typename Pixel, bool IsPlanar, typename Alloc>
474 struct channel_type<image<Pixel,IsPlanar,Alloc> > : public channel_type<Pixel> {};
475 
476 template <typename Pixel, bool IsPlanar, typename Alloc>
477 struct color_space_type<image<Pixel,IsPlanar,Alloc> > : public color_space_type<Pixel> {};
478 
479 template <typename Pixel, bool IsPlanar, typename Alloc>
480 struct channel_mapping_type<image<Pixel,IsPlanar,Alloc> > : public channel_mapping_type<Pixel> {};
481 
482 template <typename Pixel, bool IsPlanar, typename Alloc>
483 struct is_planar<image<Pixel,IsPlanar,Alloc> > : public mpl::bool_<IsPlanar> {};
484 
485 }} // namespace boost::gil
486 
487 #endif
Definition: pixel_iterator.hpp:110
void uninitialized_fill_pixels(const View &img_view, const Value &val)
std::uninitialized_fill for image views. Does not support planar heterogeneous views. If an exception is thrown destructs any in-place copy-constructed pixels
Definition: algorithm.hpp:537
Definition: algorithm.hpp:30
void swap(const boost::gil::packed_channel_reference< BF, FB, NB, M > x, R &y)
swap for packed_channel_reference
Definition: channel.hpp:485
BOOST_FORCEINLINE bool equal_pixels(const View1 &v1, const View2 &v2)
std::equal for image views
Definition: algorithm.hpp:951
BOOST_FORCEINLINE void copy_pixels(const View1 &src, const View2 &dst)
std::copy for image views
Definition: algorithm.hpp:270
void default_construct_pixels(const View &img_view)
Invokes the in-place default constructor on every pixel of the (uninitialized) view. Does not support planar heterogeneous views. If an exception is thrown destructs any in-place default-constructed pixels.
Definition: algorithm.hpp:666
container interface over image view. Models ImageConcept, PixelBasedConcept
Definition: image.hpp:39
Definition: color_convert.hpp:30
const image< Pixel, IsPlanar, Alloc >::view_t & view(image< Pixel, IsPlanar, Alloc > &img)
Returns the non-constant-pixel view of an image.
Definition: image.hpp:460
void uninitialized_copy_pixels(const View1 &view1, const View2 &view2)
std::uninitialized_copy for image views. Does not support planar heterogeneous views. If an exception is thrown destructs any in-place copy-constructed objects
Definition: algorithm.hpp:719
const image< Pixel, IsPlanar, Alloc >::const_view_t const_view(const image< Pixel, IsPlanar, Alloc > &img)
Returns the constant-pixel view of an image.
Definition: image.hpp:464
Returns the number of channels of a pixel-based GIL construct.
Definition: locator.hpp:38
BOOST_FORCEINLINE void destruct_pixels(const View &img_view)
Invokes the in-place destructor on every pixel of the view.
Definition: algorithm.hpp:480
Returns the type of a view the pixel type, whether it operates on planar data and whether it has a st...
Definition: metafunctions.hpp:428