color_convert.hpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  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. #include <boost/gil/channel_algorithm.hpp>
  11. #include <boost/gil/cmyk.hpp>
  12. #include <boost/gil/color_base_algorithm.hpp>
  13. #include <boost/gil/gray.hpp>
  14. #include <boost/gil/metafunctions.hpp>
  15. #include <boost/gil/pixel.hpp>
  16. #include <boost/gil/rgb.hpp>
  17. #include <boost/gil/rgba.hpp>
  18. #include <boost/gil/utilities.hpp>
  19. #include <algorithm>
  20. #include <functional>
  21. #include <type_traits>
  22. namespace boost { namespace gil {
  23. /// Support for fast and simple color conversion.
  24. /// Accurate color conversion using color profiles can be supplied separately in a dedicated module.
  25. // Forward-declare
  26. template <typename P> struct channel_type;
  27. ////////////////////////////////////////////////////////////////////////////////////////
  28. ///
  29. /// COLOR SPACE CONVERSION
  30. ///
  31. ////////////////////////////////////////////////////////////////////////////////////////
  32. /// \ingroup ColorConvert
  33. /// \brief Color Convertion function object. To be specialized for every src/dst color space
  34. template <typename C1, typename C2>
  35. struct default_color_converter_impl {};
  36. /// \ingroup ColorConvert
  37. /// \brief When the color space is the same, color convertion performs channel depth conversion
  38. template <typename C>
  39. struct default_color_converter_impl<C,C> {
  40. template <typename P1, typename P2>
  41. void operator()(const P1& src, P2& dst) const {
  42. static_for_each(src,dst,default_channel_converter());
  43. }
  44. };
  45. namespace detail {
  46. /// red * .3 + green * .59 + blue * .11 + .5
  47. // The default implementation of to_luminance uses float0..1 as the intermediate channel type
  48. template <typename RedChannel, typename GreenChannel, typename BlueChannel, typename GrayChannelValue>
  49. struct rgb_to_luminance_fn {
  50. GrayChannelValue operator()(const RedChannel& red, const GreenChannel& green, const BlueChannel& blue) const {
  51. return channel_convert<GrayChannelValue>(float32_t(
  52. channel_convert<float32_t>(red )*0.30f +
  53. channel_convert<float32_t>(green)*0.59f +
  54. channel_convert<float32_t>(blue )*0.11f) );
  55. }
  56. };
  57. // performance specialization for unsigned char
  58. template <typename GrayChannelValue>
  59. struct rgb_to_luminance_fn<uint8_t,uint8_t,uint8_t, GrayChannelValue> {
  60. GrayChannelValue operator()(uint8_t red, uint8_t green, uint8_t blue) const {
  61. return channel_convert<GrayChannelValue>(uint8_t(
  62. ((uint32_t(red )*4915 + uint32_t(green)*9667 + uint32_t(blue )*1802) + 8192) >> 14));
  63. }
  64. };
  65. template <typename GrayChannel, typename RedChannel, typename GreenChannel, typename BlueChannel>
  66. typename channel_traits<GrayChannel>::value_type rgb_to_luminance(const RedChannel& red, const GreenChannel& green, const BlueChannel& blue) {
  67. return rgb_to_luminance_fn<RedChannel,GreenChannel,BlueChannel,
  68. typename channel_traits<GrayChannel>::value_type>()(red,green,blue);
  69. }
  70. } // namespace detail
  71. /// \ingroup ColorConvert
  72. /// \brief Gray to RGB
  73. template <>
  74. struct default_color_converter_impl<gray_t,rgb_t> {
  75. template <typename P1, typename P2>
  76. void operator()(const P1& src, P2& dst) const {
  77. get_color(dst,red_t()) =
  78. channel_convert<typename color_element_type<P2, red_t >::type>(get_color(src,gray_color_t()));
  79. get_color(dst,green_t())=
  80. channel_convert<typename color_element_type<P2, green_t>::type>(get_color(src,gray_color_t()));
  81. get_color(dst,blue_t()) =
  82. channel_convert<typename color_element_type<P2, blue_t >::type>(get_color(src,gray_color_t()));
  83. }
  84. };
  85. /// \ingroup ColorConvert
  86. /// \brief Gray to CMYK
  87. template <>
  88. struct default_color_converter_impl<gray_t,cmyk_t> {
  89. template <typename P1, typename P2>
  90. void operator()(const P1& src, P2& dst) const {
  91. get_color(dst,cyan_t())=
  92. channel_traits<typename color_element_type<P2, cyan_t >::type>::min_value();
  93. get_color(dst,magenta_t())=
  94. channel_traits<typename color_element_type<P2, magenta_t>::type>::min_value();
  95. get_color(dst,yellow_t())=
  96. channel_traits<typename color_element_type<P2, yellow_t >::type>::min_value();
  97. get_color(dst,black_t())=
  98. channel_convert<typename color_element_type<P2, black_t >::type>(get_color(src,gray_color_t()));
  99. }
  100. };
  101. /// \ingroup ColorConvert
  102. /// \brief RGB to Gray
  103. template <>
  104. struct default_color_converter_impl<rgb_t,gray_t> {
  105. template <typename P1, typename P2>
  106. void operator()(const P1& src, P2& dst) const {
  107. get_color(dst,gray_color_t()) =
  108. detail::rgb_to_luminance<typename color_element_type<P2,gray_color_t>::type>(
  109. get_color(src,red_t()), get_color(src,green_t()), get_color(src,blue_t())
  110. );
  111. }
  112. };
  113. /// \ingroup ColorConvert
  114. /// \brief RGB to CMYK (not the fastest code in the world)
  115. ///
  116. /// k = min(1 - r, 1 - g, 1 - b)
  117. /// c = (1 - r - k) / (1 - k)
  118. /// m = (1 - g - k) / (1 - k)
  119. /// y = (1 - b - k) / (1 - k)
  120. template <>
  121. struct default_color_converter_impl<rgb_t,cmyk_t> {
  122. template <typename P1, typename P2>
  123. void operator()(const P1& src, P2& dst) const {
  124. using T2 = typename channel_type<P2>::type;
  125. get_color(dst,cyan_t()) = channel_invert(channel_convert<T2>(get_color(src,red_t()))); // c = 1 - r
  126. get_color(dst,magenta_t()) = channel_invert(channel_convert<T2>(get_color(src,green_t()))); // m = 1 - g
  127. get_color(dst,yellow_t()) = channel_invert(channel_convert<T2>(get_color(src,blue_t()))); // y = 1 - b
  128. get_color(dst,black_t()) = (std::min)(get_color(dst,cyan_t()),
  129. (std::min)(get_color(dst,magenta_t()),
  130. get_color(dst,yellow_t()))); // k = minimum(c, m, y)
  131. T2 x = channel_traits<T2>::max_value()-get_color(dst,black_t()); // x = 1 - k
  132. if (x>0.0001f) {
  133. float x1 = channel_traits<T2>::max_value()/float(x);
  134. get_color(dst,cyan_t()) = (T2)((get_color(dst,cyan_t()) - get_color(dst,black_t()))*x1); // c = (c - k) / x
  135. get_color(dst,magenta_t()) = (T2)((get_color(dst,magenta_t()) - get_color(dst,black_t()))*x1); // m = (m - k) / x
  136. get_color(dst,yellow_t()) = (T2)((get_color(dst,yellow_t()) - get_color(dst,black_t()))*x1); // y = (y - k) / x
  137. } else {
  138. get_color(dst,cyan_t())=get_color(dst,magenta_t())=get_color(dst,yellow_t())=0;
  139. }
  140. }
  141. };
  142. /// \ingroup ColorConvert
  143. /// \brief CMYK to RGB (not the fastest code in the world)
  144. ///
  145. /// r = 1 - min(1, c*(1-k)+k)
  146. /// g = 1 - min(1, m*(1-k)+k)
  147. /// b = 1 - min(1, y*(1-k)+k)
  148. template <>
  149. struct default_color_converter_impl<cmyk_t,rgb_t> {
  150. template <typename P1, typename P2>
  151. void operator()(const P1& src, P2& dst) const {
  152. using T1 = typename channel_type<P1>::type;
  153. get_color(dst,red_t()) =
  154. channel_convert<typename color_element_type<P2,red_t>::type>(
  155. channel_invert<T1>(
  156. (std::min)(channel_traits<T1>::max_value(),
  157. T1(channel_multiply(get_color(src,cyan_t()),channel_invert(get_color(src,black_t())))+get_color(src,black_t())))));
  158. get_color(dst,green_t())=
  159. channel_convert<typename color_element_type<P2,green_t>::type>(
  160. channel_invert<T1>(
  161. (std::min)(channel_traits<T1>::max_value(),
  162. T1(channel_multiply(get_color(src,magenta_t()),channel_invert(get_color(src,black_t())))+get_color(src,black_t())))));
  163. get_color(dst,blue_t()) =
  164. channel_convert<typename color_element_type<P2,blue_t>::type>(
  165. channel_invert<T1>(
  166. (std::min)(channel_traits<T1>::max_value(),
  167. T1(channel_multiply(get_color(src,yellow_t()),channel_invert(get_color(src,black_t())))+get_color(src,black_t())))));
  168. }
  169. };
  170. /// \ingroup ColorConvert
  171. /// \brief CMYK to Gray
  172. ///
  173. /// gray = (1 - 0.212c - 0.715m - 0.0722y) * (1 - k)
  174. template <>
  175. struct default_color_converter_impl<cmyk_t,gray_t> {
  176. template <typename P1, typename P2>
  177. void operator()(const P1& src, P2& dst) const {
  178. get_color(dst,gray_color_t())=
  179. channel_convert<typename color_element_type<P2,gray_color_t>::type>(
  180. channel_multiply(
  181. channel_invert(
  182. detail::rgb_to_luminance<typename color_element_type<P1,black_t>::type>(
  183. get_color(src,cyan_t()),
  184. get_color(src,magenta_t()),
  185. get_color(src,yellow_t())
  186. )
  187. ),
  188. channel_invert(get_color(src,black_t()))));
  189. }
  190. };
  191. namespace detail {
  192. template <typename Pixel>
  193. auto alpha_or_max_impl(Pixel const& p, std::true_type) -> typename channel_type<Pixel>::type
  194. {
  195. return get_color(p,alpha_t());
  196. }
  197. template <typename Pixel>
  198. auto alpha_or_max_impl(Pixel const&, std::false_type) -> typename channel_type<Pixel>::type
  199. {
  200. return channel_traits<typename channel_type<Pixel>::type>::max_value();
  201. }
  202. } // namespace detail
  203. // Returns max_value if the pixel has no alpha channel. Otherwise returns the alpha.
  204. template <typename Pixel>
  205. auto alpha_or_max(Pixel const& p) -> typename channel_type<Pixel>::type
  206. {
  207. return detail::alpha_or_max_impl(
  208. p,
  209. mp11::mp_contains<typename color_space_type<Pixel>::type, alpha_t>());
  210. }
  211. /// \ingroup ColorConvert
  212. /// \brief Converting any pixel type to RGBA. Note: Supports homogeneous pixels only.
  213. template <typename C1>
  214. struct default_color_converter_impl<C1,rgba_t> {
  215. template <typename P1, typename P2>
  216. void operator()(const P1& src, P2& dst) const {
  217. using T2 = typename channel_type<P2>::type;
  218. pixel<T2,rgb_layout_t> tmp;
  219. default_color_converter_impl<C1,rgb_t>()(src,tmp);
  220. get_color(dst,red_t()) =get_color(tmp,red_t());
  221. get_color(dst,green_t())=get_color(tmp,green_t());
  222. get_color(dst,blue_t()) =get_color(tmp,blue_t());
  223. get_color(dst,alpha_t())=channel_convert<T2>(alpha_or_max(src));
  224. }
  225. };
  226. /// \ingroup ColorConvert
  227. /// \brief Converting RGBA to any pixel type. Note: Supports homogeneous pixels only.
  228. ///
  229. /// Done by multiplying the alpha to get to RGB, then converting the RGB to the target pixel type
  230. /// Note: This may be slower if the compiler doesn't optimize out constructing/destructing a temporary RGB pixel.
  231. /// Consider rewriting if performance is an issue
  232. template <typename C2>
  233. struct default_color_converter_impl<rgba_t,C2> {
  234. template <typename P1, typename P2>
  235. void operator()(const P1& src, P2& dst) const {
  236. using T1 = typename channel_type<P1>::type;
  237. default_color_converter_impl<rgb_t,C2>()(
  238. pixel<T1,rgb_layout_t>(channel_multiply(get_color(src,red_t()), get_color(src,alpha_t())),
  239. channel_multiply(get_color(src,green_t()),get_color(src,alpha_t())),
  240. channel_multiply(get_color(src,blue_t()), get_color(src,alpha_t())))
  241. ,dst);
  242. }
  243. };
  244. /// \ingroup ColorConvert
  245. /// \brief Unfortunately RGBA to RGBA must be explicitly provided - otherwise we get ambiguous specialization error.
  246. template <>
  247. struct default_color_converter_impl<rgba_t,rgba_t> {
  248. template <typename P1, typename P2>
  249. void operator()(const P1& src, P2& dst) const {
  250. static_for_each(src,dst,default_channel_converter());
  251. }
  252. };
  253. /// @defgroup ColorConvert Color Space Converion
  254. /// \ingroup ColorSpaces
  255. /// \brief Support for conversion between pixels of different color spaces and channel depths
  256. /// \ingroup PixelAlgorithm ColorConvert
  257. /// \brief class for color-converting one pixel to another
  258. struct default_color_converter {
  259. template <typename SrcP, typename DstP>
  260. void operator()(const SrcP& src,DstP& dst) const {
  261. using SrcColorSpace = typename color_space_type<SrcP>::type;
  262. using DstColorSpace = typename color_space_type<DstP>::type;
  263. default_color_converter_impl<SrcColorSpace,DstColorSpace>()(src,dst);
  264. }
  265. };
  266. /// \ingroup PixelAlgorithm
  267. /// \brief helper function for converting one pixel to another using GIL default color-converters
  268. /// where ScrP models HomogeneousPixelConcept
  269. /// DstP models HomogeneousPixelValueConcept
  270. template <typename SrcP, typename DstP>
  271. inline void color_convert(const SrcP& src, DstP& dst) {
  272. default_color_converter()(src,dst);
  273. }
  274. } } // namespace boost::gil
  275. #endif