File indexing completed on 2024-11-15 09:12:39
0001
0002
0003
0004
0005
0006
0007
0008 #ifndef BOOST_GIL_COLOR_CONVERT_HPP
0009 #define BOOST_GIL_COLOR_CONVERT_HPP
0010
0011 #include <boost/gil/channel_algorithm.hpp>
0012 #include <boost/gil/cmyk.hpp>
0013 #include <boost/gil/color_base_algorithm.hpp>
0014 #include <boost/gil/gray.hpp>
0015 #include <boost/gil/metafunctions.hpp>
0016 #include <boost/gil/pixel.hpp>
0017 #include <boost/gil/rgb.hpp>
0018 #include <boost/gil/rgba.hpp>
0019 #include <boost/gil/utilities.hpp>
0020
0021 #include <algorithm>
0022 #include <functional>
0023 #include <type_traits>
0024
0025 namespace boost { namespace gil {
0026
0027
0028
0029
0030
0031 template <typename P> struct channel_type;
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041 template <typename C1, typename C2>
0042 struct default_color_converter_impl
0043 {
0044 static_assert(
0045 std::is_same<C1, C2>::value,
0046 "default_color_converter_impl not specialized for given color spaces");
0047 };
0048
0049
0050
0051 template <typename C>
0052 struct default_color_converter_impl<C,C> {
0053 template <typename P1, typename P2>
0054 void operator()(const P1& src, P2& dst) const {
0055 static_for_each(src,dst,default_channel_converter());
0056 }
0057 };
0058
0059 namespace detail {
0060
0061
0062
0063
0064 template <typename RedChannel, typename GreenChannel, typename BlueChannel, typename GrayChannelValue>
0065 struct rgb_to_luminance_fn {
0066 auto operator()(const RedChannel& red, const GreenChannel& green, const BlueChannel& blue) const -> GrayChannelValue
0067 {
0068 return channel_convert<GrayChannelValue>(float32_t(
0069 channel_convert<float32_t>(red )*0.30f +
0070 channel_convert<float32_t>(green)*0.59f +
0071 channel_convert<float32_t>(blue )*0.11f) );
0072 }
0073 };
0074
0075
0076 template <typename GrayChannelValue>
0077 struct rgb_to_luminance_fn<uint8_t,uint8_t,uint8_t, GrayChannelValue> {
0078 auto operator()(uint8_t red, uint8_t green, uint8_t blue) const -> GrayChannelValue
0079 {
0080 return channel_convert<GrayChannelValue>(uint8_t(
0081 ((uint32_t(red )*4915 + uint32_t(green)*9667 + uint32_t(blue )*1802) + 8192) >> 14));
0082 }
0083 };
0084
0085 template <typename GrayChannel, typename RedChannel, typename GreenChannel, typename BlueChannel>
0086 auto rgb_to_luminance(const RedChannel& red, const GreenChannel& green, const BlueChannel& blue) -> typename channel_traits<GrayChannel>::value_type
0087 {
0088 return rgb_to_luminance_fn<RedChannel,GreenChannel,BlueChannel,
0089 typename channel_traits<GrayChannel>::value_type>()(red,green,blue);
0090 }
0091
0092 }
0093
0094
0095
0096 template <>
0097 struct default_color_converter_impl<gray_t,rgb_t> {
0098 template <typename P1, typename P2>
0099 void operator()(const P1& src, P2& dst) const {
0100 get_color(dst,red_t()) =
0101 channel_convert<typename color_element_type<P2, red_t >::type>(get_color(src,gray_color_t()));
0102 get_color(dst,green_t())=
0103 channel_convert<typename color_element_type<P2, green_t>::type>(get_color(src,gray_color_t()));
0104 get_color(dst,blue_t()) =
0105 channel_convert<typename color_element_type<P2, blue_t >::type>(get_color(src,gray_color_t()));
0106 }
0107 };
0108
0109
0110
0111
0112
0113 template <>
0114 struct default_color_converter_impl<gray_t,cmyk_t> {
0115 template <typename P1, typename P2>
0116 void operator()(const P1& src, P2& dst) const {
0117 get_color(dst,cyan_t())=
0118 channel_traits<typename color_element_type<P2, cyan_t >::type>::min_value();
0119 get_color(dst,magenta_t())=
0120 channel_traits<typename color_element_type<P2, magenta_t>::type>::min_value();
0121 get_color(dst,yellow_t())=
0122 channel_traits<typename color_element_type<P2, yellow_t >::type>::min_value();
0123 get_color(dst,black_t())=
0124 channel_convert<typename color_element_type<P2, black_t >::type>(get_color(src,gray_color_t()));
0125 }
0126 };
0127
0128
0129
0130 template <>
0131 struct default_color_converter_impl<rgb_t,gray_t> {
0132 template <typename P1, typename P2>
0133 void operator()(const P1& src, P2& dst) const {
0134 get_color(dst,gray_color_t()) =
0135 detail::rgb_to_luminance<typename color_element_type<P2,gray_color_t>::type>(
0136 get_color(src,red_t()), get_color(src,green_t()), get_color(src,blue_t())
0137 );
0138 }
0139 };
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149
0150
0151
0152
0153
0154
0155
0156 template <>
0157 struct default_color_converter_impl<rgb_t, cmyk_t>
0158 {
0159 template <typename SrcPixel, typename DstPixel>
0160 void operator()(SrcPixel const& src, DstPixel& dst) const
0161 {
0162 using src_t = typename channel_type<SrcPixel>::type;
0163 src_t const r = get_color(src, red_t());
0164 src_t const g = get_color(src, green_t());
0165 src_t const b = get_color(src, blue_t());
0166
0167 using uint_t = typename channel_type<cmyk8_pixel_t>::type;
0168 uint_t c = channel_invert(channel_convert<uint_t>(r));
0169 uint_t m = channel_invert(channel_convert<uint_t>(g));
0170 uint_t y = channel_invert(channel_convert<uint_t>(b));
0171 uint_t k = (std::min)(c,(std::min)(m,y));
0172
0173
0174
0175 uint_t const dst_max = channel_traits<uint_t>::max_value();
0176 uint_t const s_div = static_cast<uint_t>(dst_max - k);
0177 if (s_div != 0)
0178 {
0179 double const s = dst_max / static_cast<double>(s_div);
0180 c = static_cast<uint_t>((c - k) * s);
0181 m = static_cast<uint_t>((m - k) * s);
0182 y = static_cast<uint_t>((y - k) * s);
0183 }
0184 else
0185 {
0186
0187 c = channel_traits<uint_t>::min_value();
0188 m = channel_traits<uint_t>::min_value();
0189 y = channel_traits<uint_t>::min_value();
0190 }
0191 using dst_t = typename channel_type<DstPixel>::type;
0192 get_color(dst, cyan_t()) = channel_convert<dst_t>(c);
0193 get_color(dst, magenta_t()) = channel_convert<dst_t>(m);
0194 get_color(dst, yellow_t()) = channel_convert<dst_t>(y);
0195 get_color(dst, black_t()) = channel_convert<dst_t>(k);
0196 }
0197 };
0198
0199
0200
0201
0202
0203
0204
0205
0206 template <>
0207 struct default_color_converter_impl<cmyk_t,rgb_t> {
0208 template <typename P1, typename P2>
0209 void operator()(const P1& src, P2& dst) const {
0210 using T1 = typename channel_type<P1>::type;
0211 get_color(dst,red_t()) =
0212 channel_convert<typename color_element_type<P2,red_t>::type>(
0213 channel_invert<T1>(
0214 (std::min)(channel_traits<T1>::max_value(),
0215 T1(channel_multiply(get_color(src,cyan_t()),channel_invert(get_color(src,black_t())))+get_color(src,black_t())))));
0216 get_color(dst,green_t())=
0217 channel_convert<typename color_element_type<P2,green_t>::type>(
0218 channel_invert<T1>(
0219 (std::min)(channel_traits<T1>::max_value(),
0220 T1(channel_multiply(get_color(src,magenta_t()),channel_invert(get_color(src,black_t())))+get_color(src,black_t())))));
0221 get_color(dst,blue_t()) =
0222 channel_convert<typename color_element_type<P2,blue_t>::type>(
0223 channel_invert<T1>(
0224 (std::min)(channel_traits<T1>::max_value(),
0225 T1(channel_multiply(get_color(src,yellow_t()),channel_invert(get_color(src,black_t())))+get_color(src,black_t())))));
0226 }
0227 };
0228
0229
0230
0231
0232
0233
0234 template <>
0235 struct default_color_converter_impl<cmyk_t,gray_t> {
0236 template <typename P1, typename P2>
0237 void operator()(const P1& src, P2& dst) const {
0238 get_color(dst,gray_color_t())=
0239 channel_convert<typename color_element_type<P2,gray_color_t>::type>(
0240 channel_multiply(
0241 channel_invert(
0242 detail::rgb_to_luminance<typename color_element_type<P1,black_t>::type>(
0243 get_color(src,cyan_t()),
0244 get_color(src,magenta_t()),
0245 get_color(src,yellow_t())
0246 )
0247 ),
0248 channel_invert(get_color(src,black_t()))));
0249 }
0250 };
0251
0252 namespace detail {
0253
0254 template <typename Pixel>
0255 auto alpha_or_max_impl(Pixel const& p, std::true_type) -> typename channel_type<Pixel>::type
0256 {
0257 return get_color(p,alpha_t());
0258 }
0259 template <typename Pixel>
0260 auto alpha_or_max_impl(Pixel const&, std::false_type) -> typename channel_type<Pixel>::type
0261 {
0262 return channel_traits<typename channel_type<Pixel>::type>::max_value();
0263 }
0264
0265 }
0266
0267
0268 template <typename Pixel>
0269 auto alpha_or_max(Pixel const& p) -> typename channel_type<Pixel>::type
0270 {
0271 return detail::alpha_or_max_impl(
0272 p,
0273 mp11::mp_contains<typename color_space_type<Pixel>::type, alpha_t>());
0274 }
0275
0276
0277
0278
0279 template <typename C1>
0280 struct default_color_converter_impl<C1,rgba_t> {
0281 template <typename P1, typename P2>
0282 void operator()(const P1& src, P2& dst) const {
0283 using T2 = typename channel_type<P2>::type;
0284 pixel<T2,rgb_layout_t> tmp;
0285 default_color_converter_impl<C1,rgb_t>()(src,tmp);
0286 get_color(dst,red_t()) =get_color(tmp,red_t());
0287 get_color(dst,green_t())=get_color(tmp,green_t());
0288 get_color(dst,blue_t()) =get_color(tmp,blue_t());
0289 get_color(dst,alpha_t())=channel_convert<T2>(alpha_or_max(src));
0290 }
0291 };
0292
0293
0294
0295
0296
0297
0298
0299 template <typename C2>
0300 struct default_color_converter_impl<rgba_t,C2> {
0301 template <typename P1, typename P2>
0302 void operator()(const P1& src, P2& dst) const {
0303 using T1 = typename channel_type<P1>::type;
0304 default_color_converter_impl<rgb_t,C2>()(
0305 pixel<T1,rgb_layout_t>(channel_multiply(get_color(src,red_t()), get_color(src,alpha_t())),
0306 channel_multiply(get_color(src,green_t()),get_color(src,alpha_t())),
0307 channel_multiply(get_color(src,blue_t()), get_color(src,alpha_t())))
0308 ,dst);
0309 }
0310 };
0311
0312
0313
0314 template <>
0315 struct default_color_converter_impl<rgba_t,rgba_t> {
0316 template <typename P1, typename P2>
0317 void operator()(const P1& src, P2& dst) const {
0318 static_for_each(src,dst,default_channel_converter());
0319 }
0320 };
0321
0322
0323
0324
0325
0326
0327
0328 struct default_color_converter {
0329 template <typename SrcP, typename DstP>
0330 void operator()(const SrcP& src,DstP& dst) const {
0331 using SrcColorSpace = typename color_space_type<SrcP>::type;
0332 using DstColorSpace = typename color_space_type<DstP>::type;
0333 default_color_converter_impl<SrcColorSpace,DstColorSpace>()(src,dst);
0334 }
0335 };
0336
0337
0338
0339
0340
0341 template <typename SrcP, typename DstP>
0342 inline void color_convert(const SrcP& src, DstP& dst) {
0343 default_color_converter()(src,dst);
0344 }
0345
0346 } }
0347
0348 #endif