]> git.proxmox.com Git - ceph.git/blobdiff - ceph/src/boost/boost/gil/color_convert.hpp
import quincy beta 17.1.0
[ceph.git] / ceph / src / boost / boost / gil / color_convert.hpp
index 4894359c5f28ba3ac1819cdde829b59b249c8ba0..1c9e75d879722f9ac8749e6f98fd200fc0f5b4a2 100644 (file)
@@ -105,6 +105,8 @@ struct default_color_converter_impl<gray_t,rgb_t> {
 
 /// \ingroup ColorConvert
 /// \brief Gray to CMYK
+/// \todo FIXME: Where does this calculation come from? Shouldn't gray be inverted?
+///              Currently, white becomes black and black becomes white.
 template <>
 struct default_color_converter_impl<gray_t,cmyk_t> {
     template <typename P1, typename P2>
@@ -141,26 +143,51 @@ struct default_color_converter_impl<rgb_t,gray_t> {
 /// c = (1 - r - k) / (1 - k)
 /// m = (1 - g - k) / (1 - k)
 /// y = (1 - b - k) / (1 - k)
+/// where `1` denotes max value of channel type of destination pixel.
+///
+/// The conversion from RGB to CMYK is based on CMY->CMYK (Version 2)
+/// from the Principles of Digital Image Processing - Fundamental Techniques
+/// by Burger, Wilhelm, Burge, Mark J.
+/// and it is a gross approximation not precise enough for professional work.
+///
+/// \todo FIXME: The original implementation did not handle properly signed CMYK pixels as destination
+///
 template <>
-struct default_color_converter_impl<rgb_t,cmyk_t> {
-    template <typename P1, typename P2>
-    void operator()(const P1& src, P2& dst) const {
-        using T2 = typename channel_type<P2>::type;
-        get_color(dst,cyan_t())    = channel_invert(channel_convert<T2>(get_color(src,red_t())));          // c = 1 - r
-        get_color(dst,magenta_t()) = channel_invert(channel_convert<T2>(get_color(src,green_t())));        // m = 1 - g
-        get_color(dst,yellow_t())  = channel_invert(channel_convert<T2>(get_color(src,blue_t())));         // y = 1 - b
-        get_color(dst,black_t())   = (std::min)(get_color(dst,cyan_t()),
-                                                (std::min)(get_color(dst,magenta_t()),
-                                                           get_color(dst,yellow_t())));   // k = minimum(c, m, y)
-        T2 x = channel_traits<T2>::max_value()-get_color(dst,black_t());                  // x = 1 - k
-        if (x>0.0001f) {
-            float x1 = channel_traits<T2>::max_value()/float(x);
-            get_color(dst,cyan_t())    = (T2)((get_color(dst,cyan_t())    - get_color(dst,black_t()))*x1);                // c = (c - k) / x
-            get_color(dst,magenta_t()) = (T2)((get_color(dst,magenta_t()) - get_color(dst,black_t()))*x1);                // m = (m - k) / x
-            get_color(dst,yellow_t())  = (T2)((get_color(dst,yellow_t())  - get_color(dst,black_t()))*x1);                // y = (y - k) / x
-        } else {
-            get_color(dst,cyan_t())=get_color(dst,magenta_t())=get_color(dst,yellow_t())=0;
+struct default_color_converter_impl<rgb_t, cmyk_t>
+{
+    template <typename SrcPixel, typename DstPixel>
+    void operator()(SrcPixel const& src, DstPixel& dst) const
+    {
+        using src_t = typename channel_type<SrcPixel>::type;
+        src_t const r = get_color(src, red_t());  
+        src_t const g = get_color(src, green_t());
+        src_t const b = get_color(src, blue_t());
+
+        using dst_t   = typename channel_type<DstPixel>::type;
+        dst_t const c = channel_invert(channel_convert<dst_t>(r)); // c = 1 - r
+        dst_t const m = channel_invert(channel_convert<dst_t>(g)); // m = 1 - g
+        dst_t const y = channel_invert(channel_convert<dst_t>(b)); // y = 1 - b
+        dst_t const k = (std::min)(c, (std::min)(m, y));           // k = minimum(c, m, y)
+
+        // Apply color correction, strengthening, reducing non-zero components by
+        // s = 1 / (1 - k) for k < 1, where 1 denotes dst_t max, otherwise s = 1 (literal).
+        dst_t const dst_max = channel_traits<dst_t>::max_value();
+        dst_t const s_div   = dst_max - k;
+        if (s_div != 0)
+        {
+            double const s              = dst_max / static_cast<double>(s_div);
+            get_color(dst, cyan_t())    = static_cast<dst_t>((c - k) * s);
+            get_color(dst, magenta_t()) = static_cast<dst_t>((m - k) * s);
+            get_color(dst, yellow_t())  = static_cast<dst_t>((y - k) * s);
+        }
+        else
+        {
+            // Black only for k = 1 (max of dst_t)
+            get_color(dst, cyan_t())    = channel_traits<dst_t>::min_value();
+            get_color(dst, magenta_t()) = channel_traits<dst_t>::min_value();
+            get_color(dst, yellow_t())  = channel_traits<dst_t>::min_value();
         }
+        get_color(dst, black_t()) = k; 
     }
 };