]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/boost/gil/image.hpp
import quincy beta 17.1.0
[ceph.git] / ceph / src / boost / boost / gil / image.hpp
CommitLineData
92f5a8d4
TL
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>
f67539c2 17#include <boost/core/exchange.hpp>
7c673cae
FG
18
19#include <cstddef>
20#include <memory>
92f5a8d4
TL
21#include <utility>
22#include <type_traits>
7c673cae
FG
23
24namespace boost { namespace gil {
25
7c673cae
FG
26////////////////////////////////////////////////////////////////////////////////////////
27/// \ingroup ImageModel PixelBasedModel
28/// \brief container interface over image view. Models ImageConcept, PixelBasedConcept
92f5a8d4 29///
7c673cae
FG
30/// A 2D container whose elements are pixels. It is templated over the pixel type, a boolean
31/// indicating whether it should be planar, and an optional allocator.
32///
92f5a8d4 33/// Note that its element type does not have to be a pixel. \p image can be instantiated with any Regular element,
7c673cae
FG
34/// in which case it models the weaker RandomAccess2DImageConcept and does not model PixelBasedConcept
35///
92f5a8d4
TL
36/// When recreating an image of the same or smaller size the memory will be reused if possible.
37///
7c673cae
FG
38////////////////////////////////////////////////////////////////////////////////////////
39
92f5a8d4 40template< typename Pixel, bool IsPlanar = false, typename Alloc=std::allocator<unsigned char> >
f67539c2
TL
41class image
42{
7c673cae 43public:
92f5a8d4
TL
44#if defined(BOOST_NO_CXX11_ALLOCATOR)
45 using allocator_type = typename Alloc::template rebind<unsigned char>::other;
46#else
47 using allocator_type = typename std::allocator_traits<Alloc>::template rebind_alloc<unsigned char>;
48#endif
49 using view_t = typename view_type_from_pixel<Pixel, IsPlanar>::type;
50 using const_view_t = typename view_t::const_t;
51 using point_t = typename view_t::point_t;
52 using coord_t = typename view_t::coord_t;
53 using value_type = typename view_t::value_type;
54 using x_coord_t = coord_t;
55 using y_coord_t = coord_t;
7c673cae
FG
56
57 const point_t& dimensions() const { return _view.dimensions(); }
58 x_coord_t width() const { return _view.width(); }
59 y_coord_t height() const { return _view.height(); }
60
61 explicit image(std::size_t alignment=0,
92f5a8d4
TL
62 const Alloc alloc_in = Alloc()) :
63 _memory(nullptr), _align_in_bytes(alignment), _alloc(alloc_in), _allocated_bytes( 0 ) {}
7c673cae
FG
64
65 // Create with dimensions and optional initial value and alignment
66 image(const point_t& dimensions,
67 std::size_t alignment=0,
92f5a8d4 68 const Alloc alloc_in = Alloc()) : _memory(nullptr), _align_in_bytes(alignment), _alloc(alloc_in)
f67539c2
TL
69 , _allocated_bytes( 0 )
70 {
7c673cae
FG
71 allocate_and_default_construct(dimensions);
72 }
92f5a8d4 73
7c673cae
FG
74 image(x_coord_t width, y_coord_t height,
75 std::size_t alignment=0,
92f5a8d4 76 const Alloc alloc_in = Alloc()) : _memory(nullptr), _align_in_bytes(alignment), _alloc(alloc_in)
f67539c2
TL
77 , _allocated_bytes( 0 )
78 {
7c673cae
FG
79 allocate_and_default_construct(point_t(width,height));
80 }
92f5a8d4
TL
81
82 image(const point_t& dimensions,
7c673cae 83 const Pixel& p_in,
f67539c2 84 std::size_t alignment = 0,
92f5a8d4 85 const Alloc alloc_in = Alloc()) : _memory(nullptr), _align_in_bytes(alignment), _alloc(alloc_in)
f67539c2
TL
86 , _allocated_bytes( 0 )
87 {
7c673cae
FG
88 allocate_and_fill(dimensions, p_in);
89 }
f67539c2 90
7c673cae
FG
91 image(x_coord_t width, y_coord_t height,
92 const Pixel& p_in,
92f5a8d4
TL
93 std::size_t alignment = 0,
94 const Alloc alloc_in = Alloc()) : _memory(nullptr), _align_in_bytes(alignment), _alloc(alloc_in)
f67539c2
TL
95 , _allocated_bytes ( 0 )
96 {
7c673cae
FG
97 allocate_and_fill(point_t(width,height),p_in);
98 }
99
92f5a8d4 100 image(const image& img) : _memory(nullptr), _align_in_bytes(img._align_in_bytes), _alloc(img._alloc)
f67539c2
TL
101 , _allocated_bytes( img._allocated_bytes )
102 {
7c673cae
FG
103 allocate_and_copy(img.dimensions(),img._view);
104 }
105
106 template <typename P2, bool IP2, typename Alloc2>
92f5a8d4 107 image(const image<P2,IP2,Alloc2>& img) : _memory(nullptr), _align_in_bytes(img._align_in_bytes), _alloc(img._alloc)
f67539c2
TL
108 , _allocated_bytes( img._allocated_bytes )
109 {
7c673cae
FG
110 allocate_and_copy(img.dimensions(),img._view);
111 }
92f5a8d4 112
f67539c2
TL
113 // TODO Optimization: use noexcept (requires _view to be nothrow copy constructible)
114 image(image&& img) :
115 _view(img._view),
116 _memory(img._memory),
117 _align_in_bytes(img._align_in_bytes),
118 _alloc(std::move(img._alloc)),
119 _allocated_bytes(img._allocated_bytes)
120 {
121 img._view = view_t();
122 img._memory = nullptr;
123 img._align_in_bytes = 0;
124 img._allocated_bytes = 0;
125 }
126
127 image& operator=(const image& img)
128 {
7c673cae
FG
129 if (dimensions() == img.dimensions())
130 copy_pixels(img._view,_view);
f67539c2
TL
131 else
132 {
7c673cae
FG
133 image tmp(img);
134 swap(tmp);
135 }
136 return *this;
137 }
138
139 template <typename Img>
f67539c2
TL
140 image& operator=(const Img& img)
141 {
7c673cae
FG
142 if (dimensions() == img.dimensions())
143 copy_pixels(img._view,_view);
f67539c2
TL
144 else
145 {
7c673cae
FG
146 image tmp(img);
147 swap(tmp);
148 }
149 return *this;
150 }
151
f67539c2
TL
152 private:
153 using propagate_allocators = std::true_type;
154 using no_propagate_allocators = std::false_type;
155
156 template <class Alloc2>
157 using choose_pocma = typename std::conditional<
158 // TODO: Use std::allocator_traits<Allocator>::is_always_equal if available
159 std::is_empty<Alloc2>::value,
160 std::true_type,
161 typename std::allocator_traits<Alloc2>::propagate_on_container_move_assignment::type
162 >::type;
163
164 static void exchange_memory(image& lhs, image& rhs)
165 {
166 lhs._memory = boost::exchange(rhs._memory, nullptr);
167 lhs._align_in_bytes = boost::exchange(rhs._align_in_bytes, 0);
168 lhs._allocated_bytes = boost::exchange(rhs._allocated_bytes, 0);
169 lhs._view = boost::exchange(rhs._view, image::view_t{});
170 };
171
172 void move_assign(image& img, propagate_allocators) noexcept {
173 // non-sticky allocator, can adopt the memory, fast
174 destruct_pixels(_view);
175 this->deallocate();
176 this->_alloc = img._alloc;
177 exchange_memory(*this, img);
178 }
179
180 void move_assign(image& img, no_propagate_allocators) {
181 if (_alloc == img._alloc) {
182 // allocator stuck to the rhs, but it's equivalent of ours, we can still adopt the memory
183 destruct_pixels(_view);
184 this->deallocate();
185 exchange_memory(*this, img);
186 } else {
187 // cannot propagate the allocator and cannot adopt the memory
188 if (img._memory)
189 {
190 allocate_and_copy(img.dimensions(), img._view);
191 destruct_pixels(img._view);
192 img.deallocate();
193 img._view = image::view_t{};
194 }
195 else
196 {
197 destruct_pixels(this->_view);
198 this->deallocate();
199 this->_view = view_t{};
200 }
201 }
202 }
203
204 public:
205 // TODO: Use noexcept(noexcept(move_assign(img, choose_pocma<allocator_type>{})))
206 // But https://gcc.gnu.org/bugzilla/show_bug.cgi?id=52869 prevents it (fixed in GCC > 9)
207 image& operator=(image&& img) {
208 if (this != std::addressof(img))
209 // Use rebinded alloc to choose pocma
210 move_assign(img, choose_pocma<allocator_type>{});
211
212 return *this;
213 }
214
215 ~image()
216 {
7c673cae 217 destruct_pixels(_view);
92f5a8d4 218 deallocate();
7c673cae
FG
219 }
220
221 Alloc& allocator() { return _alloc; }
222 Alloc const& allocator() const { return _alloc; }
223
f67539c2
TL
224 void swap(image& img) // required by MutableContainerConcept
225 {
7c673cae 226 using std::swap;
92f5a8d4
TL
227 swap(_align_in_bytes, img._align_in_bytes);
228 swap(_memory, img._memory);
229 swap(_view, img._view);
230 swap(_alloc, img._alloc);
231 swap(_allocated_bytes, img._allocated_bytes );
232 }
233
234 /////////////////////
235 // recreate
236 /////////////////////
237
238 // without Allocator
239 void recreate(const point_t& dims, std::size_t alignment = 0)
240 {
241 if (dims == _view.dimensions() && _align_in_bytes == alignment)
242 return;
243
244 _align_in_bytes = alignment;
245
246 if (_allocated_bytes >= total_allocated_size_in_bytes(dims))
247 {
248 destruct_pixels(_view);
249 create_view(dims, std::integral_constant<bool, IsPlanar>());
250 default_construct_pixels(_view);
251 }
252 else
253 {
254 image tmp(dims, alignment);
255 swap(tmp);
256 }
257 }
258
259 void recreate(x_coord_t width, y_coord_t height, std::size_t alignment = 0)
260 {
261 recreate(point_t(width, height), alignment);
262 }
263
264 void recreate(const point_t& dims, const Pixel& p_in, std::size_t alignment = 0)
265 {
266 if (dims == _view.dimensions() && _align_in_bytes == alignment)
267 return;
268
269 _align_in_bytes = alignment;
270
271 if (_allocated_bytes >= total_allocated_size_in_bytes(dims))
272 {
273 destruct_pixels(_view);
274 create_view(dims, typename std::integral_constant<bool, IsPlanar>());
275 uninitialized_fill_pixels(_view, p_in);
276 }
277 else
278 {
279 image tmp(dims, p_in, alignment);
280 swap(tmp);
281 }
282 }
283
284 void recreate( x_coord_t width, y_coord_t height, const Pixel& p_in, std::size_t alignment = 0 )
285 {
286 recreate( point_t( width, height ), p_in, alignment );
287 }
288
289 // with Allocator
290 void recreate(const point_t& dims, std::size_t alignment, const Alloc alloc_in)
291 {
292 if (dims == _view.dimensions() && _align_in_bytes == alignment && alloc_in == _alloc)
293 return;
294
295 _align_in_bytes = alignment;
296
297 if (_allocated_bytes >= total_allocated_size_in_bytes(dims))
298 {
299 destruct_pixels(_view);
300 create_view(dims, std::integral_constant<bool, IsPlanar>());
301 default_construct_pixels(_view);
302 }
303 else
304 {
7c673cae
FG
305 image tmp(dims, alignment, alloc_in);
306 swap(tmp);
307 }
308 }
92f5a8d4
TL
309
310 void recreate(x_coord_t width, y_coord_t height, std::size_t alignment, const Alloc alloc_in)
311 {
312 recreate(point_t(width, height), alignment, alloc_in);
7c673cae 313 }
92f5a8d4
TL
314
315 void recreate(const point_t& dims, const Pixel& p_in, std::size_t alignment, const Alloc alloc_in)
316 {
317 if (dims == _view.dimensions() && _align_in_bytes == alignment && alloc_in == _alloc)
318 return;
319
320 _align_in_bytes = alignment;
321
322 if (_allocated_bytes >= total_allocated_size_in_bytes(dims))
323 {
324 destruct_pixels(_view);
325 create_view(dims, std::integral_constant<bool, IsPlanar>());
326 uninitialized_fill_pixels(_view, p_in);
327 }
328 else
329 {
7c673cae
FG
330 image tmp(dims, p_in, alignment, alloc_in);
331 swap(tmp);
332 }
333 }
92f5a8d4
TL
334
335 void recreate(x_coord_t width, y_coord_t height, const Pixel& p_in, std::size_t alignment, const Alloc alloc_in )
336 {
337 recreate(point_t(width, height), p_in, alignment, alloc_in);
7c673cae
FG
338 }
339
340 view_t _view; // contains pointer to the pixels, the image size and ways to navigate pixels
20effc67
TL
341
342 // for construction from other type
343 template <typename P2, bool IP2, typename Alloc2> friend class image;
7c673cae
FG
344private:
345 unsigned char* _memory;
346 std::size_t _align_in_bytes;
347 allocator_type _alloc;
348
92f5a8d4
TL
349 std::size_t _allocated_bytes;
350
351 void allocate_and_default_construct(point_t const& dimensions)
352 {
353 try
354 {
355 allocate_(dimensions, std::integral_constant<bool, IsPlanar>());
7c673cae 356 default_construct_pixels(_view);
92f5a8d4
TL
357 }
358 catch (...) { deallocate(); throw; }
7c673cae
FG
359 }
360
92f5a8d4
TL
361 void allocate_and_fill(const point_t& dimensions, Pixel const& p_in)
362 {
363 try
364 {
365 allocate_(dimensions, std::integral_constant<bool, IsPlanar>());
7c673cae 366 uninitialized_fill_pixels(_view, p_in);
92f5a8d4
TL
367 }
368 catch(...) { deallocate(); throw; }
7c673cae
FG
369 }
370
371 template <typename View>
92f5a8d4
TL
372 void allocate_and_copy(const point_t& dimensions, View const& v)
373 {
374 try
375 {
376 allocate_(dimensions, std::integral_constant<bool, IsPlanar>());
377 uninitialized_copy_pixels(v, _view);
378 }
379 catch(...) { deallocate(); throw; }
7c673cae
FG
380 }
381
92f5a8d4
TL
382 void deallocate()
383 {
384 if (_memory && _allocated_bytes > 0)
385 _alloc.deallocate(_memory, _allocated_bytes);
7c673cae
FG
386 }
387
92f5a8d4
TL
388 std::size_t is_planar_impl(
389 std::size_t const size_in_units,
390 std::size_t const channels_in_image,
391 std::true_type) const
392 {
393 return size_in_units * channels_in_image;
394 }
7c673cae 395
92f5a8d4
TL
396 std::size_t is_planar_impl(
397 std::size_t const size_in_units,
398 std::size_t const,
399 std::false_type) const
400 {
401 return size_in_units;
402 }
7c673cae 403
92f5a8d4
TL
404 std::size_t total_allocated_size_in_bytes(point_t const& dimensions) const
405 {
406 using x_iterator = typename view_t::x_iterator;
7c673cae 407
92f5a8d4
TL
408 // when value_type is a non-pixel, like int or float, num_channels< ... > doesn't work.
409 constexpr std::size_t _channels_in_image =
410 std::conditional
411 <
412 is_pixel<value_type>::value,
413 num_channels<view_t>,
414 std::integral_constant<std::size_t, 1>
415 >::type::value;
416
417 std::size_t size_in_units = is_planar_impl(
418 get_row_size_in_memunits(dimensions.x) * dimensions.y,
419 _channels_in_image,
420 std::integral_constant<bool, IsPlanar>());
7c673cae
FG
421
422 // return the size rounded up to the nearest byte
92f5a8d4
TL
423 return ( size_in_units + byte_to_memunit< x_iterator >::value - 1 )
424 / byte_to_memunit<x_iterator>::value
7c673cae
FG
425 + ( _align_in_bytes > 0 ? _align_in_bytes - 1 : 0 ); // add extra padding in case we need to align the first image pixel
426 }
427
428 std::size_t get_row_size_in_memunits(x_coord_t width) const { // number of units per row
429 std::size_t size_in_memunits = width*memunit_step(typename view_t::x_iterator());
430 if (_align_in_bytes>0) {
431 std::size_t alignment_in_memunits=_align_in_bytes*byte_to_memunit<typename view_t::x_iterator>::value;
432 return align(size_in_memunits, alignment_in_memunits);
433 }
434 return size_in_memunits;
435 }
92f5a8d4
TL
436
437 void allocate_(point_t const& dimensions, std::false_type)
438 {
439 // if it throws and _memory!=0 the client must deallocate _memory
440 _allocated_bytes = total_allocated_size_in_bytes(dimensions);
441 _memory=_alloc.allocate( _allocated_bytes );
442
7c673cae 443 unsigned char* tmp=(_align_in_bytes>0) ? (unsigned char*)align((std::size_t)_memory,_align_in_bytes) : _memory;
92f5a8d4
TL
444 _view=view_t(dimensions,typename view_t::locator(typename view_t::x_iterator(tmp), get_row_size_in_memunits(dimensions.x)));
445
446 BOOST_ASSERT(_view.width() == dimensions.x);
447 BOOST_ASSERT(_view.height() == dimensions.y);
7c673cae
FG
448 }
449
92f5a8d4
TL
450 void allocate_(point_t const& dimensions, std::true_type)
451 {
452 // if it throws and _memory!=0 the client must deallocate _memory
7c673cae
FG
453 std::size_t row_size=get_row_size_in_memunits(dimensions.x);
454 std::size_t plane_size=row_size*dimensions.y;
92f5a8d4
TL
455
456 _allocated_bytes = total_allocated_size_in_bytes( dimensions );
457
458 _memory = _alloc.allocate( _allocated_bytes );
459
7c673cae 460 unsigned char* tmp=(_align_in_bytes>0) ? (unsigned char*)align((std::size_t)_memory,_align_in_bytes) : _memory;
92f5a8d4 461 typename view_t::x_iterator first;
f67539c2
TL
462 for (std::size_t i = 0; i < num_channels<view_t>::value; ++i)
463 {
464 dynamic_at_c(first, i) = (typename channel_type<view_t>::type*)tmp;
465 memunit_advance(dynamic_at_c(first, i), static_cast<std::ptrdiff_t>(plane_size * i));
7c673cae
FG
466 }
467 _view=view_t(dimensions, typename view_t::locator(first, row_size));
92f5a8d4
TL
468
469 BOOST_ASSERT(_view.width() == dimensions.x);
470 BOOST_ASSERT(_view.height() == dimensions.y);
471 }
472
473 void create_view(point_t const& dims, std::true_type) // is planar
474 {
475 std::size_t row_size=get_row_size_in_memunits(dims.x);
476 std::size_t plane_size=row_size*dims.y;
477
478 unsigned char* tmp = ( _align_in_bytes > 0 ) ? (unsigned char*) align( (std::size_t) _memory
479 ,_align_in_bytes
480 )
481 : _memory;
482 typename view_t::x_iterator first;
483
f67539c2 484 for (std::size_t i = 0; i < num_channels<view_t>::value; ++i)
92f5a8d4 485 {
f67539c2
TL
486 dynamic_at_c(first, i) = (typename channel_type<view_t>::type*)tmp;
487 memunit_advance(dynamic_at_c(first, i), static_cast<std::ptrdiff_t>(plane_size * i));
92f5a8d4
TL
488 }
489
490 _view = view_t(dims, typename view_t::locator(first, row_size));
491
492 BOOST_ASSERT(_view.width() == dims.x);
493 BOOST_ASSERT(_view.height() == dims.y);
494 }
495
496 void create_view(point_t const& dims, std::false_type) // is planar
497 {
498 unsigned char* tmp = ( _align_in_bytes > 0 ) ? ( unsigned char* ) align( (std::size_t) _memory
499 , _align_in_bytes
500 )
501 : _memory;
502
503 _view = view_t( dims
504 , typename view_t::locator( typename view_t::x_iterator( tmp )
505 , get_row_size_in_memunits( dims.x )
506 )
507 );
508
509 BOOST_ASSERT(_view.width() == dims.x);
510 BOOST_ASSERT(_view.height() == dims.y);
7c673cae
FG
511 }
512};
513
514template <typename Pixel, bool IsPlanar, typename Alloc>
f67539c2
TL
515void swap(image<Pixel, IsPlanar, Alloc>& im1,image<Pixel, IsPlanar, Alloc>& im2)
516{
92f5a8d4 517 im1.swap(im2);
7c673cae
FG
518}
519
520template <typename Pixel1, bool IsPlanar1, typename Alloc1, typename Pixel2, bool IsPlanar2, typename Alloc2>
f67539c2
TL
521bool operator==(const image<Pixel1,IsPlanar1,Alloc1>& im1,const image<Pixel2,IsPlanar2,Alloc2>& im2)
522{
7c673cae
FG
523 if ((void*)(&im1)==(void*)(&im2)) return true;
524 if (const_view(im1).dimensions()!=const_view(im2).dimensions()) return false;
525 return equal_pixels(const_view(im1),const_view(im2));
526}
527template <typename Pixel1, bool IsPlanar1, typename Alloc1, typename Pixel2, bool IsPlanar2, typename Alloc2>
528bool operator!=(const image<Pixel1,IsPlanar1,Alloc1>& im1,const image<Pixel2,IsPlanar2,Alloc2>& im2) {return !(im1==im2);}
529
530///@{
531/// \name view, const_view
532/// \brief Get an image view from an image
533
534/// \ingroup ImageModel
535
536/// \brief Returns the non-constant-pixel view of an image
92f5a8d4 537template <typename Pixel, bool IsPlanar, typename Alloc> inline
7c673cae
FG
538const typename image<Pixel,IsPlanar,Alloc>::view_t& view(image<Pixel,IsPlanar,Alloc>& img) { return img._view; }
539
540/// \brief Returns the constant-pixel view of an image
92f5a8d4 541template <typename Pixel, bool IsPlanar, typename Alloc> inline
f67539c2
TL
542const typename image<Pixel,IsPlanar,Alloc>::const_view_t const_view(const image<Pixel,IsPlanar,Alloc>& img)
543{
92f5a8d4 544 return static_cast<const typename image<Pixel,IsPlanar,Alloc>::const_view_t>(img._view);
7c673cae
FG
545}
546///@}
547
548/////////////////////////////
549// PixelBasedConcept
550/////////////////////////////
551
552template <typename Pixel, bool IsPlanar, typename Alloc>
92f5a8d4 553struct channel_type<image<Pixel, IsPlanar, Alloc>> : channel_type<Pixel> {};
7c673cae
FG
554
555template <typename Pixel, bool IsPlanar, typename Alloc>
92f5a8d4 556struct color_space_type<image<Pixel, IsPlanar, Alloc>> : color_space_type<Pixel> {};
7c673cae
FG
557
558template <typename Pixel, bool IsPlanar, typename Alloc>
92f5a8d4 559struct channel_mapping_type<image<Pixel, IsPlanar, Alloc>> : channel_mapping_type<Pixel> {};
7c673cae
FG
560
561template <typename Pixel, bool IsPlanar, typename Alloc>
92f5a8d4 562struct is_planar<image<Pixel, IsPlanar, Alloc>> : std::integral_constant<bool, IsPlanar> {};
7c673cae 563
92f5a8d4 564}} // namespace boost::gil
7c673cae
FG
565
566#endif