Improve detection of color space transfer fns
authorMatt Sarett <msarett@google.com>
Wed, 4 Jan 2017 15:53:31 +0000 (10:53 -0500)
committerSkia Commit-Bot <skia-commit-bot@chromium.org>
Wed, 4 Jan 2017 16:26:58 +0000 (16:26 +0000)
BUG=skia:

Change-Id: I744af0efd4d48a8932b834092ed2dbad13008c1d
Reviewed-on: https://skia-review.googlesource.com/6556
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Matt Sarett <msarett@google.com>

src/core/SkColorSpace.cpp
src/core/SkColorSpacePriv.h
tests/ColorSpaceTest.cpp

index f6cbf0a..239a61b 100644 (file)
@@ -165,6 +165,10 @@ sk_sp<SkColorSpace> SkColorSpace::MakeRGB(const SkColorSpaceTransferFn& coeffs,
         return SkColorSpace_Base::MakeRGB(k2Dot2Curve_SkGammaNamed, toXYZD50);
     }
 
+    if (is_almost_linear(coeffs)) {
+        return SkColorSpace_Base::MakeRGB(kLinear_SkGammaNamed, toXYZD50);
+    }
+
     void* memory = sk_malloc_throw(sizeof(SkGammas) + sizeof(SkColorSpaceTransferFn));
     sk_sp<SkGammas> gammas = sk_sp<SkGammas>(new (memory) SkGammas(3));
     SkColorSpaceTransferFn* fn = SkTAddOffset<SkColorSpaceTransferFn>(memory, sizeof(SkGammas));
