TuttleOFX  1
color_convert.hpp
Go to the documentation of this file.
00001 // Hack the standard gil file
00002 
00003 /*
00004     Copyright 2005-2007 Adobe Systems Incorporated
00005 
00006     Use, modification and distribution are subject to the Boost Software License,
00007     Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
00008     http://www.boost.org/LICENSE_1_0.txt).
00009 
00010     See http://opensource.adobe.com/gil for most recent version including documentation.
00011 */
00012 /*************************************************************************************************/
00013 
00014 #ifndef GIL_COLOR_CONVERT_HPP
00015 #define GIL_COLOR_CONVERT_HPP
00016 
00017 ////////////////////////////////////////////////////////////////////////////////////////
00018 /// \file
00019 /// \brief GIL default color space conversions
00020 /// \author Lubomir Bourdev and Hailin Jin \n
00021 ///         Adobe Systems Incorporated
00022 /// \date   2005-2007 \n Last updated on January 30, 2007
00023 ///
00024 /// Support for fast and simple color conversion. Accurate color conversion using color
00025 /// profiles can be supplied separately in a dedicated module
00026 ///
00027 ////////////////////////////////////////////////////////////////////////////////////////
00028 
00029 #include <functional>
00030 #include <boost/gil/gil_config.hpp>
00031 #include <boost/gil/channel_algorithm.hpp>
00032 #include <boost/gil/pixel.hpp>
00033 #include <boost/gil/gray.hpp>
00034 #include <boost/gil/rgb.hpp>
00035 #include <boost/gil/rgba.hpp>
00036 #include <boost/gil/cmyk.hpp>
00037 #include <boost/gil/metafunctions.hpp>
00038 #include <boost/gil/utilities.hpp>
00039 #include <boost/gil/color_base_algorithm.hpp>
00040 
00041 namespace boost { namespace gil {
00042 
00043 // Forward-declare
00044 template <typename P> struct channel_type;
00045 
00046 ////////////////////////////////////////////////////////////////////////////////////////
00047 ///
00048 ///                 COLOR SPACE CONVERSION
00049 ///
00050 ////////////////////////////////////////////////////////////////////////////////////////
00051 
00052 /// \ingroup ColorConvert
00053 /// \brief Color Convertion function object. To be specialized for every src/dst color space
00054 template <typename C1, typename C2>
00055 struct default_color_converter_impl {};
00056 
00057 /// \ingroup ColorConvert
00058 /// \brief When the color space is the same, color convertion performs channel depth conversion
00059 template <typename C>
00060 struct default_color_converter_impl<C,C> {
00061     template <typename P1, typename P2>
00062     void operator()(const P1& src, P2& dst) const {
00063         static_for_each(src,dst,default_channel_converter());
00064     }
00065 };
00066 
00067 namespace detail {
00068 
00069 /// red * .3 + green * .59 + blue * .11 + .5
00070 
00071 // The default implementation of to_luminance uses float0..1 as the intermediate channel type
00072 template <typename RedChannel, typename GreenChannel, typename BlueChannel, typename GrayChannelValue>
00073 struct rgb_to_luminance_fn {
00074     GrayChannelValue operator()(const RedChannel& red, const GreenChannel& green, const BlueChannel& blue) const {
00075         return channel_convert<GrayChannelValue>( bits32f(
00076             channel_convert<bits32f>(red  )*0.30f +
00077             channel_convert<bits32f>(green)*0.59f +
00078             channel_convert<bits32f>(blue )*0.11f) );
00079     }
00080 };
00081 
00082 // performance specialization for unsigned char
00083 template <typename GrayChannelValue>
00084 struct rgb_to_luminance_fn<uint8_t,uint8_t,uint8_t, GrayChannelValue> {
00085     GrayChannelValue operator()(uint8_t red, uint8_t green, uint8_t blue) const {
00086         return channel_convert<GrayChannelValue>(uint8_t(
00087             ((uint32_t(red  )*4915 + uint32_t(green)*9667 + uint32_t(blue )*1802) + 8192) >> 14));
00088     }
00089 };
00090 
00091 template <typename GrayChannel, typename RedChannel, typename GreenChannel, typename BlueChannel>
00092 typename channel_traits<GrayChannel>::value_type rgb_to_luminance(const RedChannel& red, const GreenChannel& green, const BlueChannel& blue) {
00093     return rgb_to_luminance_fn<RedChannel,GreenChannel,BlueChannel,
00094                                typename channel_traits<GrayChannel>::value_type>()(red,green,blue);
00095 }
00096 
00097 }   // namespace detail
00098 
00099 /// \ingroup ColorConvert
00100 /// \brief Gray to RGB
00101 template <>
00102 struct default_color_converter_impl<gray_t,rgb_t> {
00103     template <typename P1, typename P2>
00104     void operator()(const P1& src, P2& dst) const {
00105         get_color(dst,red_t())  =
00106             channel_convert<typename color_element_type<P2, red_t  >::type>(get_color(src,gray_color_t()));
00107         get_color(dst,green_t())=
00108             channel_convert<typename color_element_type<P2, green_t>::type>(get_color(src,gray_color_t()));
00109         get_color(dst,blue_t()) =
00110             channel_convert<typename color_element_type<P2, blue_t >::type>(get_color(src,gray_color_t()));
00111     }
00112 };
00113 
00114 /// \ingroup ColorConvert
00115 /// \brief Gray to CMYK
00116 template <>
00117 struct default_color_converter_impl<gray_t,cmyk_t> {
00118     template <typename P1, typename P2>
00119     void operator()(const P1& src, P2& dst) const {
00120         get_color(dst,cyan_t())=
00121             channel_traits<typename color_element_type<P2, cyan_t   >::type>::min_value();
00122         get_color(dst,magenta_t())=
00123             channel_traits<typename color_element_type<P2, magenta_t>::type>::min_value();
00124         get_color(dst,yellow_t())=
00125             channel_traits<typename color_element_type<P2, yellow_t >::type>::min_value();
00126         get_color(dst,black_t())=
00127             channel_convert<typename color_element_type<P2, black_t >::type>(get_color(src,gray_color_t()));
00128     }
00129 };
00130 
00131 /// \ingroup ColorConvert
00132 ///  \brief Converting GRAY to any pixel type. Note: Supports homogeneous pixels only.
00133 ///
00134 /// Done by an intermediate RGB conversion
00135 template <typename C2>
00136 struct default_color_converter_impl<gray_t,C2>
00137 {
00138     template <typename P1, typename P2>
00139     void operator()(const P1& src, P2& dst) const
00140         {
00141         typedef gray_t C1;
00142         typedef typename channel_type<P1>::type T1;
00143         typedef typename channel_type<P2>::type T2;
00144                 pixel<T2,rgb_layout_t> tmp;
00145         default_color_converter_impl<C1,rgb_t>()(src, tmp);
00146         default_color_converter_impl<rgb_t,C2>()(tmp, dst);
00147     }
00148 };
00149 
00150 /// \ingroup ColorConvert
00151 /// \brief RGB to Gray
00152 template <>
00153 struct default_color_converter_impl<rgb_t,gray_t> {
00154     template <typename P1, typename P2>
00155     void operator()(const P1& src, P2& dst) const {
00156         get_color(dst,gray_color_t()) =
00157             detail::rgb_to_luminance<typename color_element_type<P2,gray_color_t>::type>(
00158                 get_color(src,red_t()), get_color(src,green_t()), get_color(src,blue_t())
00159             );
00160     }
00161 };
00162 
00163 
00164 /// \ingroup ColorConvert
00165 /// \brief RGB to CMYK (not the fastest code in the world)
00166 ///
00167 /// k = min(1 - r, 1 - g, 1 - b)
00168 /// c = (1 - r - k) / (1 - k)
00169 /// m = (1 - g - k) / (1 - k)
00170 /// y = (1 - b - k) / (1 - k)
00171 template <>
00172 struct default_color_converter_impl<rgb_t,cmyk_t> {
00173     template <typename P1, typename P2>
00174     void operator()(const P1& src, P2& dst) const {
00175         typedef typename channel_type<P2>::type T2;
00176         get_color(dst,cyan_t())    = channel_invert(channel_convert<T2>(get_color(src,red_t())));          // c = 1 - r
00177         get_color(dst,magenta_t()) = channel_invert(channel_convert<T2>(get_color(src,green_t())));        // m = 1 - g
00178         get_color(dst,yellow_t())  = channel_invert(channel_convert<T2>(get_color(src,blue_t())));         // y = 1 - b
00179         get_color(dst,black_t())   = (std::min)(get_color(dst,cyan_t()),
00180                                                 (std::min)(get_color(dst,magenta_t()),
00181                                                            get_color(dst,yellow_t())));   // k = minimum(c, m, y)
00182         T2 x = channel_traits<T2>::max_value()-get_color(dst,black_t());                  // x = 1 - k
00183         if (x>0.0001f) {
00184             float x1 = channel_traits<T2>::max_value()/float(x);
00185             get_color(dst,cyan_t())    = (T2)((get_color(dst,cyan_t())    - get_color(dst,black_t()))*x1);                // c = (c - k) / x
00186             get_color(dst,magenta_t()) = (T2)((get_color(dst,magenta_t()) - get_color(dst,black_t()))*x1);                // m = (m - k) / x
00187             get_color(dst,yellow_t())  = (T2)((get_color(dst,yellow_t())  - get_color(dst,black_t()))*x1);                // y = (y - k) / x
00188         } else {
00189             get_color(dst,cyan_t())=get_color(dst,magenta_t())=get_color(dst,yellow_t())=0;
00190         }
00191     }
00192 };
00193 
00194 /// \ingroup ColorConvert
00195 /// \brief CMYK to RGB (not the fastest code in the world)
00196 ///
00197 /// r = 1 - min(1, c*(1-k)+k)
00198 /// g = 1 - min(1, m*(1-k)+k)
00199 /// b = 1 - min(1, y*(1-k)+k)
00200 template <>
00201 struct default_color_converter_impl<cmyk_t,rgb_t> {
00202     template <typename P1, typename P2>
00203     void operator()(const P1& src, P2& dst) const {
00204         typedef typename channel_type<P1>::type T1;
00205         get_color(dst,red_t())  =
00206             channel_convert<typename color_element_type<P2,red_t>::type>(
00207                 channel_invert<T1>(
00208                     (std::min)(channel_traits<T1>::max_value(),
00209                              T1(get_color(src,cyan_t())*channel_invert(get_color(src,black_t()))+get_color(src,black_t())))));
00210         get_color(dst,green_t())=
00211             channel_convert<typename color_element_type<P2,green_t>::type>(
00212                 channel_invert<T1>(
00213                     (std::min)(channel_traits<T1>::max_value(),
00214                              T1(get_color(src,magenta_t())*channel_invert(get_color(src,black_t()))+get_color(src,black_t())))));
00215         get_color(dst,blue_t()) =
00216             channel_convert<typename color_element_type<P2,blue_t>::type>(
00217                 channel_invert<T1>(
00218                     (std::min)(channel_traits<T1>::max_value(),
00219                              T1(get_color(src,yellow_t())*channel_invert(get_color(src,black_t()))+get_color(src,black_t())))));
00220     }
00221 };
00222 
00223 
00224 /// \ingroup ColorConvert
00225 /// \brief CMYK to Gray
00226 ///
00227 /// gray = (1 - 0.212c - 0.715m - 0.0722y) * (1 - k)
00228 template <>
00229 struct default_color_converter_impl<cmyk_t,gray_t> {
00230     template <typename P1, typename P2>
00231     void operator()(const P1& src, P2& dst) const  {
00232         get_color(dst,gray_color_t())=
00233             channel_convert<typename color_element_type<P2,gray_t>::type>(
00234                 channel_multiply(
00235                     channel_invert(
00236                        detail::rgb_to_luminance<typename color_element_type<P1,black_t>::type>(
00237                             get_color(src,cyan_t()),
00238                             get_color(src,magenta_t()),
00239                             get_color(src,yellow_t())
00240                        )
00241                     ),
00242                     channel_invert(get_color(src,black_t()))));
00243     }
00244 };
00245 
00246 /// \ingroup ColorConvert
00247 ///  \brief Converting CMYK to any pixel type. Note: Supports homogeneous pixels only.
00248 ///
00249 /// Done by an intermediate RGB conversion
00250 template <typename C2>
00251 struct default_color_converter_impl<cmyk_t,C2>
00252 {
00253     template <typename P1, typename P2>
00254     void operator()(const P1& src, P2& dst) const
00255         {
00256         typedef cmyk_t C1;
00257         typedef typename channel_type<P1>::type T1;
00258         typedef typename channel_type<P2>::type T2;
00259                 pixel<T2,rgb_layout_t> tmp;
00260         default_color_converter_impl<C1,rgb_t>()(src, tmp);
00261         default_color_converter_impl<rgb_t,C2>()(tmp, dst);
00262     }
00263 };
00264 
00265 namespace detail {
00266 template <typename Pixel>
00267 typename channel_type<Pixel>::type alpha_or_max_impl(const Pixel& p, mpl::true_) {
00268     return get_color(p,alpha_t());
00269 }
00270 template <typename Pixel>
00271 typename channel_type<Pixel>::type alpha_or_max_impl(const Pixel&  , mpl::false_) {
00272     return channel_traits<typename channel_type<Pixel>::type>::max_value();
00273 }
00274 } // namespace detail
00275 
00276 // Returns max_value if the pixel has no alpha channel. Otherwise returns the alpha.
00277 template <typename Pixel>
00278 typename channel_type<Pixel>::type alpha_or_max(const Pixel& p) {
00279     return detail::alpha_or_max_impl(p, mpl::contains<typename color_space_type<Pixel>::type,alpha_t>());
00280 }
00281 
00282 /*
00283 /// \ingroup ColorConvert
00284 /// \brief Converting any pixel type to RGBA. Note: Supports homogeneous pixels only.
00285 template <typename C1>
00286 struct default_color_converter_impl<C1,rgba_t> {
00287     template <typename P1, typename P2>
00288     void operator()(const P1& src, P2& dst) const {
00289         typedef typename channel_type<P2>::type T2;
00290         pixel<T2,rgb_layout_t> tmp;
00291         default_color_converter_impl<C1,rgb_t>()(src,tmp);
00292         get_color(dst,red_t())  = get_color(tmp,red_t());
00293         get_color(dst,green_t())= get_color(tmp,green_t());
00294         get_color(dst,blue_t()) = get_color(tmp,blue_t());
00295         get_color(dst,alpha_t())= channel_convert<T2>(alpha_or_max(src));
00296     }
00297 };
00298 */
00299 
00300 /// \ingroup ColorConvert
00301 /// \brief Converting grayscale pixel type to RGBA. Note: Supports homogeneous pixels only.
00302 template <>
00303 struct default_color_converter_impl<gray_t,rgba_t> {
00304     template <typename P1, typename P2>
00305     void operator()(const P1& src, P2& dst) const
00306         {
00307         typedef gray_t C1;
00308         typedef typename channel_type<P2>::type T2;
00309         get_color(dst,red_t())  = get_color(src,gray_color_t());
00310         get_color(dst,green_t())= get_color(src,gray_color_t());
00311         get_color(dst,blue_t()) = get_color(src,gray_color_t());
00312         get_color(dst,alpha_t())= channel_convert<T2>(alpha_or_max(src));
00313     }
00314 };
00315 
00316 /// \ingroup ColorConvert
00317 /// \brief Converting grayscale pixel type to RGBA. Note: Supports homogeneous pixels only.
00318 template <>
00319 struct default_color_converter_impl<rgb_t,rgba_t> {
00320     template <typename P1, typename P2>
00321     void operator()(const P1& src, P2& dst) const
00322         {
00323         typedef rgb_t C1;
00324         typedef typename channel_type<P2>::type T2;
00325         get_color(dst,red_t())  = get_color(src,red_t());
00326         get_color(dst,green_t())= get_color(src,green_t());
00327         get_color(dst,blue_t()) = get_color(src,blue_t());
00328         get_color(dst,alpha_t())= channel_convert<T2>(alpha_or_max(src));
00329     }
00330 };
00331 
00332 /// \ingroup ColorConvert
00333 ///  \brief Converting RGBA to any pixel type. Note: Supports homogeneous pixels only.
00334 ///
00335 /// Done by multiplying the alpha to get to RGB, then converting the RGB to the target pixel type
00336 /// Note: This may be slower if the compiler doesn't optimize out constructing/destructing a temporary RGB pixel.
00337 ///       Consider rewriting if performance is an issue
00338 template <typename C2>
00339 struct default_color_converter_impl<rgba_t,C2> {
00340     template <typename P1, typename P2>
00341     void operator()(const P1& src, P2& dst) const {
00342         typedef typename channel_type<P1>::type T1;
00343         default_color_converter_impl<rgb_t,C2>()(
00344             pixel<T1,rgb_layout_t>(channel_multiply(get_color(src,red_t()),  get_color(src,alpha_t())),
00345                                    channel_multiply(get_color(src,green_t()),get_color(src,alpha_t())),
00346                                    channel_multiply(get_color(src,blue_t()), get_color(src,alpha_t())))
00347             ,dst);
00348     }
00349 };
00350 
00351 /// \ingroup ColorConvert
00352 /// \brief Unfortunately RGBA to RGBA must be explicitly provided - otherwise we get ambiguous specialization error.
00353 template <>
00354 struct default_color_converter_impl<rgba_t,rgba_t> {
00355     template <typename P1, typename P2>
00356     void operator()(const P1& src, P2& dst) const {
00357         static_for_each(src,dst,default_channel_converter());
00358     }
00359 };
00360 
00361 /// @defgroup ColorConvert Color Space Converion
00362 /// \ingroup ColorSpaces
00363 /// \brief Support for conversion between pixels of different color spaces and channel depths
00364 
00365 /// \ingroup PixelAlgorithm ColorConvert
00366 /// \brief class for color-converting one pixel to another
00367 struct default_color_converter {
00368     template <typename SrcP, typename DstP>
00369     void operator()(const SrcP& src,DstP& dst) const {
00370         typedef typename color_space_type<SrcP>::type SrcColorSpace;
00371         typedef typename color_space_type<DstP>::type DstColorSpace;
00372         default_color_converter_impl<SrcColorSpace,DstColorSpace>()(src,dst);
00373     }
00374 };
00375 
00376 /// \ingroup PixelAlgorithm
00377 /// \brief helper function for converting one pixel to another using GIL default color-converters
00378 ///     where ScrP models HomogeneousPixelConcept
00379 ///           DstP models HomogeneousPixelValueConcept
00380 template <typename SrcP, typename DstP>
00381 inline void color_convert(const SrcP& src, DstP& dst) {
00382     default_color_converter()(src,dst);
00383 }
00384 
00385 } }  // namespace boost::gil
00386 
00387 #endif