Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2024-11-15 09:12:39

0001 //
0002 // Copyright 2005-2007 Adobe Systems Incorporated
0003 //
0004 // Distributed under the Boost Software License, Version 1.0
0005 // See accompanying file LICENSE_1_0.txt or copy at
0006 // http://www.boost.org/LICENSE_1_0.txt
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 /// Support for fast and simple color conversion.
0028 /// Accurate color conversion using color profiles can be supplied separately in a dedicated module.
0029 
0030 // Forward-declare
0031 template <typename P> struct channel_type;
0032 
0033 ////////////////////////////////////////////////////////////////////////////////////////
0034 ///
0035 ///                 COLOR SPACE CONVERSION
0036 ///
0037 ////////////////////////////////////////////////////////////////////////////////////////
0038 
0039 /// \ingroup ColorConvert
0040 /// \brief Color Convertion function object. To be specialized for every src/dst color space
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 /// \ingroup ColorConvert
0050 /// \brief When the color space is the same, color convertion performs channel depth conversion
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 /// red * .3 + green * .59 + blue * .11 + .5
0062 
0063 // The default implementation of to_luminance uses float0..1 as the intermediate channel type
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 // performance specialization for unsigned char
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 }   // namespace detail
0093 
0094 /// \ingroup ColorConvert
0095 /// \brief Gray to RGB
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 /// \ingroup ColorConvert
0110 /// \brief Gray to CMYK
0111 /// \todo FIXME: Where does this calculation come from? Shouldn't gray be inverted?
0112 ///              Currently, white becomes black and black becomes white.
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 /// \ingroup ColorConvert
0129 /// \brief RGB to Gray
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 /// \ingroup ColorConvert
0143 /// \brief RGB to CMYK (not the fastest code in the world)
0144 ///
0145 /// k = min(1 - r, 1 - g, 1 - b)
0146 /// c = (1 - r - k) / (1 - k)
0147 /// m = (1 - g - k) / (1 - k)
0148 /// y = (1 - b - k) / (1 - k)
0149 /// where `1` denotes max value of channel type of destination pixel.
0150 ///
0151 /// The conversion from RGB to CMYK is based on CMY->CMYK (Version 2)
0152 /// from the Principles of Digital Image Processing - Fundamental Techniques
0153 /// by Burger, Wilhelm, Burge, Mark J.
0154 /// and it is a gross approximation not precise enough for professional work.
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)); // c = 1 - r
0169         uint_t m = channel_invert(channel_convert<uint_t>(g)); // m = 1 - g
0170         uint_t y = channel_invert(channel_convert<uint_t>(b)); // y = 1 - b
0171         uint_t k = (std::min)(c,(std::min)(m,y));              // k = minimum(c, m, y)
0172 
0173         // Apply color correction, strengthening, reducing non-zero components by
0174         // s = 1 / (1 - k) for k < 1, where 1 denotes dst_t max, otherwise s = 1 (literal).
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             // Black only for k = 1 (max of dst_t)
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 /// \ingroup ColorConvert
0201 /// \brief CMYK to RGB (not the fastest code in the world)
0202 ///
0203 /// r = 1 - min(1, c*(1-k)+k)
0204 /// g = 1 - min(1, m*(1-k)+k)
0205 /// b = 1 - min(1, y*(1-k)+k)
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 /// \ingroup ColorConvert
0231 /// \brief CMYK to Gray
0232 ///
0233 /// gray = (1 - 0.212c - 0.715m - 0.0722y) * (1 - k)
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 } // namespace detail
0266 
0267 // Returns max_value if the pixel has no alpha channel. Otherwise returns the alpha.
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 /// \ingroup ColorConvert
0278 /// \brief Converting any pixel type to RGBA. Note: Supports homogeneous pixels only.
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 /// \ingroup ColorConvert
0294 ///  \brief Converting RGBA to any pixel type. Note: Supports homogeneous pixels only.
0295 ///
0296 /// Done by multiplying the alpha to get to RGB, then converting the RGB to the target pixel type
0297 /// Note: This may be slower if the compiler doesn't optimize out constructing/destructing a temporary RGB pixel.
0298 ///       Consider rewriting if performance is an issue
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 /// \ingroup ColorConvert
0313 /// \brief Unfortunately RGBA to RGBA must be explicitly provided - otherwise we get ambiguous specialization error.
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 /// @defgroup ColorConvert Color Space Converion
0323 /// \ingroup ColorSpaces
0324 /// \brief Support for conversion between pixels of different color spaces and channel depths
0325 
0326 /// \ingroup PixelAlgorithm ColorConvert
0327 /// \brief class for color-converting one pixel to another
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 /// \ingroup PixelAlgorithm
0338 /// \brief helper function for converting one pixel to another using GIL default color-converters
0339 ///     where ScrP models HomogeneousPixelConcept
0340 ///           DstP models HomogeneousPixelValueConcept
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 } }  // namespace boost::gil
0347 
0348 #endif