index 9f084e7..5b09036 100644 (file)
@@ -51,7 +51,7 @@ static inline bool is_valid_transfer_fn(const SkColorSpaceTransferFn& coeffs) {
     }
 
     if (coeffs.fD == 0.0f) {
-        // Y = (aX + b)^g + c  for always
+        // Y = (aX + b)^g + e  for always
         if (0.0f == coeffs.fA || 0.0f == coeffs.fG) {
             SkColorSpacePrintf("A or G is zero, constant transfer function "
                                "is nonsense");
@@ -60,16 +60,16 @@ static inline bool is_valid_transfer_fn(const SkColorSpaceTransferFn& coeffs) {
     }
 
     if (coeffs.fD >= 1.0f) {
-        // Y = eX + f          for always
-        if (0.0f == coeffs.fE) {
-            SkColorSpacePrintf("E is zero, constant transfer function is "
+        // Y = cX + f          for always
+        if (0.0f == coeffs.fC) {
+            SkColorSpacePrintf("C is zero, constant transfer function is "
                                "nonsense");
             return false;
         }
     }
 
     if ((0.0f == coeffs.fA || 0.0f == coeffs.fG) && 0.0f == coeffs.fC) {
-        SkColorSpacePrintf("A or G, and E are zero, constant transfer function "
+        SkColorSpacePrintf("A or G, and C are zero, constant transfer function "
                            "is nonsense");
         return false;
     }
@@ -100,11 +100,27 @@ static inline bool is_almost_srgb(const SkColorSpaceTransferFn& coeffs) {
 static inline bool is_almost_2dot2(const SkColorSpaceTransferFn& coeffs) {
     return color_space_almost_equal(1.0f, coeffs.fA) &&
            color_space_almost_equal(0.0f, coeffs.fB) &&
-           color_space_almost_equal(0.0f, coeffs.fC) &&
-           color_space_almost_equal(0.0f, coeffs.fD) &&
            color_space_almost_equal(0.0f, coeffs.fE) &&
+           color_space_almost_equal(2.2f, coeffs.fG) &&
+           coeffs.fD <= 0.0f;
+}
+
+static inline bool is_almost_linear(const SkColorSpaceTransferFn& coeffs) {
+    // OutputVal = InputVal ^ 1.0f
+    const bool linearExp =
+           color_space_almost_equal(1.0f, coeffs.fA) &&
+           color_space_almost_equal(0.0f, coeffs.fB) &&
+           color_space_almost_equal(0.0f, coeffs.fE) &&
+           color_space_almost_equal(1.0f, coeffs.fG) &&
+           coeffs.fD <= 0.0f;
+
+    // OutputVal = 1.0f * InputVal
+    const bool linearFn =
+           color_space_almost_equal(1.0f, coeffs.fC) &&
            color_space_almost_equal(0.0f, coeffs.fF) &&
-           color_space_almost_equal(2.2f, coeffs.fG);
+           coeffs.fD >= 1.0f;
+
+    return linearExp || linearFn;
 }
 
 static inline void value_to_parametric(SkColorSpaceTransferFn* coeffs, float exponent) {
index df253c0..ba355cd 100644 (file)
@@ -10,6 +10,7 @@
 #include "SkColorSpace.h"
 #include "SkColorSpace_Base.h"
 #include "SkColorSpace_XYZ.h"
+#include "SkColorSpacePriv.h"
 #include "Test.h"
 
 #include "png.h"
@@ -111,6 +112,17 @@ DEF_TEST(ColorSpaceSRGBCompare, r) {
             SkColorSpace::MakeRGB(SkColorSpace::kSRGB_RenderTargetGamma, srgbToxyzD50);
     REPORTER_ASSERT(r, rgbColorSpace == namedColorSpace);
 
+    SkColorSpaceTransferFn srgbFn;
+    srgbFn.fA = (1.0f / 1.055f);
+    srgbFn.fB = (0.055f / 1.055f);
+    srgbFn.fC = (1.0f / 12.92f);
+    srgbFn.fD = 0.04045f;
+    srgbFn.fE = 0.0f;
+    srgbFn.fF = 0.0f;
+    srgbFn.fG = 2.4f;
+    sk_sp<SkColorSpace> rgbColorSpace2 = SkColorSpace::MakeRGB(srgbFn, srgbToxyzD50);
+    REPORTER_ASSERT(r, rgbColorSpace2 == namedColorSpace);
+
     // Change a single value from the sRGB matrix
     srgbToxyzD50.set(2, 2, 0.5f);
     sk_sp<SkColorSpace> strangeColorSpace =
@@ -135,6 +147,28 @@ DEF_TEST(ColorSpaceSRGBLinearCompare, r) {
         SkColorSpace::MakeRGB(SkColorSpace::kLinear_RenderTargetGamma, srgbToxyzD50);
     REPORTER_ASSERT(r, rgbColorSpace == namedColorSpace);
 
+    SkColorSpaceTransferFn linearExpFn;
+    linearExpFn.fA = 1.0f;
+    linearExpFn.fB = 0.0f;
+    linearExpFn.fC = 0.0f;
+    linearExpFn.fD = 0.0f;
+    linearExpFn.fE = 0.0f;
+    linearExpFn.fF = 0.0f;
+    linearExpFn.fG = 1.0f;
+    sk_sp<SkColorSpace> rgbColorSpace2 = SkColorSpace::MakeRGB(linearExpFn, srgbToxyzD50);
+    REPORTER_ASSERT(r, rgbColorSpace2 == namedColorSpace);
+
+    SkColorSpaceTransferFn linearFn;
+    linearFn.fA = 0.0f;
+    linearFn.fB = 0.0f;
+    linearFn.fC = 1.0f;
+    linearFn.fD = 1.0f;
+    linearFn.fE = 0.0f;
+    linearFn.fF = 0.0f;
+    linearFn.fG = 0.0f;
+    sk_sp<SkColorSpace> rgbColorSpace3 = SkColorSpace::MakeRGB(linearFn, srgbToxyzD50);
+    REPORTER_ASSERT(r, rgbColorSpace3 == namedColorSpace);
+
     // Change a single value from the sRGB matrix
     srgbToxyzD50.set(2, 2, 0.5f);
     sk_sp<SkColorSpace> strangeColorSpace =
@@ -142,6 +176,26 @@ DEF_TEST(ColorSpaceSRGBLinearCompare, r) {
     REPORTER_ASSERT(r, strangeColorSpace != namedColorSpace);
 }
 
+DEF_TEST(ColorSpaceAdobeCompare, r) {
+    // Create an sRGB color space by name
+    sk_sp<SkColorSpace> namedColorSpace = SkColorSpace::MakeNamed(SkColorSpace::kAdobeRGB_Named);
+
+    // Create an sRGB color space by value
+    SkMatrix44 adobeToxyzD50(SkMatrix44::kUninitialized_Constructor);
+    adobeToxyzD50.set3x3RowMajorf(gAdobeRGB_toXYZD50);
+
+    SkColorSpaceTransferFn fn;
+    fn.fA = 1.0f;
+    fn.fB = 0.0f;
+    fn.fC = 0.0f;
+    fn.fD = 0.0f;
+    fn.fE = 0.0f;
+    fn.fF = 0.0f;
+    fn.fG = 2.2f;
+    sk_sp<SkColorSpace> rgbColorSpace = SkColorSpace::MakeRGB(fn, adobeToxyzD50);
+    REPORTER_ASSERT(r, rgbColorSpace == namedColorSpace);
+}
+
 DEF_TEST(ColorSpace_Named, r) {
     const struct {
         SkColorSpace::Named fNamed;