1/*
2 Copyright 2005-2007 Adobe Systems Incorporated
3
4 Use, modification and distribution are subject to the Boost Software License,
5 Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
6 http://www.boost.org/LICENSE_1_0.txt).
7
8 See http://opensource.adobe.com/gil for most recent version including documentation.
9*/
10/*************************************************************************************************/
11
12#ifndef GIL_COLOR_CONVERT_HPP
13#define GIL_COLOR_CONVERT_HPP
14
15////////////////////////////////////////////////////////////////////////////////////////
16/// \file
17/// \brief GIL default color space conversions
18/// \author Lubomir Bourdev and Hailin Jin \n
19/// Adobe Systems Incorporated
20/// \date 2005-2007 \n Last updated on January 30, 2007
21///
22/// Support for fast and simple color conversion. Accurate color conversion using color
23/// profiles can be supplied separately in a dedicated module
24///
25////////////////////////////////////////////////////////////////////////////////////////
26
27#include <functional>
28#include "gil_config.hpp"
29#include "channel_algorithm.hpp"
30#include "pixel.hpp"
31#include "gray.hpp"
32#include "rgb.hpp"
33#include "rgba.hpp"
34#include "cmyk.hpp"
35#include "metafunctions.hpp"
36#include "utilities.hpp"
37#include "color_base_algorithm.hpp"
38
39namespace boost { namespace gil {
40
41// Forward-declare
42template <typename P> struct channel_type;
43
44////////////////////////////////////////////////////////////////////////////////////////
45///
46/// COLOR SPACE CONVERSION
47///
48////////////////////////////////////////////////////////////////////////////////////////
49
50/// \ingroup ColorConvert
51/// \brief Color Convertion function object. To be specialized for every src/dst color space
52template <typename C1, typename C2>
53struct default_color_converter_impl {};
54
55/// \ingroup ColorConvert
56/// \brief When the color space is the same, color convertion performs channel depth conversion
57template <typename C>
58struct default_color_converter_impl<C,C> {
59 template <typename P1, typename P2>
60 void operator()(const P1& src, P2& dst) const {
61 static_for_each(src,dst,default_channel_converter());
62 }
63};
64
65namespace detail {
66
67/// red * .3 + green * .59 + blue * .11 + .5
68
69// The default implementation of to_luminance uses float0..1 as the intermediate channel type
70template <typename RedChannel, typename GreenChannel, typename BlueChannel, typename GrayChannelValue>
71struct rgb_to_luminance_fn {
72 GrayChannelValue operator()(const RedChannel& red, const GreenChannel& green, const BlueChannel& blue) const {
73 return channel_convert<GrayChannelValue>( bits32f(
74 channel_convert<bits32f>(red )*0.30f +
75 channel_convert<bits32f>(green)*0.59f +
76 channel_convert<bits32f>(blue )*0.11f) );
77 }
78};
79
80// performance specialization for unsigned char
81template <typename GrayChannelValue>
82struct rgb_to_luminance_fn<uint8_t,uint8_t,uint8_t, GrayChannelValue> {
83 GrayChannelValue operator()(uint8_t red, uint8_t green, uint8_t blue) const {
84 return channel_convert<GrayChannelValue>(uint8_t(
85 ((uint32_t(red )*4915 + uint32_t(green)*9667 + uint32_t(blue )*1802) + 8192) >> 14));
86 }
87};
88
89template <typename GrayChannel, typename RedChannel, typename GreenChannel, typename BlueChannel>
90typename channel_traits<GrayChannel>::value_type rgb_to_luminance(const RedChannel& red, const GreenChannel& green, const BlueChannel& blue) {
91 return rgb_to_luminance_fn<RedChannel,GreenChannel,BlueChannel,
92 typename channel_traits<GrayChannel>::value_type>()(red,green,blue);
93}
94
95} // namespace detail
96
97/// \ingroup ColorConvert
98/// \brief Gray to RGB
99template <>
100struct default_color_converter_impl<gray_t,rgb_t> {
101 template <typename P1, typename P2>
102 void operator()(const P1& src, P2& dst) const {
103 get_color(dst,red_t()) =
104 channel_convert<typename color_element_type<P2, red_t >::type>(get_color(src,gray_color_t()));
105 get_color(dst,green_t())=
106 channel_convert<typename color_element_type<P2, green_t>::type>(get_color(src,gray_color_t()));
107 get_color(dst,blue_t()) =
108 channel_convert<typename color_element_type<P2, blue_t >::type>(get_color(src,gray_color_t()));
109 }
110};
111
112/// \ingroup ColorConvert
113/// \brief Gray to CMYK
114template <>
115struct default_color_converter_impl<gray_t,cmyk_t> {
116 template <typename P1, typename P2>
117 void operator()(const P1& src, P2& dst) const {
118 get_color(dst,cyan_t())=
119 channel_traits<typename color_element_type<P2, cyan_t >::type>::min_value();
120 get_color(dst,magenta_t())=
121 channel_traits<typename color_element_type<P2, magenta_t>::type>::min_value();
122 get_color(dst,yellow_t())=
123 channel_traits<typename color_element_type<P2, yellow_t >::type>::min_value();
124 get_color(dst,black_t())=
125 channel_convert<typename color_element_type<P2, black_t >::type>(get_color(src,gray_color_t()));
126 }
127};
128
129/// \ingroup ColorConvert
130/// \brief RGB to Gray
131template <>
132struct default_color_converter_impl<rgb_t,gray_t> {
133 template <typename P1, typename P2>
134 void operator()(const P1& src, P2& dst) const {
135 get_color(dst,gray_color_t()) =
136 detail::rgb_to_luminance<typename color_element_type<P2,gray_color_t>::type>(
137 get_color(src,red_t()), get_color(src,green_t()), get_color(src,blue_t())
138 );
139 }
140};
141
142
143/// \ingroup ColorConvert
144/// \brief RGB to CMYK (not the fastest code in the world)
145///
146/// k = min(1 - r, 1 - g, 1 - b)
147/// c = (1 - r - k) / (1 - k)
148/// m = (1 - g - k) / (1 - k)
149/// y = (1 - b - k) / (1 - k)
150template <>
151struct default_color_converter_impl<rgb_t,cmyk_t> {
152 template <typename P1, typename P2>
153 void operator()(const P1& src, P2& dst) const {
154 typedef typename channel_type<P2>::type T2;
155 get_color(dst,cyan_t()) = channel_invert(channel_convert<T2>(get_color(src,red_t()))); // c = 1 - r
156 get_color(dst,magenta_t()) = channel_invert(channel_convert<T2>(get_color(src,green_t()))); // m = 1 - g
157 get_color(dst,yellow_t()) = channel_invert(channel_convert<T2>(get_color(src,blue_t()))); // y = 1 - b
158 get_color(dst,black_t()) = (std::min)(get_color(dst,cyan_t()),
159 (std::min)(get_color(dst,magenta_t()),
160 get_color(dst,yellow_t()))); // k = minimum(c, m, y)
161 T2 x = channel_traits<T2>::max_value()-get_color(dst,black_t()); // x = 1 - k
162 if (x>0.0001f) {
163 float x1 = channel_traits<T2>::max_value()/float(x);
164 get_color(dst,cyan_t()) = (T2)((get_color(dst,cyan_t()) - get_color(dst,black_t()))*x1); // c = (c - k) / x
165 get_color(dst,magenta_t()) = (T2)((get_color(dst,magenta_t()) - get_color(dst,black_t()))*x1); // m = (m - k) / x
166 get_color(dst,yellow_t()) = (T2)((get_color(dst,yellow_t()) - get_color(dst,black_t()))*x1); // y = (y - k) / x
167 } else {
168 get_color(dst,cyan_t())=get_color(dst,magenta_t())=get_color(dst,yellow_t())=0;
169 }
170 }
171};
172
173/// \ingroup ColorConvert
174/// \brief CMYK to RGB (not the fastest code in the world)
175///
176/// r = 1 - min(1, c*(1-k)+k)
177/// g = 1 - min(1, m*(1-k)+k)
178/// b = 1 - min(1, y*(1-k)+k)
179template <>
180struct default_color_converter_impl<cmyk_t,rgb_t> {
181 template <typename P1, typename P2>
182 void operator()(const P1& src, P2& dst) const {
183 typedef typename channel_type<P1>::type T1;
184 get_color(dst,red_t()) =
185 channel_convert<typename color_element_type<P2,red_t>::type>(
186 channel_invert<T1>(
187 (std::min)(channel_traits<T1>::max_value(),
188 T1(get_color(src,cyan_t())*channel_invert(get_color(src,black_t()))+get_color(src,black_t())))));
189 get_color(dst,green_t())=
190 channel_convert<typename color_element_type<P2,green_t>::type>(
191 channel_invert<T1>(
192 (std::min)(channel_traits<T1>::max_value(),
193 T1(get_color(src,magenta_t())*channel_invert(get_color(src,black_t()))+get_color(src,black_t())))));
194 get_color(dst,blue_t()) =
195 channel_convert<typename color_element_type<P2,blue_t>::type>(
196 channel_invert<T1>(
197 (std::min)(channel_traits<T1>::max_value(),
198 T1(get_color(src,yellow_t())*channel_invert(get_color(src,black_t()))+get_color(src,black_t())))));
199 }
200};
201
202
203/// \ingroup ColorConvert
204/// \brief CMYK to Gray
205///
206/// gray = (1 - 0.212c - 0.715m - 0.0722y) * (1 - k)
207template <>
208struct default_color_converter_impl<cmyk_t,gray_t> {
209 template <typename P1, typename P2>
210 void operator()(const P1& src, P2& dst) const {
211 get_color(dst,gray_color_t())=
212 channel_convert<typename color_element_type<P2,gray_t>::type>(
213 channel_multiply(
214 channel_invert(
215 detail::rgb_to_luminance<typename color_element_type<P1,black_t>::type>(
216 get_color(src,cyan_t()),
217 get_color(src,magenta_t()),
218 get_color(src,yellow_t())
219 )
220 ),
221 channel_invert(get_color(src,black_t()))));
222 }
223};
224
225namespace detail {
226template <typename Pixel>
227typename channel_type<Pixel>::type alpha_or_max_impl(const Pixel& p, mpl::true_) {
228 return get_color(p,alpha_t());
229}
230template <typename Pixel>
231typename channel_type<Pixel>::type alpha_or_max_impl(const Pixel& , mpl::false_) {
232 return channel_traits<typename channel_type<Pixel>::type>::max_value();
233}
234} // namespace detail
235
236// Returns max_value if the pixel has no alpha channel. Otherwise returns the alpha.
237template <typename Pixel>
238typename channel_type<Pixel>::type alpha_or_max(const Pixel& p) {
239 return detail::alpha_or_max_impl(p, mpl::contains<typename color_space_type<Pixel>::type,alpha_t>());
240}
241
242
243/// \ingroup ColorConvert
244/// \brief Converting any pixel type to RGBA. Note: Supports homogeneous pixels only.
245template <typename C1>
246struct default_color_converter_impl<C1,rgba_t> {
247 template <typename P1, typename P2>
248 void operator()(const P1& src, P2& dst) const {
249 typedef typename channel_type<P2>::type T2;
250 pixel<T2,rgb_layout_t> tmp;
251 default_color_converter_impl<C1,rgb_t>()(src,tmp);
252 get_color(dst,red_t()) =get_color(tmp,red_t());
253 get_color(dst,green_t())=get_color(tmp,green_t());
254 get_color(dst,blue_t()) =get_color(tmp,blue_t());
255 get_color(dst,alpha_t())=channel_convert<T2>(alpha_or_max(src));
256 }
257};
258
259/// \ingroup ColorConvert
260/// \brief Converting RGBA to any pixel type. Note: Supports homogeneous pixels only.
261///
262/// Done by multiplying the alpha to get to RGB, then converting the RGB to the target pixel type
263/// Note: This may be slower if the compiler doesn't optimize out constructing/destructing a temporary RGB pixel.
264/// Consider rewriting if performance is an issue
265template <typename C2>
266struct default_color_converter_impl<rgba_t,C2> {
267 template <typename P1, typename P2>
268 void operator()(const P1& src, P2& dst) const {
269 typedef typename channel_type<P1>::type T1;
270 default_color_converter_impl<rgb_t,C2>()(
271 pixel<T1,rgb_layout_t>(channel_multiply(get_color(src,red_t()), get_color(src,alpha_t())),
272 channel_multiply(get_color(src,green_t()),get_color(src,alpha_t())),
273 channel_multiply(get_color(src,blue_t()), get_color(src,alpha_t())))
274 ,dst);
275 }
276};
277
278/// \ingroup ColorConvert
279/// \brief Unfortunately RGBA to RGBA must be explicitly provided - otherwise we get ambiguous specialization error.
280template <>
281struct default_color_converter_impl<rgba_t,rgba_t> {
282 template <typename P1, typename P2>
283 void operator()(const P1& src, P2& dst) const {
284 static_for_each(src,dst,default_channel_converter());
285 }
286};
287
288/// @defgroup ColorConvert Color Space Converion
289/// \ingroup ColorSpaces
290/// \brief Support for conversion between pixels of different color spaces and channel depths
291
292/// \ingroup PixelAlgorithm ColorConvert
293/// \brief class for color-converting one pixel to another
294struct default_color_converter {
295 template <typename SrcP, typename DstP>
296 void operator()(const SrcP& src,DstP& dst) const {
297 typedef typename color_space_type<SrcP>::type SrcColorSpace;
298 typedef typename color_space_type<DstP>::type DstColorSpace;
299 default_color_converter_impl<SrcColorSpace,DstColorSpace>()(src,dst);
300 }
301};
302
303/// \ingroup PixelAlgorithm
304/// \brief helper function for converting one pixel to another using GIL default color-converters
305/// where ScrP models HomogeneousPixelConcept
306/// DstP models HomogeneousPixelValueConcept
307template <typename SrcP, typename DstP>
308inline void color_convert(const SrcP& src, DstP& dst) {
309 default_color_converter()(src,dst);
310}
311
312} } // namespace boost::gil
313
314#endif
315

source code of boost/boost/gil/color_convert.hpp