Boost GIL


color_convert.hpp
1 //
2 // Copyright 2005-2007 Adobe Systems Incorporated
3 //
4 // Distributed under the Boost Software License, Version 1.0
5 // See accompanying file LICENSE_1_0.txt or copy at
6 // http://www.boost.org/LICENSE_1_0.txt
7 //
8 #ifndef BOOST_GIL_COLOR_CONVERT_HPP
9 #define BOOST_GIL_COLOR_CONVERT_HPP
10 
11 #include <boost/gil/channel_algorithm.hpp>
12 #include <boost/gil/cmyk.hpp>
13 #include <boost/gil/color_base_algorithm.hpp>
14 #include <boost/gil/gray.hpp>
15 #include <boost/gil/metafunctions.hpp>
16 #include <boost/gil/pixel.hpp>
17 #include <boost/gil/rgb.hpp>
18 #include <boost/gil/rgba.hpp>
19 #include <boost/gil/utilities.hpp>
20 
21 #include <algorithm>
22 #include <functional>
23 #include <type_traits>
24 
25 namespace boost { namespace gil {
26 
29 
30 // Forward-declare
31 template <typename P> struct channel_type;
32 
38 
41 template <typename C1, typename C2>
43 {
44  static_assert(
45  std::is_same<C1, C2>::value,
46  "default_color_converter_impl not specialized for given color spaces");
47 };
48 
51 template <typename C>
53  template <typename P1, typename P2>
54  void operator()(const P1& src, P2& dst) const {
55  static_for_each(src,dst,default_channel_converter());
56  }
57 };
58 
59 namespace detail {
60 
62 
63 // The default implementation of to_luminance uses float0..1 as the intermediate channel type
64 template <typename RedChannel, typename GreenChannel, typename BlueChannel, typename GrayChannelValue>
66  auto operator()(const RedChannel& red, const GreenChannel& green, const BlueChannel& blue) const -> GrayChannelValue
67  {
68  return channel_convert<GrayChannelValue>(float32_t(
69  channel_convert<float32_t>(red )*0.30f +
70  channel_convert<float32_t>(green)*0.59f +
71  channel_convert<float32_t>(blue )*0.11f) );
72  }
73 };
74 
75 // performance specialization for unsigned char
76 template <typename GrayChannelValue>
77 struct rgb_to_luminance_fn<uint8_t,uint8_t,uint8_t, GrayChannelValue> {
78  auto operator()(uint8_t red, uint8_t green, uint8_t blue) const -> GrayChannelValue
79  {
80  return channel_convert<GrayChannelValue>(uint8_t(
81  ((uint32_t(red )*4915 + uint32_t(green)*9667 + uint32_t(blue )*1802) + 8192) >> 14));
82  }
83 };
84 
85 template <typename GrayChannel, typename RedChannel, typename GreenChannel, typename BlueChannel>
86 auto rgb_to_luminance(const RedChannel& red, const GreenChannel& green, const BlueChannel& blue) -> typename channel_traits<GrayChannel>::value_type
87 {
88  return rgb_to_luminance_fn<RedChannel,GreenChannel,BlueChannel,
89  typename channel_traits<GrayChannel>::value_type>()(red,green,blue);
90 }
91 
92 } // namespace detail
93 
96 template <>
97 struct default_color_converter_impl<gray_t,rgb_t> {
98  template <typename P1, typename P2>
99  void operator()(const P1& src, P2& dst) const {
100  get_color(dst,red_t()) =
101  channel_convert<typename color_element_type<P2, red_t >::type>(get_color(src,gray_color_t()));
102  get_color(dst,green_t())=
103  channel_convert<typename color_element_type<P2, green_t>::type>(get_color(src,gray_color_t()));
104  get_color(dst,blue_t()) =
105  channel_convert<typename color_element_type<P2, blue_t >::type>(get_color(src,gray_color_t()));
106  }
107 };
108 
113 template <>
114 struct default_color_converter_impl<gray_t,cmyk_t> {
115  template <typename P1, typename P2>
116  void operator()(const P1& src, P2& dst) const {
117  get_color(dst,cyan_t())=
118  channel_traits<typename color_element_type<P2, cyan_t >::type>::min_value();
119  get_color(dst,magenta_t())=
120  channel_traits<typename color_element_type<P2, magenta_t>::type>::min_value();
121  get_color(dst,yellow_t())=
122  channel_traits<typename color_element_type<P2, yellow_t >::type>::min_value();
123  get_color(dst,black_t())=
124  channel_convert<typename color_element_type<P2, black_t >::type>(get_color(src,gray_color_t()));
125  }
126 };
127 
130 template <>
131 struct default_color_converter_impl<rgb_t,gray_t> {
132  template <typename P1, typename P2>
133  void operator()(const P1& src, P2& dst) const {
134  get_color(dst,gray_color_t()) =
135  detail::rgb_to_luminance<typename color_element_type<P2,gray_color_t>::type>(
136  get_color(src,red_t()), get_color(src,green_t()), get_color(src,blue_t())
137  );
138  }
139 };
140 
141 
156 template <>
157 struct default_color_converter_impl<rgb_t, cmyk_t>
158 {
159  template <typename SrcPixel, typename DstPixel>
160  void operator()(SrcPixel const& src, DstPixel& dst) const
161  {
162  using src_t = typename channel_type<SrcPixel>::type;
163  src_t const r = get_color(src, red_t());
164  src_t const g = get_color(src, green_t());
165  src_t const b = get_color(src, blue_t());
166 
167  using uint_t = typename channel_type<cmyk8_pixel_t>::type;
168  uint_t c = channel_invert(channel_convert<uint_t>(r)); // c = 1 - r
169  uint_t m = channel_invert(channel_convert<uint_t>(g)); // m = 1 - g
170  uint_t y = channel_invert(channel_convert<uint_t>(b)); // y = 1 - b
171  uint_t k = (std::min)(c,(std::min)(m,y)); // k = minimum(c, m, y)
172 
173  // Apply color correction, strengthening, reducing non-zero components by
174  // s = 1 / (1 - k) for k < 1, where 1 denotes dst_t max, otherwise s = 1 (literal).
175  uint_t const dst_max = channel_traits<uint_t>::max_value();
176  uint_t const s_div = static_cast<uint_t>(dst_max - k);
177  if (s_div != 0)
178  {
179  double const s = dst_max / static_cast<double>(s_div);
180  c = static_cast<uint_t>((c - k) * s);
181  m = static_cast<uint_t>((m - k) * s);
182  y = static_cast<uint_t>((y - k) * s);
183  }
184  else
185  {
186  // Black only for k = 1 (max of dst_t)
187  c = channel_traits<uint_t>::min_value();
188  m = channel_traits<uint_t>::min_value();
189  y = channel_traits<uint_t>::min_value();
190  }
191  using dst_t = typename channel_type<DstPixel>::type;
192  get_color(dst, cyan_t()) = channel_convert<dst_t>(c);
193  get_color(dst, magenta_t()) = channel_convert<dst_t>(m);
194  get_color(dst, yellow_t()) = channel_convert<dst_t>(y);
195  get_color(dst, black_t()) = channel_convert<dst_t>(k);
196  }
197 };
198 
199 
206 template <>
207 struct default_color_converter_impl<cmyk_t,rgb_t> {
208  template <typename P1, typename P2>
209  void operator()(const P1& src, P2& dst) const {
210  using T1 = typename channel_type<P1>::type;
211  get_color(dst,red_t()) =
212  channel_convert<typename color_element_type<P2,red_t>::type>(
213  channel_invert<T1>(
214  (std::min)(channel_traits<T1>::max_value(),
216  get_color(dst,green_t())=
217  channel_convert<typename color_element_type<P2,green_t>::type>(
218  channel_invert<T1>(
219  (std::min)(channel_traits<T1>::max_value(),
221  get_color(dst,blue_t()) =
222  channel_convert<typename color_element_type<P2,blue_t>::type>(
223  channel_invert<T1>(
224  (std::min)(channel_traits<T1>::max_value(),
226  }
227 };
228 
229 
234 template <>
235 struct default_color_converter_impl<cmyk_t,gray_t> {
236  template <typename P1, typename P2>
237  void operator()(const P1& src, P2& dst) const {
238  get_color(dst,gray_color_t())=
239  channel_convert<typename color_element_type<P2,gray_color_t>::type>(
242  detail::rgb_to_luminance<typename color_element_type<P1,black_t>::type>(
243  get_color(src,cyan_t()),
244  get_color(src,magenta_t()),
245  get_color(src,yellow_t())
246  )
247  ),
248  channel_invert(get_color(src,black_t()))));
249  }
250 };
251 
252 namespace detail {
253 
254 template <typename Pixel>
255 auto alpha_or_max_impl(Pixel const& p, std::true_type) -> typename channel_type<Pixel>::type
256 {
257  return get_color(p,alpha_t());
258 }
259 template <typename Pixel>
260 auto alpha_or_max_impl(Pixel const&, std::false_type) -> typename channel_type<Pixel>::type
261 {
262  return channel_traits<typename channel_type<Pixel>::type>::max_value();
263 }
264 
265 } // namespace detail
266 
267 // Returns max_value if the pixel has no alpha channel. Otherwise returns the alpha.
268 template <typename Pixel>
269 auto alpha_or_max(Pixel const& p) -> typename channel_type<Pixel>::type
270 {
271  return detail::alpha_or_max_impl(
272  p,
273  mp11::mp_contains<typename color_space_type<Pixel>::type, alpha_t>());
274 }
275 
276 
279 template <typename C1>
280 struct default_color_converter_impl<C1,rgba_t> {
281  template <typename P1, typename P2>
282  void operator()(const P1& src, P2& dst) const {
283  using T2 = typename channel_type<P2>::type;
286  get_color(dst,red_t()) =get_color(tmp,red_t());
287  get_color(dst,green_t())=get_color(tmp,green_t());
288  get_color(dst,blue_t()) =get_color(tmp,blue_t());
289  get_color(dst,alpha_t())=channel_convert<T2>(alpha_or_max(src));
290  }
291 };
292 
299 template <typename C2>
300 struct default_color_converter_impl<rgba_t,C2> {
301  template <typename P1, typename P2>
302  void operator()(const P1& src, P2& dst) const {
303  using T1 = typename channel_type<P1>::type;
308  ,dst);
309  }
310 };
311 
314 template <>
315 struct default_color_converter_impl<rgba_t,rgba_t> {
316  template <typename P1, typename P2>
317  void operator()(const P1& src, P2& dst) const {
318  static_for_each(src,dst,default_channel_converter());
319  }
320 };
321 
325 
329  template <typename SrcP, typename DstP>
330  void operator()(const SrcP& src,DstP& dst) const {
331  using SrcColorSpace = typename color_space_type<SrcP>::type;
332  using DstColorSpace = typename color_space_type<DstP>::type;
334  }
335 };
336 
341 template <typename SrcP, typename DstP>
342 inline void color_convert(const SrcP& src, DstP& dst) {
343  default_color_converter()(src,dst);
344 }
345 
346 } } // namespace boost::gil
347 
348 #endif
auto channel_invert(Channel x) -> typename channel_traits< Channel >::value_type
Default implementation. Provide overloads for performance.
Definition: channel_algorithm.hpp:582
scoped_channel_value< float, float_point_zero< float >, float_point_one< float > > float32_t
32-bit floating point channel type with range [0.0f ... 1.0f]. Models ChannelValueConcept
Definition: typedefs.hpp:153
auto channel_multiply(Channel a, Channel b) -> typename channel_traits< Channel >::value_type
A function multiplying two channels. result = a * b / max_value.
Definition: channel_algorithm.hpp:561
auto get_color(ColorBase &cb, Color=Color()) -> typename color_element_reference_type< ColorBase, Color >::type
Mutable accessor to the element associated with a given color name.
Definition: color_base_algorithm.hpp:190
void color_convert(const SrcP &src, DstP &dst)
helper function for converting one pixel to another using GIL default color-converters where ScrP mod...
Definition: color_convert.hpp:342
defined(BOOST_NO_CXX17_HDR_MEMORY_RESOURCE)
Definition: algorithm.hpp:36
Alpha.
Definition: rgba.hpp:22
Black.
Definition: cmyk.hpp:31
Blue.
Definition: rgb.hpp:30
Definition: color_convert.hpp:31
Cyan.
Definition: cmyk.hpp:22
Same as channel_converter, except it takes the destination channel by reference, which allows us to m...
Definition: channel_algorithm.hpp:471
Color Conversion function object. To be specialized for every src/dst color space.
Definition: color_convert.hpp:43
class for color-converting one pixel to another
Definition: color_convert.hpp:328
red * .3 + green * .59 + blue * .11 + .5
Definition: color_convert.hpp:65
Gray.
Definition: gray.hpp:18
Green.
Definition: rgb.hpp:27
Magenta.
Definition: cmyk.hpp:25
Represents a pixel value (a container of channels). Models: HomogeneousColorBaseValueConcept,...
Definition: pixel.hpp:106
Red.
Definition: rgb.hpp:24
Yellow.
Definition: cmyk.hpp:28