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