]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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 | ||
39 | namespace boost { namespace gil { | |
40 | ||
41 | // Forward-declare | |
42 | template <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 | |
52 | template <typename C1, typename C2> | |
53 | struct default_color_converter_impl {}; | |
54 | ||
55 | /// \ingroup ColorConvert | |
56 | /// \brief When the color space is the same, color convertion performs channel depth conversion | |
57 | template <typename C> | |
58 | struct 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 | ||
65 | namespace 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 | |
70 | template <typename RedChannel, typename GreenChannel, typename BlueChannel, typename GrayChannelValue> | |
71 | struct 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 | |
81 | template <typename GrayChannelValue> | |
82 | struct 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 | ||
89 | template <typename GrayChannel, typename RedChannel, typename GreenChannel, typename BlueChannel> | |
90 | typename 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 | |
99 | template <> | |
100 | struct 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 | |
114 | template <> | |
115 | struct 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 | |
131 | template <> | |
132 | struct 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) | |
150 | template <> | |
151 | struct 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) | |
179 | template <> | |
180 | struct 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) | |
207 | template <> | |
208 | struct 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 | ||
225 | namespace detail { | |
226 | template <typename Pixel> | |
227 | typename channel_type<Pixel>::type alpha_or_max_impl(const Pixel& p, mpl::true_) { | |
228 | return get_color(p,alpha_t()); | |
229 | } | |
230 | template <typename Pixel> | |
231 | typename 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. | |
237 | template <typename Pixel> | |
238 | typename 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. | |
245 | template <typename C1> | |
246 | struct 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 | |
265 | template <typename C2> | |
266 | struct 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. | |
280 | template <> | |
281 | struct 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 | |
294 | struct 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 | |
307 | template <typename SrcP, typename DstP> | |
308 | inline void color_convert(const SrcP& src, DstP& dst) { | |
309 | default_color_converter()(src,dst); | |
310 | } | |
311 | ||
312 | } } // namespace boost::gil | |
313 | ||
314 | #endif |