Boost GIL


color_base.hpp
1//
2// Copyright 2005-2007 Adobe Systems Incorporated
3// Copyright 2019 Mateusz Loskot <mateusz at loskot dot net>
4//
5// Distributed under the Boost Software License, Version 1.0
6// See accompanying file LICENSE_1_0.txt or copy at
7// http://www.boost.org/LICENSE_1_0.txt
8//
9#ifndef BOOST_GIL_COLOR_BASE_HPP
10#define BOOST_GIL_COLOR_BASE_HPP
11
12#include <boost/gil/utilities.hpp>
13#include <boost/gil/concepts.hpp>
14#include <boost/gil/detail/mp11.hpp>
15
16#include <boost/assert.hpp>
17#include <boost/config.hpp>
18
19#include <type_traits>
20
21namespace boost { namespace gil {
22
23// Forward-declare
24template <typename P> P* memunit_advanced(const P* p, std::ptrdiff_t diff);
25
26// Forward-declare semantic_at_c
27template <int K, typename ColorBase>
28auto semantic_at_c(ColorBase& p)
29 -> typename std::enable_if
30 <
31 !std::is_const<ColorBase>::value,
32 typename kth_semantic_element_reference_type<ColorBase, K>::type
33 >::type;
34
35
36template <int K, typename ColorBase>
37auto semantic_at_c(const ColorBase& p) -> typename kth_semantic_element_const_reference_type<ColorBase,K>::type;
38
39// Forward declare element_reference_type
40template <typename ColorBase> struct element_reference_type;
41template <typename ColorBase> struct element_const_reference_type;
42template <typename ColorBase, int K> struct kth_element_type;
43template <typename ColorBase, int K> struct kth_element_type<const ColorBase,K> : public kth_element_type<ColorBase,K> {};
44template <typename ColorBase, int K> struct kth_element_reference_type;
45template <typename ColorBase, int K> struct kth_element_reference_type<const ColorBase,K> : public kth_element_reference_type<ColorBase,K> {};
46template <typename ColorBase, int K> struct kth_element_const_reference_type;
47template <typename ColorBase, int K> struct kth_element_const_reference_type<const ColorBase,K> : public kth_element_const_reference_type<ColorBase,K> {};
48
49namespace detail {
50
51template <typename DstLayout, typename SrcLayout, int K>
52struct mapping_transform : mp11::mp_at
53 <
54 typename SrcLayout::channel_mapping_t,
55 typename detail::type_to_index
56 <
57 typename DstLayout::channel_mapping_t,
58 std::integral_constant<int, K>
59 >
60 >::type
61{};
62
68
69#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
70#pragma warning(push)
71#pragma warning(disable:4512) //assignment operator could not be generated
72#endif
73
77template <typename Element, typename Layout>
78struct homogeneous_color_base<Element, Layout, 1>
79{
80 using layout_t = Layout;
81
82 template
83 <
84 typename U = Element,
85 typename = typename std::enable_if<!std::is_reference<U>::value>::type
86 >
87 homogeneous_color_base() : v0_{} {}
88
89 explicit homogeneous_color_base(Element v) : v0_(v) {}
90
91 template <typename E2, typename L2>
92 homogeneous_color_base(homogeneous_color_base<E2, L2, 1> const& c)
93 : v0_(gil::at_c<0>(c))
94 {}
95
96 auto at(std::integral_constant<int, 0>)
98 { return v0_; }
99
100 auto at(std::integral_constant<int, 0>) const
102 { return v0_; }
103
104 // grayscale pixel values are convertible to channel type
105 // FIXME: explicit?
106 operator Element() const { return v0_; }
107
108private:
109 Element v0_;
110};
111
115template <typename Element, typename Layout>
116struct homogeneous_color_base<Element, Layout, 2>
117{
118 using layout_t = Layout;
119
120 template
121 <
122 typename U = Element,
123 typename = typename std::enable_if<!std::is_reference<U>::value>::type
124 >
125 homogeneous_color_base() : v0_{}, v1_{} {}
126
127 explicit homogeneous_color_base(Element v) : v0_(v), v1_(v) {}
128
129 homogeneous_color_base(Element v0, Element v1) : v0_(v0), v1_(v1) {}
130
131 template <typename E2, typename L2>
132 homogeneous_color_base(homogeneous_color_base<E2, L2, 2> const& c)
133 : v0_(gil::at_c<mapping_transform<Layout, L2, 0>::value>(c))
134 , v1_(gil::at_c<mapping_transform<Layout, L2, 1>::value>(c))
135 {}
136
137 // Support for l-value reference proxy copy construction
138 template <typename E2, typename L2>
139 homogeneous_color_base(homogeneous_color_base<E2, L2, 2>& c)
140 : v0_(gil::at_c<mapping_transform<Layout, L2, 0>::value>(c))
141 , v1_(gil::at_c<mapping_transform<Layout, L2, 1>::value>(c))
142 {}
143
144 // Support for planar_pixel_iterator construction and dereferencing
145 template <typename P>
146 homogeneous_color_base(P* p, bool)
147 : v0_(&semantic_at_c<0>(*p))
148 , v1_(&semantic_at_c<1>(*p))
149 {}
150
151 // Support for planar_pixel_reference offset constructor
152 template <typename Ptr>
153 homogeneous_color_base(Ptr const& ptr, std::ptrdiff_t diff)
154 : v0_(*memunit_advanced(semantic_at_c<0>(ptr), diff))
155 , v1_(*memunit_advanced(semantic_at_c<1>(ptr), diff))
156 {}
157
158 template <typename Ref>
159 Ref deref() const
160 {
161 return Ref(*semantic_at_c<0>(*this), *semantic_at_c<1>(*this));
162 }
163
164 auto at(std::integral_constant<int, 0>)
166 { return v0_; }
167
168 auto at(std::integral_constant<int, 0>) const
170 { return v0_; }
171
172 auto at(std::integral_constant<int, 1>)
174 { return v1_; }
175
176 auto at(std::integral_constant<int, 1>) const
178 { return v1_; }
179
180 // Support for planar_pixel_reference operator[]
181 auto at_c_dynamic(std::size_t i) const -> Element
182 {
183 if (i == 0)
184 return v0_;
185 else
186 return v1_;
187 }
188
189private:
190 Element v0_;
191 Element v1_;
192};
193
197template <typename Element, typename Layout>
198struct homogeneous_color_base<Element, Layout, 3>
199{
200 using layout_t = Layout;
201
202 template
203 <
204 typename U = Element,
205 typename = typename std::enable_if<!std::is_reference<U>::value>::type
206 >
207 homogeneous_color_base() : v0_{}, v1_{}, v2_{} {}
208
209 explicit homogeneous_color_base(Element v) : v0_(v), v1_(v), v2_(v) {}
210
211 homogeneous_color_base(Element v0, Element v1, Element v2)
212 : v0_(v0), v1_(v1), v2_(v2)
213 {}
214
215 template <typename E2, typename L2>
216 homogeneous_color_base(homogeneous_color_base<E2, L2, 3> const& c)
217 : v0_(gil::at_c<mapping_transform<Layout, L2, 0>::value>(c))
218 , v1_(gil::at_c<mapping_transform<Layout, L2, 1>::value>(c))
219 , v2_(gil::at_c<mapping_transform<Layout, L2, 2>::value>(c))
220 {}
221
222 // Support for l-value reference proxy copy construction
223 template <typename E2, typename L2>
224 homogeneous_color_base(homogeneous_color_base<E2, L2, 3>& c)
225 : v0_(gil::at_c<mapping_transform<Layout, L2, 0>::value>(c))
226 , v1_(gil::at_c<mapping_transform<Layout, L2, 1>::value>(c))
227 , v2_(gil::at_c<mapping_transform<Layout, L2, 2>::value>(c))
228 {}
229
230 // Support for planar_pixel_iterator construction and dereferencing
231 template <typename P>
232 homogeneous_color_base(P* p, bool)
233 : v0_(&semantic_at_c<0>(*p))
234 , v1_(&semantic_at_c<1>(*p))
235 , v2_(&semantic_at_c<2>(*p))
236 {}
237
238 // Support for planar_pixel_reference offset constructor
239 template <typename Ptr>
240 homogeneous_color_base(Ptr const& ptr, std::ptrdiff_t diff)
241 : v0_(*memunit_advanced(semantic_at_c<0>(ptr), diff))
242 , v1_(*memunit_advanced(semantic_at_c<1>(ptr), diff))
243 , v2_(*memunit_advanced(semantic_at_c<2>(ptr), diff))
244 {}
245
246 template <typename Ref>
247 Ref deref() const
248 {
249 return Ref(
250 *semantic_at_c<0>(*this),
251 *semantic_at_c<1>(*this),
252 *semantic_at_c<2>(*this));
253 }
254
255 auto at(std::integral_constant<int, 0>)
257 { return v0_; }
258
259 auto at(std::integral_constant<int, 0>) const
261 { return v0_; }
262
263 auto at(std::integral_constant<int, 1>)
265 { return v1_; }
266
267 auto at(std::integral_constant<int, 1>) const
269 { return v1_; }
270
271 auto at(std::integral_constant<int, 2>)
273 { return v2_; }
274
275 auto at(std::integral_constant<int, 2>) const
277 { return v2_; }
278
279 // Support for planar_pixel_reference operator[]
280 auto at_c_dynamic(std::size_t i) const -> Element
281 {
282 switch (i)
283 {
284 case 0: return v0_;
285 case 1: return v1_;
286 }
287 return v2_;
288 }
289
290private:
291 Element v0_;
292 Element v1_;
293 Element v2_;
294};
295
299template <typename Element, typename Layout>
300struct homogeneous_color_base<Element, Layout, 4>
301{
302 using layout_t = Layout;
303
304 template
305 <
306 typename U = Element,
307 typename = typename std::enable_if<!std::is_reference<U>::value>::type
308 >
309 homogeneous_color_base() : v0_{}, v1_{}, v2_{}, v3_{} {}
310
311 explicit homogeneous_color_base(Element v) : v0_(v), v1_(v), v2_(v), v3_(v) {}
312
313 homogeneous_color_base(Element v0, Element v1, Element v2, Element v3)
314 : v0_(v0), v1_(v1), v2_(v2), v3_(v3)
315 {}
316
317 template <typename E2, typename L2>
318 homogeneous_color_base(homogeneous_color_base<E2, L2, 4> const& c)
319 : v0_(gil::at_c<mapping_transform<Layout, L2, 0>::value>(c))
320 , v1_(gil::at_c<mapping_transform<Layout, L2, 1>::value>(c))
321 , v2_(gil::at_c<mapping_transform<Layout, L2, 2>::value>(c))
322 , v3_(gil::at_c<mapping_transform<Layout, L2, 3>::value>(c))
323 {}
324
325 // Support for l-value reference proxy copy construction
326 template <typename E2, typename L2>
327 homogeneous_color_base(homogeneous_color_base<E2, L2, 4>& c)
328 : v0_(gil::at_c<mapping_transform<Layout, L2, 0>::value>(c))
329 , v1_(gil::at_c<mapping_transform<Layout, L2, 1>::value>(c))
330 , v2_(gil::at_c<mapping_transform<Layout, L2, 2>::value>(c))
331 , v3_(gil::at_c<mapping_transform<Layout, L2, 3>::value>(c))
332 {}
333
334 // Support for planar_pixel_iterator construction and dereferencing
335 template <typename P>
336 homogeneous_color_base(P * p, bool)
337 : v0_(&semantic_at_c<0>(*p))
338 , v1_(&semantic_at_c<1>(*p))
339 , v2_(&semantic_at_c<2>(*p))
340 , v3_(&semantic_at_c<3>(*p))
341 {}
342
343 // Support for planar_pixel_reference offset constructor
344 template <typename Ptr>
345 homogeneous_color_base(Ptr const& ptr, std::ptrdiff_t diff)
346 : v0_(*memunit_advanced(semantic_at_c<0>(ptr), diff))
347 , v1_(*memunit_advanced(semantic_at_c<1>(ptr), diff))
348 , v2_(*memunit_advanced(semantic_at_c<2>(ptr), diff))
349 , v3_(*memunit_advanced(semantic_at_c<3>(ptr), diff))
350 {}
351
352 template <typename Ref>
353 Ref deref() const
354 {
355 return Ref(
356 *semantic_at_c<0>(*this),
357 *semantic_at_c<1>(*this),
358 *semantic_at_c<2>(*this),
359 *semantic_at_c<3>(*this));
360 }
361
362 auto at(std::integral_constant<int, 0>)
364 { return v0_; }
365
366 auto at(std::integral_constant<int, 0>) const
368 { return v0_; }
369
370 auto at(std::integral_constant<int, 1>)
372 { return v1_; }
373
374 auto at(std::integral_constant<int, 1>) const
376 { return v1_; }
377
378 auto at(std::integral_constant<int, 2>)
380 { return v2_; }
381
382 auto at(std::integral_constant<int, 2>) const
384 { return v2_; }
385
386 auto at(std::integral_constant<int, 3>)
388 { return v3_; }
389
390 auto at(std::integral_constant<int, 3>) const
392 { return v3_; }
393
394 // Support for planar_pixel_reference operator[]
395 auto at_c_dynamic(std::size_t i) const -> Element
396 {
397 switch (i)
398 {
399 case 0: return v0_;
400 case 1: return v1_;
401 case 2: return v2_;
402 }
403 return v3_;
404 }
405
406private:
407 Element v0_;
408 Element v1_;
409 Element v2_;
410 Element v3_;
411};
412
416template <typename Element, typename Layout>
417struct homogeneous_color_base<Element, Layout, 5>
418{
419 using layout_t = Layout;
420
421 template
422 <
423 typename U = Element,
424 typename = typename std::enable_if<!std::is_reference<U>::value>::type
425 >
426 homogeneous_color_base()
427 : v0_{}, v1_{}, v2_{}, v3_{}, v4_{}
428 {}
429
430 explicit homogeneous_color_base(Element v)
431 : v0_(v), v1_(v), v2_(v), v3_(v), v4_(v)
432 {}
433
434 homogeneous_color_base(Element v0, Element v1, Element v2, Element v3, Element v4)
435 : v0_(v0), v1_(v1), v2_(v2), v3_(v3), v4_(v4)
436 {}
437
438 template <typename E2, typename L2>
439 homogeneous_color_base(homogeneous_color_base<E2, L2, 5> const& c)
440 : v0_(gil::at_c<mapping_transform<Layout, L2, 0>::value>(c))
441 , v1_(gil::at_c<mapping_transform<Layout, L2, 1>::value>(c))
442 , v2_(gil::at_c<mapping_transform<Layout, L2, 2>::value>(c))
443 , v3_(gil::at_c<mapping_transform<Layout, L2, 3>::value>(c))
444 , v4_(gil::at_c<mapping_transform<Layout, L2, 4>::value>(c))
445 {}
446
447 // Support for l-value reference proxy copy construction
448 template <typename E2, typename L2>
449 homogeneous_color_base(homogeneous_color_base<E2, L2, 5>& c)
450 : v0_(gil::at_c<mapping_transform<Layout, L2, 0>::value>(c))
451 , v1_(gil::at_c<mapping_transform<Layout, L2, 1>::value>(c))
452 , v2_(gil::at_c<mapping_transform<Layout, L2, 2>::value>(c))
453 , v3_(gil::at_c<mapping_transform<Layout, L2, 3>::value>(c))
454 , v4_(gil::at_c<mapping_transform<Layout, L2, 4>::value>(c))
455 {}
456
457 // Support for planar_pixel_iterator construction and dereferencing
458 template <typename P>
459 homogeneous_color_base(P* p, bool)
460 : v0_(&semantic_at_c<0>(*p))
461 , v1_(&semantic_at_c<1>(*p))
462 , v2_(&semantic_at_c<2>(*p))
463 , v3_(&semantic_at_c<3>(*p))
464 , v4_(&semantic_at_c<4>(*p))
465 {}
466
467 // Support for planar_pixel_reference offset constructor
468 template <typename Ptr>
469 homogeneous_color_base(Ptr const& ptr, std::ptrdiff_t diff)
470 : v0_(*memunit_advanced(semantic_at_c<0>(ptr), diff))
471 , v1_(*memunit_advanced(semantic_at_c<1>(ptr), diff))
472 , v2_(*memunit_advanced(semantic_at_c<2>(ptr), diff))
473 , v3_(*memunit_advanced(semantic_at_c<3>(ptr), diff))
474 , v4_(*memunit_advanced(semantic_at_c<4>(ptr), diff))
475 {}
476
477
478 auto at(std::integral_constant<int, 0>)
480 { return v0_; }
481
482 auto at(std::integral_constant<int, 0>) const
484 { return v0_; }
485
486 auto at(std::integral_constant<int, 1>)
488 { return v1_; }
489
490 auto at(std::integral_constant<int, 1>) const
492 { return v1_; }
493
494 auto at(std::integral_constant<int, 2>)
496 { return v2_; }
497
498 auto at(std::integral_constant<int, 2>) const
500 { return v2_; }
501
502 auto at(std::integral_constant<int, 3>)
504 { return v3_; }
505
506 auto at(std::integral_constant<int, 3>) const
508 { return v3_; }
509
510 auto at(std::integral_constant<int, 4>)
512 { return v4_; }
513
514 auto at(std::integral_constant<int, 4>) const
516 { return v4_; }
517
518 template <typename Ref>
519 Ref deref() const
520 {
521 return Ref(
522 *semantic_at_c<0>(*this),
523 *semantic_at_c<1>(*this),
524 *semantic_at_c<2>(*this),
525 *semantic_at_c<3>(*this),
526 *semantic_at_c<4>(*this));
527 }
528
529 // Support for planar_pixel_reference operator[]
530 auto at_c_dynamic(std::size_t i) const -> Element
531 {
532 switch (i)
533 {
534 case 0: return v0_;
535 case 1: return v1_;
536 case 2: return v2_;
537 case 3: return v3_;
538 }
539 return v4_;
540 }
541
542private:
543 Element v0_;
544 Element v1_;
545 Element v2_;
546 Element v3_;
547 Element v4_;
548};
549
550#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
551#pragma warning(pop)
552#endif
553
554// The following way of casting adjacent channels (the contents of color_base) into an array appears to be unsafe
555// -- there is no guarantee that the compiler won't add any padding between adjacent channels.
556// Note, however, that GIL _must_ be compiled with compiler settings ensuring there is no padding in the color base structs.
557// This is because the color base structs must model the interleaved organization in memory. In other words, the client may
558// have existing RGB image in the form "RGBRGBRGB..." and we must be able to represent it with an array of RGB color bases (i.e. RGB pixels)
559// with no padding. We have tested with char/int/float/double channels on gcc and VC and have so far discovered no problem.
560// We have even tried using strange channels consisting of short + char (3 bytes). With the default 4-byte alignment on VC, the size
561// of this channel is padded to 4 bytes, so an RGB pixel of it will be 4x3=12 bytes. The code below will still work properly.
562// However, the client must nevertheless ensure that proper compiler settings are used for their compiler and their channel types.
563
564template <typename Element, typename Layout, int K>
565auto dynamic_at_c(homogeneous_color_base<Element,Layout,K>& cb, std::size_t i)
567{
568 BOOST_ASSERT(i < K);
569 return (gil_reinterpret_cast<Element*>(&cb))[i];
570}
571
572template <typename Element, typename Layout, int K>
573auto dynamic_at_c(homogeneous_color_base<Element, Layout, K> const& cb, std::size_t i)
575 <
576 homogeneous_color_base<Element, Layout, K>
577 >::type
578{
579 BOOST_ASSERT(i < K);
580 return (gil_reinterpret_cast_c<const Element*>(&cb))[i];
581}
582
583template <typename Element, typename Layout, int K>
584auto dynamic_at_c(homogeneous_color_base<Element&, Layout, K> const& cb, std::size_t i)
585 -> typename element_reference_type
586 <
587 homogeneous_color_base<Element&, Layout, K>
588 >::type
589{
590 BOOST_ASSERT(i < K);
591 return cb.at_c_dynamic(i);
592}
593
594template <typename Element, typename Layout, int K>
595auto dynamic_at_c(
596 homogeneous_color_base<Element const&, Layout, K>const& cb, std::size_t i)
597 -> typename element_const_reference_type
598 <
599 homogeneous_color_base<Element const&, Layout, K>
600 >::type
601{
602 BOOST_ASSERT(i < K);
603 return cb.at_c_dynamic(i);
604}
605
606} // namespace detail
607
608template <typename Element, typename Layout, int K1, int K>
609struct kth_element_type<detail::homogeneous_color_base<Element, Layout, K1>, K>
610{
611 using type = Element;
612};
613
614template <typename Element, typename Layout, int K1, int K>
615struct kth_element_reference_type<detail::homogeneous_color_base<Element, Layout, K1>, K>
616 : std::add_lvalue_reference<Element>
617{};
618
619template <typename Element, typename Layout, int K1, int K>
620struct kth_element_const_reference_type
621 <
622 detail::homogeneous_color_base<Element, Layout, K1>,
623 K
624 >
625 : std::add_lvalue_reference<typename std::add_const<Element>::type>
626{};
627
630template <int K, typename E, typename L, int N>
631inline
632auto at_c(detail::homogeneous_color_base<E, L, N>& p)
633 -> typename std::add_lvalue_reference<E>::type
634{
635 return p.at(std::integral_constant<int, K>());
636}
637
640template <int K, typename E, typename L, int N>
641inline
642auto at_c(const detail::homogeneous_color_base<E, L, N>& p)
643 -> typename std::add_lvalue_reference<typename std::add_const<E>::type>::type
644{
645 return p.at(std::integral_constant<int, K>());
646}
647
648namespace detail
649{
650
651struct swap_fn
652{
653 template <typename T>
654 void operator()(T& x, T& y) const
655 {
656 using std::swap;
657 swap(x, y);
658 }
659};
660
661} // namespace detail
662
663template <typename E, typename L, int N>
664inline
665void swap(
666 detail::homogeneous_color_base<E, L, N>& x,
667 detail::homogeneous_color_base<E, L, N>& y)
668{
669 static_for_each(x, y, detail::swap_fn());
670}
671
672}} // namespace boost::gil
673
674#endif
auto semantic_at_c(ColorBase &p) -> typename std::enable_if< !std::is_const< ColorBase >::value, typename kth_semantic_element_reference_type< ColorBase, K >::type >::type
A mutable accessor to the K-th semantic element of a color base.
Definition color_base_algorithm.hpp:119
defined(BOOST_NO_CXX17_HDR_MEMORY_RESOURCE)
Definition algorithm.hpp:36
Specifies the return type of the constant element accessor at_c of a homogeneous color base.
Definition color_base_algorithm.hpp:235
Specifies the return type of the mutable element accessor at_c of a homogeneous color base.
Definition color_base_algorithm.hpp:230