TuttleOFX
1
|
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