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 
21 namespace boost { namespace gil {
22 
23 // Forward-declare
24 template <typename P> P* memunit_advanced(const P* p, std::ptrdiff_t diff);
25 
26 // Forward-declare semantic_at_c
27 template <int K, typename ColorBase>
28 auto 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 
36 template <int K, typename ColorBase>
37 auto semantic_at_c(const ColorBase& p) -> typename kth_semantic_element_const_reference_type<ColorBase,K>::type;
38 
39 // Forward declare element_reference_type
40 template <typename ColorBase> struct element_reference_type;
41 template <typename ColorBase> struct element_const_reference_type;
42 template <typename ColorBase, int K> struct kth_element_type;
43 template <typename ColorBase, int K> struct kth_element_type<const ColorBase,K> : public kth_element_type<ColorBase,K> {};
44 template <typename ColorBase, int K> struct kth_element_reference_type;
45 template <typename ColorBase, int K> struct kth_element_reference_type<const ColorBase,K> : public kth_element_reference_type<ColorBase,K> {};
46 template <typename ColorBase, int K> struct kth_element_const_reference_type;
47 template <typename ColorBase, int K> struct kth_element_const_reference_type<const ColorBase,K> : public kth_element_const_reference_type<ColorBase,K> {};
48 
49 namespace detail {
50 
51 template <typename DstLayout, typename SrcLayout, int K>
52 struct 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 
77 template <typename Element, typename Layout>
78 struct 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 
108 private:
109  Element v0_;
110 };
111 
115 template <typename Element, typename Layout>
116 struct 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 
189 private:
190  Element v0_;
191  Element v1_;
192 };
193 
197 template <typename Element, typename Layout>
198 struct 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 
290 private:
291  Element v0_;
292  Element v1_;
293  Element v2_;
294 };
295 
299 template <typename Element, typename Layout>
300 struct 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 
406 private:
407  Element v0_;
408  Element v1_;
409  Element v2_;
410  Element v3_;
411 };
412 
416 template <typename Element, typename Layout>
417 struct 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 
542 private:
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 
564 template <typename Element, typename Layout, int K>
565 auto 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 
572 template <typename Element, typename Layout, int K>
573 auto dynamic_at_c(homogeneous_color_base<Element, Layout, K> const& cb, std::size_t i)
574  -> typename element_const_reference_type
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 
583 template <typename Element, typename Layout, int K>
584 auto 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 
594 template <typename Element, typename Layout, int K>
595 auto 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 
608 template <typename Element, typename Layout, int K1, int K>
609 struct kth_element_type<detail::homogeneous_color_base<Element, Layout, K1>, K>
610 {
611  using type = Element;
612 };
613 
614 template <typename Element, typename Layout, int K1, int K>
615 struct kth_element_reference_type<detail::homogeneous_color_base<Element, Layout, K1>, K>
616  : std::add_lvalue_reference<Element>
617 {};
618 
619 template <typename Element, typename Layout, int K1, int K>
620 struct 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 
630 template <int K, typename E, typename L, int N>
631 inline
632 auto 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 
640 template <int K, typename E, typename L, int N>
641 inline
642 auto 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 
648 namespace detail
649 {
650 
651 struct 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 
663 template <typename E, typename L, int N>
664 inline
665 void 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(const ColorBase &p) -> typename kth_semantic_element_const_reference_type< ColorBase, K >::type
A constant accessor to the K-th semantic element of a color base.
Definition: color_base_algorithm.hpp:133
auto at_c(const detail::homogeneous_color_base< E, L, N > &p) -> typename std::add_lvalue_reference< typename std::add_const< E >::type >::type
Provides constant access to the K-th element, in physical order.
Definition: color_base.hpp:642
void swap(boost::gil::packed_channel_reference< BF, FB, NB, M > const x, R &y)
swap for packed_channel_reference
Definition: channel.hpp:583
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