]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/gil/color_convert.hpp
update sources to v12.2.3
[ceph.git] / ceph / src / boost / boost / gil / color_convert.hpp
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