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_ALGORITHM_HPP
10 #define BOOST_GIL_COLOR_BASE_ALGORITHM_HPP
11 
12 #include <boost/gil/concepts.hpp>
13 #include <boost/gil/utilities.hpp>
14 #include <boost/gil/detail/mp11.hpp>
15 
16 #include <boost/config.hpp>
17 
18 #include <algorithm>
19 #include <type_traits>
20 
21 namespace boost { namespace gil {
22 
23 ///////////////////////////////////////
24 /// size:   Semantic channel size
25 ///////////////////////////////////////
26 
27 /**
28 \defgroup ColorBaseAlgorithmSize size
29 \ingroup ColorBaseAlgorithm
30 \brief Returns an integral constant type specifying the number of elements in a color base
31 
32 Example:
33 \code
34 static_assert(size<rgb8_pixel_t>::value == 3, "");
35 static_assert(size<cmyk8_planar_ptr_t>::value == 4, "");
36 \endcode
37 */
38 
39 /// \brief Returns an integral constant type specifying the number of elements in a color base
40 /// \ingroup ColorBaseAlgorithmSize
41 template <typename ColorBase>
42 struct size : public mp11::mp_size<typename ColorBase::layout_t::color_space_t> {};
43 
44 ///////////////////////////////////////
45 /// semantic_at_c:   Semantic channel accessors
46 ///////////////////////////////////////
47 
48 /**
49 \defgroup ColorBaseAlgorithmSemanticAtC kth_semantic_element_type, kth_semantic_element_reference_type, kth_semantic_element_const_reference_type, semantic_at_c
50 \ingroup ColorBaseAlgorithm
51 \brief Support for accessing the elements of a color base by semantic index
52 
53 The semantic index of an element is the index of its color in the color space. Semantic indexing allows for proper pairing of elements of color bases
54 independent on their layout. For example, red is the first semantic element of a color base regardless of whether it has an RGB layout or a BGR layout.
55 All GIL color base algorithms taking multiple color bases use semantic indexing to access their elements.
56 
57 Example:
58 \code
59 // 16-bit BGR pixel, 4 bits for the blue, 3 bits for the green, 2 bits for the red channel and 7 unused bits
60 using bgr432_pixel_t = packed_pixel_type<uint16_t, mp11::mp_list_c<unsigned,4,3,2>, bgr_layout_t>::type;
61 
62 // A reference to its red channel. Although the red channel is the third, its semantic index is 0 in the RGB color space
63 using red_channel_reference_t = kth_semantic_element_reference_type<bgr432_pixel_t, 0>::type;
64 
65 // Initialize the pixel to black
66 bgr432_pixel_t red_pixel(0,0,0);
67 
68 // Set the red channel to 100%
69 red_channel_reference_t red_channel = semantic_at_c<0>(red_pixel);
70 red_channel = channel_traits<red_channel_reference_t>::max_value();
71 
72 \endcode
73 */
74 /// \brief Specifies the type of the K-th semantic element of a color base
75 /// \ingroup ColorBaseAlgorithmSemanticAtC
76 template <typename ColorBase, int K>
77 struct kth_semantic_element_type
78 {
79     using channel_mapping_t = typename ColorBase::layout_t::channel_mapping_t;
80     static_assert(K < mp11::mp_size<channel_mapping_t>::value,
81         "K index should be less than size of channel_mapping_t sequence");
82 
83     static constexpr int semantic_index = mp11::mp_at_c<channel_mapping_t, K>::type::value;
84     using type = typename kth_element_type<ColorBase, semantic_index>::type;
85 };
86 
87 /// \brief Specifies the return type of the mutable semantic_at_c<K>(color_base);
88 /// \ingroup ColorBaseAlgorithmSemanticAtC
89 template <typename ColorBase, int K>
90 struct kth_semantic_element_reference_type
91 {
92     using channel_mapping_t = typename ColorBase::layout_t::channel_mapping_t;
93     static_assert(K < mp11::mp_size<channel_mapping_t>::value,
94         "K index should be less than size of channel_mapping_t sequence");
95 
96     static constexpr int semantic_index = mp11::mp_at_c<channel_mapping_t, K>::type::value;
97     using type = typename kth_element_reference_type<ColorBase, semantic_index>::type;
getboost::gil::kth_semantic_element_reference_type98     static type get(ColorBase& cb) { return gil::at_c<semantic_index>(cb); }
99 };
100 
101 /// \brief Specifies the return type of the constant semantic_at_c<K>(color_base);
102 /// \ingroup ColorBaseAlgorithmSemanticAtC
103 template <typename ColorBase, int K>
104 struct kth_semantic_element_const_reference_type
105 {
106     using channel_mapping_t = typename ColorBase::layout_t::channel_mapping_t;
107     static_assert(K < mp11::mp_size<channel_mapping_t>::value,
108         "K index should be less than size of channel_mapping_t sequence");
109 
110     static constexpr int semantic_index = mp11::mp_at_c<channel_mapping_t, K>::type::value;
111     using type = typename kth_element_const_reference_type<ColorBase,semantic_index>::type;
getboost::gil::kth_semantic_element_const_reference_type112     static type get(const ColorBase& cb) { return gil::at_c<semantic_index>(cb); }
113 };
114 
115 /// \brief A mutable accessor to the K-th semantic element of a color base
116 /// \ingroup ColorBaseAlgorithmSemanticAtC
117 template <int K, typename ColorBase>
118 inline
semantic_at_c(ColorBase & p)119 auto semantic_at_c(ColorBase& p)
120     -> typename std::enable_if
121     <
122         !std::is_const<ColorBase>::value,
123         typename kth_semantic_element_reference_type<ColorBase, K>::type
124     >::type
125 {
126     return kth_semantic_element_reference_type<ColorBase, K>::get(p);
127 }
128 
129 /// \brief A constant accessor to the K-th semantic element of a color base
130 /// \ingroup ColorBaseAlgorithmSemanticAtC
131 template <int K, typename ColorBase>
132 inline
semantic_at_c(ColorBase const & p)133 auto semantic_at_c(ColorBase const& p)
134     -> typename kth_semantic_element_const_reference_type<ColorBase, K>::type
135 {
136     return kth_semantic_element_const_reference_type<ColorBase, K>::get(p);
137 }
138 
139 ///////////////////////////////////////
140 /// get_color:   Named channel accessors
141 ///////////////////////////////////////
142 
143 /**
144 \defgroup ColorBaseAlgorithmColor color_element_type, color_element_reference_type, color_element_const_reference_type, get_color, contains_color
145 \ingroup ColorBaseAlgorithm
146 \brief Support for accessing the elements of a color base by color name
147 
148 Example: A function that takes a generic pixel containing a red channel and sets it to 100%:
149 
150 \code
151 template <typename Pixel>
152 void set_red_to_max(Pixel& pixel) {
153     boost::function_requires<MutablePixelConcept<Pixel> >();
154     static_assert(contains_color<Pixel, red_t>::value, "");
155 
156     using red_channel_t = typename color_element_type<Pixel, red_t>::type;
157     get_color(pixel, red_t()) = channel_traits<red_channel_t>::max_value();
158 }
159 \endcode
160 */
161 
162 /// \brief A predicate metafunction determining whether a given color base contains a given color
163 /// \ingroup ColorBaseAlgorithmColor
164 template <typename ColorBase, typename Color>
165 struct contains_color
166     : mp11::mp_contains<typename ColorBase::layout_t::color_space_t, Color>
167 {};
168 
169 template <typename ColorBase, typename Color>
170 struct color_index_type : public detail::type_to_index<typename ColorBase::layout_t::color_space_t,Color> {};
171 
172 /// \brief Specifies the type of the element associated with a given color tag
173 /// \ingroup ColorBaseAlgorithmColor
174 template <typename ColorBase, typename Color>
175 struct color_element_type : public kth_semantic_element_type<ColorBase,color_index_type<ColorBase,Color>::value> {};
176 
177 /// \brief Specifies the return type of the mutable element accessor by color name, get_color(color_base, Color());
178 /// \ingroup ColorBaseAlgorithmColor
179 template <typename ColorBase, typename Color>
180 struct color_element_reference_type : public kth_semantic_element_reference_type<ColorBase,color_index_type<ColorBase,Color>::value> {};
181 
182 /// \brief Specifies the return type of the constant element accessor by color name, get_color(color_base, Color());
183 /// \ingroup ColorBaseAlgorithmColor
184 template <typename ColorBase, typename Color>
185 struct color_element_const_reference_type : public kth_semantic_element_const_reference_type<ColorBase,color_index_type<ColorBase,Color>::value> {};
186 
187 /// \brief Mutable accessor to the element associated with a given color name
188 /// \ingroup ColorBaseAlgorithmColor
189 template <typename ColorBase, typename Color>
get_color(ColorBase & cb,Color=Color ())190 typename color_element_reference_type<ColorBase,Color>::type get_color(ColorBase& cb, Color=Color()) {
191     return color_element_reference_type<ColorBase,Color>::get(cb);
192 }
193 
194 /// \brief Constant accessor to the element associated with a given color name
195 /// \ingroup ColorBaseAlgorithmColor
196 template <typename ColorBase, typename Color>
get_color(const ColorBase & cb,Color=Color ())197 typename color_element_const_reference_type<ColorBase,Color>::type get_color(const ColorBase& cb, Color=Color()) {
198     return color_element_const_reference_type<ColorBase,Color>::get(cb);
199 }
200 
201 ///////////////////////////////////////
202 ///
203 /// element_type, element_reference_type, element_const_reference_type: Support for homogeneous color bases
204 ///
205 ///////////////////////////////////////
206 
207 /**
208 \defgroup ColorBaseAlgorithmHomogeneous element_type, element_reference_type, element_const_reference_type
209 \ingroup ColorBaseAlgorithm
210 \brief Types for homogeneous color bases
211 
212 Example:
213 \code
214 using element_t = element_type<rgb8c_planar_ptr_t>::type;
215 static_assert(std::is_same<element_t, const uint8_t*>::value, "");
216 \endcode
217 */
218 /// \brief Specifies the element type of a homogeneous color base
219 /// \ingroup ColorBaseAlgorithmHomogeneous
220 template <typename ColorBase>
221 struct element_type : public kth_element_type<ColorBase, 0> {};
222 
223 /// \brief Specifies the return type of the mutable element accessor at_c of a homogeneous color base
224 /// \ingroup ColorBaseAlgorithmHomogeneous
225 template <typename ColorBase>
226 struct element_reference_type : public kth_element_reference_type<ColorBase, 0> {};
227 
228 /// \brief Specifies the return type of the constant element accessor at_c of a homogeneous color base
229 /// \ingroup ColorBaseAlgorithmHomogeneous
230 template <typename ColorBase>
231 struct element_const_reference_type : public kth_element_const_reference_type<ColorBase, 0> {};
232 
233 
234 namespace detail {
235 
236 // compile-time recursion for per-element operations on color bases
237 template <int N>
238 struct element_recursion
239 {
240 
241 #if defined(BOOST_GCC) && (BOOST_GCC >= 40900)
242 #pragma GCC diagnostic push
243 #pragma GCC diagnostic ignored "-Wconversion"
244 #pragma GCC diagnostic ignored "-Wfloat-equal"
245 #endif
246 
247     template <typename P1,typename P2>
static_equalboost::gil::detail::element_recursion248     static bool static_equal(const P1& p1, const P2& p2)
249     {
250         return element_recursion<N-1>::static_equal(p1,p2) &&
251                semantic_at_c<N-1>(p1)==semantic_at_c<N-1>(p2);
252     }
253 
254     template <typename P1,typename P2>
static_copyboost::gil::detail::element_recursion255     static void static_copy(const P1& p1, P2& p2)
256     {
257         element_recursion<N-1>::static_copy(p1,p2);
258         semantic_at_c<N-1>(p2)=semantic_at_c<N-1>(p1);
259     }
260 
261     template <typename P,typename T2>
static_fillboost::gil::detail::element_recursion262     static void static_fill(P& p, T2 v)
263     {
264         element_recursion<N-1>::static_fill(p,v);
265         semantic_at_c<N-1>(p)=v;
266     }
267 
268     template <typename Dst,typename Op>
static_generateboost::gil::detail::element_recursion269     static void static_generate(Dst& dst, Op op)
270     {
271         element_recursion<N-1>::static_generate(dst,op);
272         semantic_at_c<N-1>(dst)=op();
273     }
274 
275 #if defined(BOOST_GCC) && (BOOST_GCC >= 40900)
276 #pragma GCC diagnostic pop
277 #endif
278 
279     //static_for_each with one source
280     template <typename P1,typename Op>
static_for_eachboost::gil::detail::element_recursion281     static Op static_for_each(P1& p1, Op op) {
282         Op op2(element_recursion<N-1>::static_for_each(p1,op));
283         op2(semantic_at_c<N-1>(p1));
284         return op2;
285     }
286     template <typename P1,typename Op>
static_for_eachboost::gil::detail::element_recursion287     static Op static_for_each(const P1& p1, Op op) {
288         Op op2(element_recursion<N-1>::static_for_each(p1,op));
289         op2(semantic_at_c<N-1>(p1));
290         return op2;
291     }
292     //static_for_each with two sources
293     template <typename P1,typename P2,typename Op>
static_for_eachboost::gil::detail::element_recursion294     static Op static_for_each(P1& p1, P2& p2, Op op) {
295         Op op2(element_recursion<N-1>::static_for_each(p1,p2,op));
296         op2(semantic_at_c<N-1>(p1), semantic_at_c<N-1>(p2));
297         return op2;
298     }
299     template <typename P1,typename P2,typename Op>
static_for_eachboost::gil::detail::element_recursion300     static Op static_for_each(P1& p1, const P2& p2, Op op) {
301         Op op2(element_recursion<N-1>::static_for_each(p1,p2,op));
302         op2(semantic_at_c<N-1>(p1), semantic_at_c<N-1>(p2));
303         return op2;
304     }
305     template <typename P1,typename P2,typename Op>
static_for_eachboost::gil::detail::element_recursion306     static Op static_for_each(const P1& p1, P2& p2, Op op) {
307         Op op2(element_recursion<N-1>::static_for_each(p1,p2,op));
308         op2(semantic_at_c<N-1>(p1), semantic_at_c<N-1>(p2));
309         return op2;
310     }
311     template <typename P1,typename P2,typename Op>
static_for_eachboost::gil::detail::element_recursion312     static Op static_for_each(const P1& p1, const P2& p2, Op op) {
313         Op op2(element_recursion<N-1>::static_for_each(p1,p2,op));
314         op2(semantic_at_c<N-1>(p1), semantic_at_c<N-1>(p2));
315         return op2;
316     }
317     //static_for_each with three sources
318     template <typename P1,typename P2,typename P3,typename Op>
static_for_eachboost::gil::detail::element_recursion319     static Op static_for_each(P1& p1, P2& p2, P3& p3, Op op) {
320         Op op2(element_recursion<N-1>::static_for_each(p1,p2,p3,op));
321         op2(semantic_at_c<N-1>(p1), semantic_at_c<N-1>(p2), semantic_at_c<N-1>(p3));
322         return op2;
323     }
324     template <typename P1,typename P2,typename P3,typename Op>
static_for_eachboost::gil::detail::element_recursion325     static Op static_for_each(P1& p1, P2& p2, const P3& p3, Op op) {
326         Op op2(element_recursion<N-1>::static_for_each(p1,p2,p3,op));
327         op2(semantic_at_c<N-1>(p1), semantic_at_c<N-1>(p2), semantic_at_c<N-1>(p3));
328         return op2;
329     }
330     template <typename P1,typename P2,typename P3,typename Op>
static_for_eachboost::gil::detail::element_recursion331     static Op static_for_each(P1& p1, const P2& p2, P3& p3, Op op) {
332         Op op2(element_recursion<N-1>::static_for_each(p1,p2,p3,op));
333         op2(semantic_at_c<N-1>(p1), semantic_at_c<N-1>(p2), semantic_at_c<N-1>(p3));
334         return op2;
335     }
336     template <typename P1,typename P2,typename P3,typename Op>
static_for_eachboost::gil::detail::element_recursion337     static Op static_for_each(P1& p1, const P2& p2, const P3& p3, Op op) {
338         Op op2(element_recursion<N-1>::static_for_each(p1,p2,p3,op));
339         op2(semantic_at_c<N-1>(p1), semantic_at_c<N-1>(p2), semantic_at_c<N-1>(p3));
340         return op2;
341     }
342     template <typename P1,typename P2,typename P3,typename Op>
static_for_eachboost::gil::detail::element_recursion343     static Op static_for_each(const P1& p1, P2& p2, P3& p3, Op op) {
344         Op op2(element_recursion<N-1>::static_for_each(p1,p2,p3,op));
345         op2(semantic_at_c<N-1>(p1), semantic_at_c<N-1>(p2), semantic_at_c<N-1>(p3));
346         return op2;
347     }
348     template <typename P1,typename P2,typename P3,typename Op>
static_for_eachboost::gil::detail::element_recursion349     static Op static_for_each(const P1& p1, P2& p2, const P3& p3, Op op) {
350         Op op2(element_recursion<N-1>::static_for_each(p1,p2,p3,op));
351         op2(semantic_at_c<N-1>(p1), semantic_at_c<N-1>(p2), semantic_at_c<N-1>(p3));
352         return op2;
353     }
354     template <typename P1,typename P2,typename P3,typename Op>
static_for_eachboost::gil::detail::element_recursion355     static Op static_for_each(const P1& p1, const P2& p2, P3& p3, Op op) {
356         Op op2(element_recursion<N-1>::static_for_each(p1,p2,p3,op));
357         op2(semantic_at_c<N-1>(p1), semantic_at_c<N-1>(p2), semantic_at_c<N-1>(p3));
358         return op2;
359     }
360     template <typename P1,typename P2,typename P3,typename Op>
static_for_eachboost::gil::detail::element_recursion361     static Op static_for_each(const P1& p1, const P2& p2, const P3& p3, Op op) {
362         Op op2(element_recursion<N-1>::static_for_each(p1,p2,p3,op));
363         op2(semantic_at_c<N-1>(p1), semantic_at_c<N-1>(p2), semantic_at_c<N-1>(p3));
364         return op2;
365     }
366     //static_transform with one source
367     template <typename P1,typename Dst,typename Op>
static_transformboost::gil::detail::element_recursion368     static Op static_transform(P1& src, Dst& dst, Op op) {
369         Op op2(element_recursion<N-1>::static_transform(src,dst,op));
370         semantic_at_c<N-1>(dst)=op2(semantic_at_c<N-1>(src));
371         return op2;
372     }
373     template <typename P1,typename Dst,typename Op>
static_transformboost::gil::detail::element_recursion374     static Op static_transform(const P1& src, Dst& dst, Op op) {
375         Op op2(element_recursion<N-1>::static_transform(src,dst,op));
376         semantic_at_c<N-1>(dst)=op2(semantic_at_c<N-1>(src));
377         return op2;
378     }
379     //static_transform with two sources
380     template <typename P1,typename P2,typename Dst,typename Op>
static_transformboost::gil::detail::element_recursion381     static Op static_transform(P1& src1, P2& src2, Dst& dst, Op op) {
382         Op op2(element_recursion<N-1>::static_transform(src1,src2,dst,op));
383         semantic_at_c<N-1>(dst)=op2(semantic_at_c<N-1>(src1), semantic_at_c<N-1>(src2));
384         return op2;
385     }
386     template <typename P1,typename P2,typename Dst,typename Op>
static_transformboost::gil::detail::element_recursion387     static Op static_transform(P1& src1, const P2& src2, Dst& dst, Op op) {
388         Op op2(element_recursion<N-1>::static_transform(src1,src2,dst,op));
389         semantic_at_c<N-1>(dst)=op2(semantic_at_c<N-1>(src1), semantic_at_c<N-1>(src2));
390         return op2;
391     }
392     template <typename P1,typename P2,typename Dst,typename Op>
static_transformboost::gil::detail::element_recursion393     static Op static_transform(const P1& src1, P2& src2, Dst& dst, Op op) {
394         Op op2(element_recursion<N-1>::static_transform(src1,src2,dst,op));
395         semantic_at_c<N-1>(dst)=op2(semantic_at_c<N-1>(src1), semantic_at_c<N-1>(src2));
396         return op2;
397     }
398     template <typename P1,typename P2,typename Dst,typename Op>
static_transformboost::gil::detail::element_recursion399     static Op static_transform(const P1& src1, const P2& src2, Dst& dst, Op op) {
400         Op op2(element_recursion<N-1>::static_transform(src1,src2,dst,op));
401         semantic_at_c<N-1>(dst)=op2(semantic_at_c<N-1>(src1), semantic_at_c<N-1>(src2));
402         return op2;
403     }
404 };
405 
406 // Termination condition of the compile-time recursion for element operations on a color base
407 template<> struct element_recursion<0> {
408     //static_equal
409     template <typename P1,typename P2>
static_equalboost::gil::detail::element_recursion410     static bool static_equal(const P1&, const P2&) { return true; }
411     //static_copy
412     template <typename P1,typename P2>
static_copyboost::gil::detail::element_recursion413     static void static_copy(const P1&, const P2&) {}
414     //static_fill
415     template <typename P, typename T2>
static_fillboost::gil::detail::element_recursion416     static void static_fill(const P&, T2) {}
417     //static_generate
418     template <typename Dst,typename Op>
static_generateboost::gil::detail::element_recursion419     static void static_generate(const Dst&,Op){}
420     //static_for_each with one source
421     template <typename P1,typename Op>
static_for_eachboost::gil::detail::element_recursion422     static Op static_for_each(const P1&,Op op){return op;}
423     //static_for_each with two sources
424     template <typename P1,typename P2,typename Op>
static_for_eachboost::gil::detail::element_recursion425     static Op static_for_each(const P1&,const P2&,Op op){return op;}
426     //static_for_each with three sources
427     template <typename P1,typename P2,typename P3,typename Op>
static_for_eachboost::gil::detail::element_recursion428     static Op static_for_each(const P1&,const P2&,const P3&,Op op){return op;}
429     //static_transform with one source
430     template <typename P1,typename Dst,typename Op>
static_transformboost::gil::detail::element_recursion431     static Op static_transform(const P1&,const Dst&,Op op){return op;}
432     //static_transform with two sources
433     template <typename P1,typename P2,typename Dst,typename Op>
static_transformboost::gil::detail::element_recursion434     static Op static_transform(const P1&,const P2&,const Dst&,Op op){return op;}
435 };
436 
437 // std::min and std::max don't have the mutable overloads...
mutable_min(const Q & x,const Q & y)438 template <typename Q> inline const Q& mutable_min(const Q& x, const Q& y) { return x<y ? x : y; }
mutable_min(Q & x,Q & y)439 template <typename Q> inline       Q& mutable_min(      Q& x,       Q& y) { return x<y ? x : y; }
mutable_max(const Q & x,const Q & y)440 template <typename Q> inline const Q& mutable_max(const Q& x, const Q& y) { return x<y ? y : x; }
mutable_max(Q & x,Q & y)441 template <typename Q> inline       Q& mutable_max(      Q& x,       Q& y) { return x<y ? y : x; }
442 
443 
444 // compile-time recursion for min/max element
445 template <int N>
446 struct min_max_recur {
max_boost::gil::detail::min_max_recur447     template <typename P> static typename element_const_reference_type<P>::type max_(const P& p) {
448         return mutable_max(min_max_recur<N-1>::max_(p),semantic_at_c<N-1>(p));
449     }
max_boost::gil::detail::min_max_recur450     template <typename P> static typename element_reference_type<P>::type       max_(      P& p) {
451         return mutable_max(min_max_recur<N-1>::max_(p),semantic_at_c<N-1>(p));
452     }
min_boost::gil::detail::min_max_recur453     template <typename P> static typename element_const_reference_type<P>::type min_(const P& p) {
454         return mutable_min(min_max_recur<N-1>::min_(p),semantic_at_c<N-1>(p));
455     }
min_boost::gil::detail::min_max_recur456     template <typename P> static typename element_reference_type<P>::type       min_(      P& p) {
457         return mutable_min(min_max_recur<N-1>::min_(p),semantic_at_c<N-1>(p));
458     }
459 };
460 
461 // termination condition of the compile-time recursion for min/max element
462 template <>
463 struct min_max_recur<1> {
max_boost::gil::detail::min_max_recur464     template <typename P> static typename element_const_reference_type<P>::type max_(const P& p) { return semantic_at_c<0>(p); }
max_boost::gil::detail::min_max_recur465     template <typename P> static typename element_reference_type<P>::type       max_(      P& p) { return semantic_at_c<0>(p); }
min_boost::gil::detail::min_max_recur466     template <typename P> static typename element_const_reference_type<P>::type min_(const P& p) { return semantic_at_c<0>(p); }
min_boost::gil::detail::min_max_recur467     template <typename P> static typename element_reference_type<P>::type       min_(      P& p) { return semantic_at_c<0>(p); }
468 };
469 }  // namespace detail
470 
471 /// \defgroup ColorBaseAlgorithmMinMax static_min, static_max
472 /// \ingroup ColorBaseAlgorithm
473 /// \brief Equivalents to std::min_element and std::max_element for homogeneous color bases
474 ///
475 /// Example:
476 /// \code
477 /// rgb8_pixel_t pixel(10,20,30);
478 /// assert(pixel[2] == 30);
479 /// static_max(pixel) = static_min(pixel);
480 /// assert(pixel[2] == 10);
481 /// \endcode
482 /// \{
483 
484 template <typename P>
485 BOOST_FORCEINLINE
static_max(const P & p)486 typename element_const_reference_type<P>::type static_max(const P& p) { return detail::min_max_recur<size<P>::value>::max_(p); }
487 
488 template <typename P>
489 BOOST_FORCEINLINE
static_max(P & p)490 typename element_reference_type<P>::type       static_max(      P& p) { return detail::min_max_recur<size<P>::value>::max_(p); }
491 
492 template <typename P>
493 BOOST_FORCEINLINE
static_min(const P & p)494 typename element_const_reference_type<P>::type static_min(const P& p) { return detail::min_max_recur<size<P>::value>::min_(p); }
495 
496 template <typename P>
497 BOOST_FORCEINLINE
static_min(P & p)498 typename element_reference_type<P>::type       static_min(      P& p) { return detail::min_max_recur<size<P>::value>::min_(p); }
499 /// \}
500 
501 /// \defgroup ColorBaseAlgorithmEqual static_equal
502 /// \ingroup ColorBaseAlgorithm
503 /// \brief Equivalent to std::equal. Pairs the elements semantically
504 ///
505 /// Example:
506 /// \code
507 /// rgb8_pixel_t rgb_red(255,0,0);
508 /// bgr8_pixel_t bgr_red(0,0,255);
509 /// assert(rgb_red[0]==255 && bgr_red[0]==0);
510 ///
511 /// assert(static_equal(rgb_red,bgr_red));
512 /// assert(rgb_red==bgr_red);  // operator== invokes static_equal
513 /// \endcode
514 /// \{
515 
516 template <typename P1,typename P2>
517 BOOST_FORCEINLINE
static_equal(const P1 & p1,const P2 & p2)518 bool static_equal(const P1& p1, const P2& p2) { return detail::element_recursion<size<P1>::value>::static_equal(p1,p2); }
519 
520 /// \}
521 
522 /// \defgroup ColorBaseAlgorithmCopy static_copy
523 /// \ingroup ColorBaseAlgorithm
524 /// \brief Equivalent to std::copy. Pairs the elements semantically
525 ///
526 /// Example:
527 /// \code
528 /// rgb8_pixel_t rgb_red(255,0,0);
529 /// bgr8_pixel_t bgr_red;
530 /// static_copy(rgb_red, bgr_red);  // same as bgr_red = rgb_red
531 ///
532 /// assert(rgb_red[0] == 255 && bgr_red[0] == 0);
533 /// assert(rgb_red == bgr_red);
534 /// \endcode
535 /// \{
536 
537 template <typename Src,typename Dst>
538 BOOST_FORCEINLINE
static_copy(const Src & src,Dst & dst)539 void static_copy(const Src& src, Dst& dst)
540 {
541     detail::element_recursion<size<Dst>::value>::static_copy(src, dst);
542 }
543 
544 /// \}
545 
546 /// \defgroup ColorBaseAlgorithmFill static_fill
547 /// \ingroup ColorBaseAlgorithm
548 /// \brief Equivalent to std::fill.
549 ///
550 /// Example:
551 /// \code
552 /// rgb8_pixel_t p;
553 /// static_fill(p, 10);
554 /// assert(p == rgb8_pixel_t(10,10,10));
555 /// \endcode
556 /// \{
557 
558 template <typename P,typename V>
559 BOOST_FORCEINLINE
static_fill(P & p,const V & v)560 void static_fill(P& p, const V& v)
561 {
562     detail::element_recursion<size<P>::value>::static_fill(p,v);
563 }
564 
565 /// \}
566 
567 /// \defgroup ColorBaseAlgorithmGenerate static_generate
568 /// \ingroup ColorBaseAlgorithm
569 /// \brief Equivalent to std::generate.
570 ///
571 /// Example: Set each channel of a pixel to its semantic index. The channels must be assignable from an integer.
572 /// \code
573 /// struct consecutive_fn {
574 ///     int& _current;
575 ///     consecutive_fn(int& start) : _current(start) {}
576 ///     int operator()() { return _current++; }
577 /// };
578 /// rgb8_pixel_t p;
579 /// int start=0;
580 /// static_generate(p, consecutive_fn(start));
581 /// assert(p == rgb8_pixel_t(0,1,2));
582 /// \endcode
583 ///
584 /// \{
585 
586 template <typename P1,typename Op>
587 BOOST_FORCEINLINE
static_generate(P1 & dst,Op op)588 void static_generate(P1& dst,Op op)                      { detail::element_recursion<size<P1>::value>::static_generate(dst,op); }
589 /// \}
590 
591 /// \defgroup ColorBaseAlgorithmTransform static_transform
592 /// \ingroup ColorBaseAlgorithm
593 /// \brief Equivalent to std::transform. Pairs the elements semantically
594 ///
595 /// Example: Write a generic function that adds two pixels into a homogeneous result pixel.
596 /// \code
597 /// template <typename Result>
598 /// struct my_plus {
599 ///     template <typename T1, typename T2>
600 ///     Result operator()(T1 f1, T2 f2) const { return f1+f2; }
601 /// };
602 ///
603 /// template <typename Pixel1, typename Pixel2, typename Pixel3>
604 /// void sum_channels(const Pixel1& p1, const Pixel2& p2, Pixel3& result) {
605 ///     using result_channel_t = typename channel_type<Pixel3>::type;
606 ///     static_transform(p1,p2,result,my_plus<result_channel_t>());
607 /// }
608 ///
609 /// rgb8_pixel_t p1(1,2,3);
610 /// bgr8_pixel_t p2(3,2,1);
611 /// rgb8_pixel_t result;
612 /// sum_channels(p1,p2,result);
613 /// assert(result == rgb8_pixel_t(2,4,6));
614 /// \endcode
615 /// \{
616 
617 //static_transform with one source
618 template <typename Src,typename Dst,typename Op>
619 BOOST_FORCEINLINE
static_transform(Src & src,Dst & dst,Op op)620 Op static_transform(Src& src,Dst& dst,Op op)              { return detail::element_recursion<size<Dst>::value>::static_transform(src,dst,op); }
621 template <typename Src,typename Dst,typename Op>
622 BOOST_FORCEINLINE
static_transform(const Src & src,Dst & dst,Op op)623 Op static_transform(const Src& src,Dst& dst,Op op)              { return detail::element_recursion<size<Dst>::value>::static_transform(src,dst,op); }
624 //static_transform with two sources
625 template <typename P2,typename P3,typename Dst,typename Op>
626 BOOST_FORCEINLINE
static_transform(P2 & p2,P3 & p3,Dst & dst,Op op)627 Op static_transform(P2& p2,P3& p3,Dst& dst,Op op) { return detail::element_recursion<size<Dst>::value>::static_transform(p2,p3,dst,op); }
628 template <typename P2,typename P3,typename Dst,typename Op>
629 BOOST_FORCEINLINE
static_transform(P2 & p2,const P3 & p3,Dst & dst,Op op)630 Op static_transform(P2& p2,const P3& p3,Dst& dst,Op op) { return detail::element_recursion<size<Dst>::value>::static_transform(p2,p3,dst,op); }
631 template <typename P2,typename P3,typename Dst,typename Op>
632 BOOST_FORCEINLINE
static_transform(const P2 & p2,P3 & p3,Dst & dst,Op op)633 Op static_transform(const P2& p2,P3& p3,Dst& dst,Op op) { return detail::element_recursion<size<Dst>::value>::static_transform(p2,p3,dst,op); }
634 template <typename P2,typename P3,typename Dst,typename Op>
635 BOOST_FORCEINLINE
static_transform(const P2 & p2,const P3 & p3,Dst & dst,Op op)636 Op static_transform(const P2& p2,const P3& p3,Dst& dst,Op op) { return detail::element_recursion<size<Dst>::value>::static_transform(p2,p3,dst,op); }
637 /// \}
638 
639 /// \defgroup ColorBaseAlgorithmForEach static_for_each
640 /// \ingroup ColorBaseAlgorithm
641 /// \brief Equivalent to std::for_each. Pairs the elements semantically
642 ///
643 /// Example: Use static_for_each to increment a planar pixel iterator
644 /// \code
645 /// struct increment {
646 ///     template <typename Incrementable>
647 ///     void operator()(Incrementable& x) const { ++x; }
648 /// };
649 ///
650 /// template <typename ColorBase>
651 /// void increment_elements(ColorBase& cb) {
652 ///     static_for_each(cb, increment());
653 /// }
654 ///
655 /// uint8_t red[2], green[2], blue[2];
656 /// rgb8c_planar_ptr_t p1(red,green,blue);
657 /// rgb8c_planar_ptr_t p2=p1;
658 /// increment_elements(p1);
659 /// ++p2;
660 /// assert(p1 == p2);
661 /// \endcode
662 /// \{
663 
664 //static_for_each with one source
665 template <typename P1,typename Op>
666 BOOST_FORCEINLINE
static_for_each(P1 & p1,Op op)667 Op static_for_each(      P1& p1, Op op)                          { return detail::element_recursion<size<P1>::value>::static_for_each(p1,op); }
668 template <typename P1,typename Op>
669 BOOST_FORCEINLINE
static_for_each(const P1 & p1,Op op)670 Op static_for_each(const P1& p1, Op op)                          { return detail::element_recursion<size<P1>::value>::static_for_each(p1,op); }
671 //static_for_each with two sources
672 template <typename P1,typename P2,typename Op>
673 BOOST_FORCEINLINE
static_for_each(P1 & p1,P2 & p2,Op op)674 Op static_for_each(P1& p1,      P2& p2, Op op)             { return detail::element_recursion<size<P1>::value>::static_for_each(p1,p2,op); }
675 template <typename P1,typename P2,typename Op>
676 BOOST_FORCEINLINE
static_for_each(P1 & p1,const P2 & p2,Op op)677 Op static_for_each(P1& p1,const P2& p2, Op op)             { return detail::element_recursion<size<P1>::value>::static_for_each(p1,p2,op); }
678 template <typename P1,typename P2,typename Op>
679 BOOST_FORCEINLINE
static_for_each(const P1 & p1,P2 & p2,Op op)680 Op static_for_each(const P1& p1,      P2& p2, Op op)             { return detail::element_recursion<size<P1>::value>::static_for_each(p1,p2,op); }
681 template <typename P1,typename P2,typename Op>
682 BOOST_FORCEINLINE
static_for_each(const P1 & p1,const P2 & p2,Op op)683 Op static_for_each(const P1& p1,const P2& p2, Op op)             { return detail::element_recursion<size<P1>::value>::static_for_each(p1,p2,op); }
684 //static_for_each with three sources
685 template <typename P1,typename P2,typename P3,typename Op>
686 BOOST_FORCEINLINE
static_for_each(P1 & p1,P2 & p2,P3 & p3,Op op)687 Op static_for_each(P1& p1,P2& p2,P3& p3,Op op) { return detail::element_recursion<size<P1>::value>::static_for_each(p1,p2,p3,op); }
688 template <typename P1,typename P2,typename P3,typename Op>
689 BOOST_FORCEINLINE
static_for_each(P1 & p1,P2 & p2,const P3 & p3,Op op)690 Op static_for_each(P1& p1,P2& p2,const P3& p3,Op op) { return detail::element_recursion<size<P1>::value>::static_for_each(p1,p2,p3,op); }
691 template <typename P1,typename P2,typename P3,typename Op>
692 BOOST_FORCEINLINE
static_for_each(P1 & p1,const P2 & p2,P3 & p3,Op op)693 Op static_for_each(P1& p1,const P2& p2,P3& p3,Op op) { return detail::element_recursion<size<P1>::value>::static_for_each(p1,p2,p3,op); }
694 template <typename P1,typename P2,typename P3,typename Op>
695 BOOST_FORCEINLINE
static_for_each(P1 & p1,const P2 & p2,const P3 & p3,Op op)696 Op static_for_each(P1& p1,const P2& p2,const P3& p3,Op op) { return detail::element_recursion<size<P1>::value>::static_for_each(p1,p2,p3,op); }
697 template <typename P1,typename P2,typename P3,typename Op>
698 BOOST_FORCEINLINE
static_for_each(const P1 & p1,P2 & p2,P3 & p3,Op op)699 Op static_for_each(const P1& p1,P2& p2,P3& p3,Op op) { return detail::element_recursion<size<P1>::value>::static_for_each(p1,p2,p3,op); }
700 template <typename P1,typename P2,typename P3,typename Op>
701 BOOST_FORCEINLINE
static_for_each(const P1 & p1,P2 & p2,const P3 & p3,Op op)702 Op static_for_each(const P1& p1,P2& p2,const P3& p3,Op op) { return detail::element_recursion<size<P1>::value>::static_for_each(p1,p2,p3,op); }
703 template <typename P1,typename P2,typename P3,typename Op>
704 BOOST_FORCEINLINE
static_for_each(const P1 & p1,const P2 & p2,P3 & p3,Op op)705 Op static_for_each(const P1& p1,const P2& p2,P3& p3,Op op) { return detail::element_recursion<size<P1>::value>::static_for_each(p1,p2,p3,op); }
706 template <typename P1,typename P2,typename P3,typename Op>
707 BOOST_FORCEINLINE
static_for_each(const P1 & p1,const P2 & p2,const P3 & p3,Op op)708 Op static_for_each(const P1& p1,const P2& p2,const P3& p3,Op op) { return detail::element_recursion<size<P1>::value>::static_for_each(p1,p2,p3,op); }
709 ///\}
710 
711 } }  // namespace boost::gil
712 
713 #endif
714