###  | #  |

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>
42 struct default_color_converter_impl
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>
52 struct default_color_converter_impl<C,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>
65 struct rgb_to_luminance_fn {
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(),
215 T1(channel_multiply(get_color(src,cyan_t()),channel_invert(get_color(src,black_t())))+get_color(src,black_t())))));
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(),
220 T1(channel_multiply(get_color(src,magenta_t()),channel_invert(get_color(src,black_t())))+get_color(src,black_t())))));
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(),
225 T1(channel_multiply(get_color(src,yellow_t()),channel_invert(get_color(src,black_t())))+get_color(src,black_t())))));
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>(
240 channel_multiply(
241 channel_invert(
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;
284 pixel<T2,rgb_layout_t> tmp;
285 default_color_converter_impl<C1,rgb_t>()(src,tmp);
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;
304 default_color_converter_impl<rgb_t,C2>()(
305 pixel<T1,rgb_layout_t>(channel_multiply(get_color(src,red_t()), get_color(src,alpha_t())),
306 channel_multiply(get_color(src,green_t()),get_color(src,alpha_t())),
307 channel_multiply(get_color(src,blue_t()), get_color(src,alpha_t())))
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
328 struct default_color_converter {
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;
333 default_color_converter_impl<SrcColorSpace,DstColorSpace>()(src,dst);
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
boost::gil::channel_invert
auto channel_invert(Channel x) -> typename channel_traits< Channel >::value_type
Default implementation. Provide overloads for performance.
Definition: channel_algorithm.hpp:582
boost::gil::float32_t
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
boost::gil::channel_multiply
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
boost::gil::get_color
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
boost::gil::color_convert
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
boost
defined(BOOST_NO_CXX17_HDR_MEMORY_RESOURCE)
Definition: algorithm.hpp:36
boost::gil::alpha_t
Alpha.
Definition: rgba.hpp:22
boost::gil::black_t
Black.
Definition: cmyk.hpp:31
boost::gil::blue_t
Blue.
Definition: rgb.hpp:30
boost::gil::channel_type
Definition: color_convert.hpp:31
boost::gil::cyan_t
Cyan.
Definition: cmyk.hpp:22
boost::gil::default_channel_converter
Same as channel_converter, except it takes the destination channel by reference, which allows us to m...
Definition: channel_algorithm.hpp:471
boost::gil::default_color_converter_impl
Color Convertion function object. To be specialized for every src/dst color space.
Definition: color_convert.hpp:43
boost::gil::default_color_converter
class for color-converting one pixel to another
Definition: color_convert.hpp:328
boost::gil::detail::rgb_to_luminance_fn
red * .3 + green * .59 + blue * .11 + .5
Definition: color_convert.hpp:65
boost::gil::gray_color_t
Gray.
Definition: gray.hpp:18
boost::gil::green_t
Green.
Definition: rgb.hpp:27
boost::gil::magenta_t
Magenta.
Definition: cmyk.hpp:25
boost::gil::pixel
Represents a pixel value (a container of channels). Models: HomogeneousColorBaseValueConcept,...
Definition: pixel.hpp:106
boost::gil::red_t
Red.
Definition: rgb.hpp:24
boost::gil::yellow_t
Yellow.
Definition: cmyk.hpp:28