diff options
author | msarett <msarett@google.com> | 2016-06-16 07:37:41 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-06-16 07:37:41 -0700 |
commit | c4ce6b592487305de251bbebaf8eeee38371b877 (patch) | |
tree | 8715df359e6f40c6eff5603abe43d9ac0dc2b724 | |
parent | ded0f26a93a115fdb8f2eb99841b85cc16baf400 (diff) |
Differentiate between sRGBGamma and 2Dot2Gamma
BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2067833003
Review-Url: https://codereview.chromium.org/2067833003
-rw-r--r-- | gm/color4f.cpp | 5 | ||||
-rw-r--r-- | include/core/SkColorSpace.h | 47 | ||||
-rw-r--r-- | src/codec/SkPngCodec.cpp | 38 | ||||
-rw-r--r-- | src/core/SkColorSpace.cpp | 269 | ||||
-rw-r--r-- | src/core/SkColorSpaceXform.cpp | 113 | ||||
-rw-r--r-- | src/core/SkColorSpace_Base.h | 75 | ||||
-rw-r--r-- | src/core/SkMipMap.cpp | 2 | ||||
-rw-r--r-- | tests/ColorSpaceTest.cpp | 45 |
8 files changed, 338 insertions, 256 deletions
diff --git a/gm/color4f.cpp b/gm/color4f.cpp index ffe9a8742d..33d837786a 100644 --- a/gm/color4f.cpp +++ b/gm/color4f.cpp @@ -95,8 +95,6 @@ DEF_SIMPLE_GM(color4shader, canvas, 1024, 260) { // red -> blue, green -> red, blue -> green mat.set3x3(0, 1, 0, 0, 0, 1, 1, 0, 0); - float linearGamma[3] = { 1.0f, 1.0f, 1.0f }; - const SkColor4f colors[] { { 1, 1, 0, 0 }, { 1, 0, 1, 0 }, @@ -111,7 +109,8 @@ DEF_SIMPLE_GM(color4shader, canvas, 1024, 260) { sk_sp<SkShader> shaders[] { SkShader::MakeColorShader(c4, nullptr), SkShader::MakeColorShader(c4, SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named)), - SkShader::MakeColorShader(c4, SkColorSpace::NewRGB(linearGamma, mat)), + SkShader::MakeColorShader(c4, SkColorSpace::NewRGB(SkColorSpace::kLinear_GammaNamed, + mat)), }; canvas->save(); diff --git a/include/core/SkColorSpace.h b/include/core/SkColorSpace.h index 0b3b9768ec..0f57b6d680 100644 --- a/include/core/SkColorSpace.h +++ b/include/core/SkColorSpace.h @@ -23,27 +23,18 @@ public: kAdobeRGB_Named, }; - /** - * Create an SkColorSpace from the src gamma and a transform from src gamut to D50 XYZ. - */ - static sk_sp<SkColorSpace> NewRGB(const float gammas[3], const SkMatrix44& toXYZD50); - - /** - * Create a common, named SkColorSpace. - */ - static sk_sp<SkColorSpace> NewNamed(Named); - - /** - * Create an SkColorSpace from an ICC profile. - */ - static sk_sp<SkColorSpace> NewICC(const void*, size_t); - enum GammaNamed { kLinear_GammaNamed, /** - * Gamma curve is a close match to the 2.2f exponential curve. This is by far - * the most common gamma, and is used by sRGB and Adobe RGB profiles. + * Gamma curve is a close match to the canonical sRGB curve, which has + * a short linear segment followed by a 2.4f exponential. + */ + kSRGB_GammaNamed, + + /** + * Gamma curve is a close match to the 2.2f exponential curve. This is + * used by Adobe RGB profiles and is common on monitors as well. */ k2Dot2Curve_GammaNamed, @@ -55,6 +46,21 @@ public: kNonStandard_GammaNamed, }; + /** + * Create an SkColorSpace from the src gamma and a transform from src gamut to D50 XYZ. + */ + static sk_sp<SkColorSpace> NewRGB(GammaNamed gammaNamed, const SkMatrix44& toXYZD50); + + /** + * Create a common, named SkColorSpace. + */ + static sk_sp<SkColorSpace> NewNamed(Named); + + /** + * Create an SkColorSpace from an ICC profile. + */ + static sk_sp<SkColorSpace> NewICC(const void*, size_t); + GammaNamed gammaNamed() const { return fGammaNamed; } /** @@ -62,6 +68,13 @@ public: */ const SkMatrix44& xyz() const { return fToXYZD50; } + /** + * Returns true if the color space gamma is near enough to be approximated as sRGB. + */ + bool gammaCloseToSRGB() const { + return kSRGB_GammaNamed == fGammaNamed || k2Dot2Curve_GammaNamed == fGammaNamed; + } + protected: SkColorSpace(GammaNamed gammaNamed, const SkMatrix44& toXYZD50, Named named); diff --git a/src/codec/SkPngCodec.cpp b/src/codec/SkPngCodec.cpp index 43d1580c17..985d61a4d6 100644 --- a/src/codec/SkPngCodec.cpp +++ b/src/codec/SkPngCodec.cpp @@ -8,7 +8,7 @@ #include "SkBitmap.h" #include "SkCodecPriv.h" #include "SkColorPriv.h" -#include "SkColorSpace.h" +#include "SkColorSpace_Base.h" #include "SkColorTable.h" #include "SkMath.h" #include "SkOpts.h" @@ -172,6 +172,12 @@ static float png_inverted_fixed_point_to_float(png_fixed_point x) { return 1.0f / png_fixed_point_to_float(x); } +static constexpr float gSRGB_toXYZD50[] { + 0.4358f, 0.2224f, 0.0139f, // * R + 0.3853f, 0.7170f, 0.0971f, // * G + 0.1430f, 0.0606f, 0.7139f, // * B +}; + // Returns a colorSpace object that represents any color space information in // the encoded data. If the encoded data contains no color space, this will // return NULL. @@ -223,6 +229,8 @@ sk_sp<SkColorSpace> read_color_space(png_structp png_ptr, png_infop info_ptr) { for (int i = 0; i < 9; i++) { toXYZD50[i] = png_fixed_point_to_float(XYZ[i]); } + SkMatrix44 mat(SkMatrix44::kUninitialized_Constructor); + mat.set3x3ColMajorf(toXYZD50); if (PNG_INFO_gAMA == png_get_gAMA_fixed(png_ptr, info_ptr, &gamma)) { float value = png_inverted_fixed_point_to_float(gamma); @@ -230,40 +238,34 @@ sk_sp<SkColorSpace> read_color_space(png_structp png_ptr, png_infop info_ptr) { gammas[1] = value; gammas[2] = value; - } else { - // Default to sRGB (gamma = 2.2f) if the image has color space information, - // but does not specify gamma. - gammas[0] = 2.2f; - gammas[1] = 2.2f; - gammas[2] = 2.2f; + return SkColorSpace_Base::NewRGB(gammas, mat); } - SkMatrix44 mat(SkMatrix44::kUninitialized_Constructor); - mat.set3x3ColMajorf(toXYZD50); - return SkColorSpace::NewRGB(gammas, mat); + // Default to sRGB gamma if the image has color space information, + // but does not specify gamma. + return SkColorSpace::NewRGB(SkColorSpace::kSRGB_GammaNamed, mat); } // Last, check for gamma. if (PNG_INFO_gAMA == png_get_gAMA_fixed(png_ptr, info_ptr, &gamma)) { - // Guess a default value for cHRM? Or should we just give up? - // Here we use the identity matrix as a default. - // Set the gammas. float value = png_inverted_fixed_point_to_float(gamma); gammas[0] = value; gammas[1] = value; gammas[2] = value; - return SkColorSpace::NewRGB(gammas, SkMatrix44::I()); + // Since there is no cHRM, we will guess sRGB gamut. + SkMatrix44 mat(SkMatrix44::kUninitialized_Constructor); + mat.set3x3ColMajorf(gSRGB_toXYZD50); + + return SkColorSpace_Base::NewRGB(gammas, mat); } #endif // LIBPNG >= 1.6 - // Finally, what should we do if there is no color space information in the PNG? - // The specification says that this indicates "gamma is unknown" and that the - // "color is device dependent". I'm assuming we can represent this with NULL. - // But should we guess sRGB? Most images are sRGB, even if they don't specify. + // Report that there is no color space information in the PNG. SkPngCodec is currently + // implemented to guess sRGB in this case. return nullptr; } diff --git a/src/core/SkColorSpace.cpp b/src/core/SkColorSpace.cpp index 69fada23df..ec8de725c1 100644 --- a/src/core/SkColorSpace.cpp +++ b/src/core/SkColorSpace.cpp @@ -10,6 +10,8 @@ #include "SkEndian.h" #include "SkOnce.h" +#define SkColorSpacePrintf(...) + static bool color_space_almost_equal(float a, float b) { return SkTAbs(a - b) < 0.01f; } @@ -22,18 +24,10 @@ SkColorSpace::SkColorSpace(GammaNamed gammaNamed, const SkMatrix44& toXYZD50, Na , fNamed(named) {} -SkColorSpace_Base::SkColorSpace_Base(sk_sp<SkGammas> gammas, const SkMatrix44& toXYZD50, - Named named, sk_sp<SkData> profileData) - : INHERITED(kNonStandard_GammaNamed, toXYZD50, named) - , fGammas(std::move(gammas)) - , fProfileData(std::move(profileData)) -{} - -SkColorSpace_Base::SkColorSpace_Base(sk_sp<SkGammas> gammas, GammaNamed gammaNamed, - const SkMatrix44& toXYZD50, Named named, +SkColorSpace_Base::SkColorSpace_Base(GammaNamed gammaNamed, const SkMatrix44& toXYZD50, Named named, sk_sp<SkData> profileData) : INHERITED(gammaNamed, toXYZD50, named) - , fGammas(std::move(gammas)) + , fGammas(nullptr) , fProfileData(std::move(profileData)) {} @@ -82,52 +76,61 @@ static bool xyz_almost_equal(const SkMatrix44& toXYZD50, const float* standard) color_space_almost_equal(toXYZD50.getFloat(3, 3), 1.0f); } -static SkOnce g2Dot2CurveGammasOnce; -static SkGammas* g2Dot2CurveGammas; -static SkOnce gLinearGammasOnce; -static SkGammas* gLinearGammas; +static void set_gamma_value(SkGammaCurve* gamma, float value) { + if (color_space_almost_equal(2.2f, value)) { + gamma->fNamed = SkColorSpace::k2Dot2Curve_GammaNamed; + } else if (color_space_almost_equal(1.0f, value)) { + gamma->fNamed = SkColorSpace::kLinear_GammaNamed; + } else if (color_space_almost_equal(0.0f, value)) { + SkColorSpacePrintf("Treating invalid zero gamma as linear."); + gamma->fNamed = SkColorSpace::kLinear_GammaNamed; + } else { + gamma->fValue = value; + } +} + +sk_sp<SkColorSpace> SkColorSpace_Base::NewRGB(float values[3], const SkMatrix44& toXYZD50) { + SkGammaCurve curves[3]; + set_gamma_value(&curves[0], values[0]); + set_gamma_value(&curves[1], values[1]); + set_gamma_value(&curves[2], values[2]); + + GammaNamed gammaNamed = SkGammas::Named(curves); + if (kNonStandard_GammaNamed == gammaNamed) { + sk_sp<SkGammas> gammas(new SkGammas(std::move(curves[0]), std::move(curves[1]), + std::move(curves[2]))); + return sk_sp<SkColorSpace>(new SkColorSpace_Base(nullptr, gammas, toXYZD50, nullptr)); + } -sk_sp<SkColorSpace> SkColorSpace::NewRGB(const float gammaVals[3], const SkMatrix44& toXYZD50) { - return SkColorSpace_Base::NewRGB(gammaVals, toXYZD50, nullptr); + return SkColorSpace_Base::NewRGB(gammaNamed, toXYZD50, nullptr); } -sk_sp<SkColorSpace> SkColorSpace_Base::NewRGB(const float gammaVals[3], const SkMatrix44& toXYZD50, +sk_sp<SkColorSpace> SkColorSpace_Base::NewRGB(GammaNamed gammaNamed, const SkMatrix44& toXYZD50, sk_sp<SkData> profileData) { - sk_sp<SkGammas> gammas = nullptr; - GammaNamed gammaNamed = kNonStandard_GammaNamed; - - // Check if we really have sRGB or Adobe RGB - if (color_space_almost_equal(2.2f, gammaVals[0]) && - color_space_almost_equal(2.2f, gammaVals[1]) && - color_space_almost_equal(2.2f, gammaVals[2])) - { - g2Dot2CurveGammasOnce([] { - g2Dot2CurveGammas = new SkGammas(2.2f, 2.2f, 2.2f); - }); - gammas = sk_ref_sp(g2Dot2CurveGammas); - gammaNamed = k2Dot2Curve_GammaNamed; - - if (xyz_almost_equal(toXYZD50, gSRGB_toXYZD50)) { - return SkColorSpace::NewNamed(kSRGB_Named); - } else if (xyz_almost_equal(toXYZD50, gAdobeRGB_toXYZD50)) { - return SkColorSpace::NewNamed(kAdobeRGB_Named); - } - } else if (color_space_almost_equal(1.0f, gammaVals[0]) && - color_space_almost_equal(1.0f, gammaVals[1]) && - color_space_almost_equal(1.0f, gammaVals[2])) - { - gLinearGammasOnce([] { - gLinearGammas = new SkGammas(1.0f, 1.0f, 1.0f); - }); - gammas = sk_ref_sp(gLinearGammas); - gammaNamed = kLinear_GammaNamed; + switch (gammaNamed) { + case kSRGB_GammaNamed: + if (xyz_almost_equal(toXYZD50, gSRGB_toXYZD50)) { + return SkColorSpace::NewNamed(kSRGB_Named); + } + break; + case k2Dot2Curve_GammaNamed: + if (xyz_almost_equal(toXYZD50, gAdobeRGB_toXYZD50)) { + return SkColorSpace::NewNamed(kAdobeRGB_Named); + } + break; + case kNonStandard_GammaNamed: + // This is not allowed. + return nullptr; + default: + break; } - if (!gammas) { - gammas = sk_sp<SkGammas>(new SkGammas(gammaVals[0], gammaVals[1], gammaVals[2])); - } - return sk_sp<SkColorSpace>(new SkColorSpace_Base(gammas, gammaNamed, toXYZD50, kUnknown_Named, - std::move(profileData))); + return sk_sp<SkColorSpace>(new SkColorSpace_Base(gammaNamed, toXYZD50, kUnknown_Named, + profileData)); +} + +sk_sp<SkColorSpace> SkColorSpace::NewRGB(GammaNamed gammaNamed, const SkMatrix44& toXYZD50) { + return SkColorSpace_Base::NewRGB(gammaNamed, toXYZD50, nullptr); } sk_sp<SkColorSpace> SkColorSpace::NewNamed(Named named) { @@ -138,28 +141,18 @@ sk_sp<SkColorSpace> SkColorSpace::NewNamed(Named named) { switch (named) { case kSRGB_Named: { - g2Dot2CurveGammasOnce([] { - g2Dot2CurveGammas = new SkGammas(2.2f, 2.2f, 2.2f); - }); - sRGBOnce([] { SkMatrix44 srgbToxyzD50(SkMatrix44::kUninitialized_Constructor); srgbToxyzD50.set3x3ColMajorf(gSRGB_toXYZD50); - sRGB = new SkColorSpace_Base(sk_ref_sp(g2Dot2CurveGammas), k2Dot2Curve_GammaNamed, - srgbToxyzD50, kSRGB_Named, nullptr); + sRGB = new SkColorSpace_Base(kSRGB_GammaNamed, srgbToxyzD50, kSRGB_Named, nullptr); }); return sk_ref_sp(sRGB); } case kAdobeRGB_Named: { - g2Dot2CurveGammasOnce([] { - g2Dot2CurveGammas = new SkGammas(2.2f, 2.2f, 2.2f); - }); - adobeRGBOnce([] { SkMatrix44 adobergbToxyzD50(SkMatrix44::kUninitialized_Constructor); adobergbToxyzD50.set3x3ColMajorf(gAdobeRGB_toXYZD50); - adobeRGB = new SkColorSpace_Base(sk_ref_sp(g2Dot2CurveGammas), - k2Dot2Curve_GammaNamed, adobergbToxyzD50, + adobeRGB = new SkColorSpace_Base(k2Dot2Curve_GammaNamed, adobergbToxyzD50, kAdobeRGB_Named, nullptr); }); return sk_ref_sp(adobeRGB); @@ -175,8 +168,6 @@ sk_sp<SkColorSpace> SkColorSpace::NewNamed(Named named) { #include "SkFixed.h" #include "SkTemplates.h" -#define SkColorSpacePrintf(...) - #define return_if_false(pred, msg) \ do { \ if (!(pred)) { \ @@ -370,7 +361,7 @@ static constexpr uint32_t kTAG_gTRC = SkSetFourByteTag('g', 'T', 'R', 'C'); static constexpr uint32_t kTAG_bTRC = SkSetFourByteTag('b', 'T', 'R', 'C'); static constexpr uint32_t kTAG_A2B0 = SkSetFourByteTag('A', '2', 'B', '0'); -bool load_xyz(float dst[3], const uint8_t* src, size_t len) { +static bool load_xyz(float dst[3], const uint8_t* src, size_t len) { if (len < 20) { SkColorSpacePrintf("XYZ tag is too small (%d bytes)", len); return false; @@ -386,7 +377,7 @@ bool load_xyz(float dst[3], const uint8_t* src, size_t len) { static constexpr uint32_t kTAG_CurveType = SkSetFourByteTag('c', 'u', 'r', 'v'); static constexpr uint32_t kTAG_ParaCurveType = SkSetFourByteTag('p', 'a', 'r', 'a'); -bool load_gammas(SkGammaCurve* gammas, uint32_t numGammas, const uint8_t* src, size_t len) { +static bool load_gammas(SkGammaCurve* gammas, uint32_t numGammas, const uint8_t* src, size_t len) { for (uint32_t i = 0; i < numGammas; i++) { if (len < 12) { // FIXME (msarett): @@ -418,7 +409,7 @@ bool load_gammas(SkGammaCurve* gammas, uint32_t numGammas, const uint8_t* src, s // Some tags require a gamma curve, but the author doesn't actually want // to transform the data. In this case, it is common to see a curve with // a count of 0. - gammas[i].fValue = 1.0f; + gammas[i].fNamed = SkColorSpace::kLinear_GammaNamed; break; } else if (len < tagBytes) { SkColorSpacePrintf("gamma tag is too small (%d bytes)", len); @@ -428,20 +419,16 @@ bool load_gammas(SkGammaCurve* gammas, uint32_t numGammas, const uint8_t* src, s const uint16_t* table = (const uint16_t*) (src + 12); if (1 == count) { // The table entry is the gamma (with a bias of 256). - uint16_t value = read_big_endian_short((const uint8_t*) table); - gammas[i].fValue = value / 256.0f; - if (0.0f == gammas[i].fValue) { - SkColorSpacePrintf("Cannot have zero gamma value"); - return false; - } - SkColorSpacePrintf("gamma %d %g\n", value, gammas[i].fValue); + float value = (read_big_endian_short((const uint8_t*) table)) / 256.0f; + set_gamma_value(&gammas[i], value); + SkColorSpacePrintf("gamma %g\n", value); break; } - // Check for frequently occurring curves and use a fast approximation. + // Check for frequently occurring sRGB curves. // We do this by sampling a few values and see if they match our expectation. // A more robust solution would be to compare each value in this curve against - // a 2.2f curve see if we remain below an error threshold. At this time, + // an sRGB curve to see if we remain below an error threshold. At this time, // we haven't seen any images in the wild that make this kind of // calculation necessary. We encounter identical gamma curves over and // over again, but relatively few variations. @@ -454,7 +441,7 @@ bool load_gammas(SkGammaCurve* gammas, uint32_t numGammas, const uint8_t* src, s 14116 == read_big_endian_short((const uint8_t*) &table[513]) && 34318 == read_big_endian_short((const uint8_t*) &table[768]) && 65535 == read_big_endian_short((const uint8_t*) &table[1023])) { - gammas[i].fValue = 2.2f; + gammas[i].fNamed = SkColorSpace::kSRGB_GammaNamed; break; } } else if (26 == count) { @@ -465,7 +452,7 @@ bool load_gammas(SkGammaCurve* gammas, uint32_t numGammas, const uint8_t* src, s 12824 == read_big_endian_short((const uint8_t*) &table[12]) && 31237 == read_big_endian_short((const uint8_t*) &table[18]) && 65535 == read_big_endian_short((const uint8_t*) &table[25])) { - gammas[i].fValue = 2.2f; + gammas[i].fNamed = SkColorSpace::kSRGB_GammaNamed; break; } } else if (4096 == count) { @@ -476,7 +463,7 @@ bool load_gammas(SkGammaCurve* gammas, uint32_t numGammas, const uint8_t* src, s 3342 == read_big_endian_short((const uint8_t*) &table[1025]) && 14079 == read_big_endian_short((const uint8_t*) &table[2051]) && 65535 == read_big_endian_short((const uint8_t*) &table[4095])) { - gammas[i].fValue = 2.2f; + gammas[i].fNamed = SkColorSpace::kSRGB_GammaNamed; break; } } @@ -510,7 +497,7 @@ bool load_gammas(SkGammaCurve* gammas, uint32_t numGammas, const uint8_t* src, s // Y = X^g int32_t g = read_big_endian_int(src + 12); - gammas[i].fValue = SkFixedToFloat(g); + set_gamma_value(&gammas[i], SkFixedToFloat(g)); } else { // Here's where the real parametric gammas start. There are many // permutations of the same equations. @@ -607,7 +594,7 @@ bool load_gammas(SkGammaCurve* gammas, uint32_t numGammas, const uint8_t* src, s color_space_almost_equal(0.0774f, e) && color_space_almost_equal(0.0000f, f) && color_space_almost_equal(2.4000f, g)) { - gammas[i].fValue = 2.2f; + gammas[i].fNamed = SkColorSpace::kSRGB_GammaNamed; } else { // Fail on invalid gammas. if (d <= 0.0f) { @@ -648,7 +635,8 @@ bool load_gammas(SkGammaCurve* gammas, uint32_t numGammas, const uint8_t* src, s } // Ensure that we have successfully read a gamma representation. - SkASSERT(gammas[i].isValue() || gammas[i].isTable() || gammas[i].isParametric()); + SkASSERT(gammas[i].isNamed() || gammas[i].isValue() || gammas[i].isTable() || + gammas[i].isParametric()); // Adjust src and len if there is another gamma curve to load. if (i != numGammas - 1) { @@ -796,7 +784,10 @@ bool load_a2b0(SkColorLookUpTable* colorLUT, SkGammaCurve* gammas, SkMatrix44* t uint32_t offsetToMCurves = read_big_endian_int(src + 20); if (0 != offsetToMCurves && offsetToMCurves < len) { if (!load_gammas(gammas, outputChannels, src + offsetToMCurves, len - offsetToMCurves)) { - SkColorSpacePrintf("Failed to read M curves from A to B tag.\n"); + SkColorSpacePrintf("Failed to read M curves from A to B tag. Using linear gamma.\n"); + gammas[0].fNamed = SkColorSpace::kLinear_GammaNamed; + gammas[1].fNamed = SkColorSpace::kLinear_GammaNamed; + gammas[2].fNamed = SkColorSpace::kLinear_GammaNamed; } } @@ -804,6 +795,7 @@ bool load_a2b0(SkColorLookUpTable* colorLUT, SkGammaCurve* gammas, SkMatrix44* t if (0 != offsetToMatrix && offsetToMatrix < len) { if (!load_matrix(toXYZ, src + offsetToMatrix, len - offsetToMatrix)) { SkColorSpacePrintf("Failed to read matrix from A to B tag.\n"); + toXYZ->setIdentity(); } } @@ -872,6 +864,8 @@ sk_sp<SkColorSpace> SkColorSpace::NewICC(const void* input, size_t len) { { return_null("Need valid rgb tags for XYZ space"); } + SkMatrix44 mat(SkMatrix44::kUninitialized_Constructor); + mat.set3x3ColMajorf(toXYZ); // It is not uncommon to see missing or empty gamma tags. This indicates // that we should use unit gamma. @@ -882,32 +876,28 @@ sk_sp<SkColorSpace> SkColorSpace::NewICC(const void* input, size_t len) { if (!r || !load_gammas(&curves[0], 1, r->addr((const uint8_t*) base), r->fLength)) { SkColorSpacePrintf("Failed to read R gamma tag.\n"); + curves[0].fNamed = SkColorSpace::kLinear_GammaNamed; } if (!g || !load_gammas(&curves[1], 1, g->addr((const uint8_t*) base), g->fLength)) { SkColorSpacePrintf("Failed to read G gamma tag.\n"); + curves[1].fNamed = SkColorSpace::kLinear_GammaNamed; } if (!b || !load_gammas(&curves[2], 1, b->addr((const uint8_t*) base), b->fLength)) { SkColorSpacePrintf("Failed to read B gamma tag.\n"); + curves[2].fNamed = SkColorSpace::kLinear_GammaNamed; } - sk_sp<SkGammas> gammas(new SkGammas(std::move(curves[0]), std::move(curves[1]), - std::move(curves[2]))); - SkMatrix44 mat(SkMatrix44::kUninitialized_Constructor); - mat.set3x3ColMajorf(toXYZ); - if (gammas->isValues()) { - // When we have values, take advantage of the NewFromRGB initializer. - // This allows us to check for canonical sRGB and Adobe RGB. - float gammaVals[3]; - gammaVals[0] = gammas->fRed.fValue; - gammaVals[1] = gammas->fGreen.fValue; - gammaVals[2] = gammas->fBlue.fValue; - return SkColorSpace_Base::NewRGB(gammaVals, mat, std::move(data)); + GammaNamed gammaNamed = SkGammas::Named(curves); + if (kNonStandard_GammaNamed == gammaNamed) { + sk_sp<SkGammas> gammas = sk_make_sp<SkGammas>(std::move(curves[0]), + std::move(curves[1]), + std::move(curves[2])); + return sk_sp<SkColorSpace>(new SkColorSpace_Base(nullptr, std::move(gammas), + mat, std::move(data))); } else { - return sk_sp<SkColorSpace>(new SkColorSpace_Base(std::move(gammas), mat, - kUnknown_Named, - std::move(data))); + return SkColorSpace_Base::NewRGB(gammaNamed, mat, std::move(data)); } } @@ -922,24 +912,17 @@ sk_sp<SkColorSpace> SkColorSpace::NewICC(const void* input, size_t len) { return_null("Failed to parse A2B0 tag"); } - sk_sp<SkGammas> gammas(new SkGammas(std::move(curves[0]), std::move(curves[1]), - std::move(curves[2]))); - if (colorLUT->fTable) { + GammaNamed gammaNamed = SkGammas::Named(curves); + if (colorLUT->fTable || kNonStandard_GammaNamed == gammaNamed) { + sk_sp<SkGammas> gammas = sk_make_sp<SkGammas>(std::move(curves[0]), + std::move(curves[1]), + std::move(curves[2])); + return sk_sp<SkColorSpace>(new SkColorSpace_Base(colorLUT.release(), std::move(gammas), toXYZ, std::move(data))); - } else if (gammas->isValues()) { - // When we have values, take advantage of the NewFromRGB initializer. - // This allows us to check for canonical sRGB and Adobe RGB. - float gammaVals[3]; - gammaVals[0] = gammas->fRed.fValue; - gammaVals[1] = gammas->fGreen.fValue; - gammaVals[2] = gammas->fBlue.fValue; - return SkColorSpace_Base::NewRGB(gammaVals, toXYZ, std::move(data)); } else { - return sk_sp<SkColorSpace>(new SkColorSpace_Base(std::move(gammas), toXYZ, - kUnknown_Named, - std::move(data))); + return SkColorSpace_Base::NewRGB(gammaNamed, toXYZ, std::move(data)); } } } @@ -1079,6 +1062,23 @@ static void write_trc_tag(uint32_t* ptr, float value) { ptr16[1] = 0; } +static float get_gamma_value(const SkGammaCurve* curve) { + switch (curve->fNamed) { + case SkColorSpace::kSRGB_GammaNamed: + // FIXME (msarett): + // kSRGB cannot be represented by a value. Here we fall through to 2.2f, + // which is a close guess. To be more accurate, we need to represent sRGB + // gamma with a parametric curve. + case SkColorSpace::k2Dot2Curve_GammaNamed: + return 2.2f; + case SkColorSpace::kLinear_GammaNamed: + return 1.0f; + default: + SkASSERT(curve->isValue()); + return curve->fValue; + } +} + sk_sp<SkData> SkColorSpace_Base::writeToICC() const { // Return if this object was created from a profile, or if we have already serialized // the profile. @@ -1120,15 +1120,42 @@ sk_sp<SkData> SkColorSpace_Base::writeToICC() const { ptr += kTAG_XYZ_Bytes; // Write TRC tags - SkASSERT(as_CSB(this)->fGammas->fRed.isValue()); - write_trc_tag((uint32_t*) ptr, as_CSB(this)->fGammas->fRed.fValue); - ptr += SkAlign4(kTAG_TRC_Bytes); - SkASSERT(as_CSB(this)->fGammas->fGreen.isValue()); - write_trc_tag((uint32_t*) ptr, as_CSB(this)->fGammas->fGreen.fValue); - ptr += SkAlign4(kTAG_TRC_Bytes); - SkASSERT(as_CSB(this)->fGammas->fBlue.isValue()); - write_trc_tag((uint32_t*) ptr, as_CSB(this)->fGammas->fBlue.fValue); - ptr += SkAlign4(kTAG_TRC_Bytes); + GammaNamed gammaNamed = this->gammaNamed(); + if (kNonStandard_GammaNamed == gammaNamed) { + write_trc_tag((uint32_t*) ptr, get_gamma_value(&as_CSB(this)->fGammas->fRed)); + ptr += SkAlign4(kTAG_TRC_Bytes); + write_trc_tag((uint32_t*) ptr, get_gamma_value(&as_CSB(this)->fGammas->fGreen)); + ptr += SkAlign4(kTAG_TRC_Bytes); + write_trc_tag((uint32_t*) ptr, get_gamma_value(&as_CSB(this)->fGammas->fBlue)); + ptr += SkAlign4(kTAG_TRC_Bytes); + } else { + switch (gammaNamed) { + case SkColorSpace::kSRGB_GammaNamed: + // FIXME (msarett): + // kSRGB cannot be represented by a value. Here we fall through to 2.2f, + // which is a close guess. To be more accurate, we need to represent sRGB + // gamma with a parametric curve. + case SkColorSpace::k2Dot2Curve_GammaNamed: + write_trc_tag((uint32_t*) ptr, 2.2f); + ptr += SkAlign4(kTAG_TRC_Bytes); + write_trc_tag((uint32_t*) ptr, 2.2f); + ptr += SkAlign4(kTAG_TRC_Bytes); + write_trc_tag((uint32_t*) ptr, 2.2f); + ptr += SkAlign4(kTAG_TRC_Bytes); + break; + case SkColorSpace::kLinear_GammaNamed: + write_trc_tag((uint32_t*) ptr, 1.0f); + ptr += SkAlign4(kTAG_TRC_Bytes); + write_trc_tag((uint32_t*) ptr, 1.0f); + ptr += SkAlign4(kTAG_TRC_Bytes); + write_trc_tag((uint32_t*) ptr, 1.0f); + ptr += SkAlign4(kTAG_TRC_Bytes); + break; + default: + SkASSERT(false); + break; + } + } // Write white point tag uint32_t* ptr32 = (uint32_t*) ptr; diff --git a/src/core/SkColorSpaceXform.cpp b/src/core/SkColorSpaceXform.cpp index 0faff88286..e142011305 100644 --- a/src/core/SkColorSpaceXform.cpp +++ b/src/core/SkColorSpaceXform.cpp @@ -152,22 +152,27 @@ void SkDefaultXform::xform_RGBA_8888(uint32_t* dst, const uint32_t* src, uint32_ // be simpler and faster than our current approach. float srcFloats[3]; for (int i = 0; i < 3; i++) { - const SkGammaCurve& gamma = (*fSrcGammas)[i]; uint8_t byte = (*src >> (8 * i)) & 0xFF; - if (gamma.isValue()) { - srcFloats[i] = pow(byte_to_float(byte), gamma.fValue); - } else if (gamma.isTable()) { - srcFloats[i] = interp_lut(byte, gamma.fTable.get(), gamma.fTableSize); - } else { - SkASSERT(gamma.isParametric()); - float component = byte_to_float(byte); - if (component < gamma.fD) { - // Y = E * X + F - srcFloats[i] = gamma.fE * component + gamma.fF; + if (fSrcGammas) { + const SkGammaCurve& gamma = (*fSrcGammas)[i]; + if (gamma.isValue()) { + srcFloats[i] = powf(byte_to_float(byte), gamma.fValue); + } else if (gamma.isTable()) { + srcFloats[i] = interp_lut(byte, gamma.fTable.get(), gamma.fTableSize); } else { - // Y = (A * X + B)^G + C - srcFloats[i] = pow(gamma.fA * component + gamma.fB, gamma.fG) + gamma.fC; + SkASSERT(gamma.isParametric()); + float component = byte_to_float(byte); + if (component < gamma.fD) { + // Y = E * X + F + srcFloats[i] = gamma.fE * component + gamma.fF; + } else { + // Y = (A * X + B)^G + C + srcFloats[i] = powf(gamma.fA * component + gamma.fB, gamma.fG) + gamma.fC; + } } + } else { + // FIXME: Handle named gammas. + srcFloats[i] = powf(byte_to_float(byte), 2.2f); } } @@ -189,48 +194,54 @@ void SkDefaultXform::xform_RGBA_8888(uint32_t* dst, const uint32_t* src, uint32_ // QCMS builds a large float lookup table from the gamma info. Is this faster or // better than our approach? for (int i = 0; i < 3; i++) { - const SkGammaCurve& gamma = (*fDstGammas)[i]; - if (gamma.isValue()) { - dstFloats[i] = pow(dstFloats[i], 1.0f / gamma.fValue); - } else if (gamma.isTable()) { - // FIXME (msarett): - // An inverse table lookup is particularly strange and non-optimal. - dstFloats[i] = interp_lut_inv(dstFloats[i], gamma.fTable.get(), gamma.fTableSize); - } else { - SkASSERT(gamma.isParametric()); - // FIXME (msarett): - // This is a placeholder implementation for inverting parametric gammas. - // First, I need to verify if there are actually destination profiles that - // require this functionality. Next, I need to explore other possibilities - // for this implementation. The LUT based approach in QCMS would be a good - // place to start. - - // We need to take the inverse of a piecewise function. Assume that - // the gamma function is continuous, or this won't make much sense - // anyway. - // Plug in |fD| to the first equation to calculate the new piecewise - // interval. Then simply use the inverse of the original functions. - float interval = gamma.fE * gamma.fD + gamma.fF; - if (dstFloats[i] < interval) { - // X = (Y - F) / E - if (0.0f == gamma.fE) { - // The gamma curve for this segment is constant, so the inverse - // is undefined. - dstFloats[i] = 0.0f; - } else { - dstFloats[i] = (dstFloats[i] - gamma.fF) / gamma.fE; - } + if (fDstGammas) { + const SkGammaCurve& gamma = (*fDstGammas)[i]; + if (gamma.isValue()) { + dstFloats[i] = powf(dstFloats[i], 1.0f / gamma.fValue); + } else if (gamma.isTable()) { + // FIXME (msarett): + // An inverse table lookup is particularly strange and non-optimal. + dstFloats[i] = interp_lut_inv(dstFloats[i], gamma.fTable.get(), + gamma.fTableSize); } else { - // X = ((Y - C)^(1 / G) - B) / A - if (0.0f == gamma.fA || 0.0f == gamma.fG) { - // The gamma curve for this segment is constant, so the inverse - // is undefined. - dstFloats[i] = 0.0f; + SkASSERT(gamma.isParametric()); + // FIXME (msarett): + // This is a placeholder implementation for inverting parametric gammas. + // First, I need to verify if there are actually destination profiles that + // require this functionality. Next, I need to explore other possibilities + // for this implementation. The LUT based approach in QCMS would be a good + // place to start. + + // We need to take the inverse of a piecewise function. Assume that + // the gamma function is continuous, or this won't make much sense + // anyway. + // Plug in |fD| to the first equation to calculate the new piecewise + // interval. Then simply use the inverse of the original functions. + float interval = gamma.fE * gamma.fD + gamma.fF; + if (dstFloats[i] < interval) { + // X = (Y - F) / E + if (0.0f == gamma.fE) { + // The gamma curve for this segment is constant, so the inverse + // is undefined. + dstFloats[i] = 0.0f; + } else { + dstFloats[i] = (dstFloats[i] - gamma.fF) / gamma.fE; + } } else { - dstFloats[i] = (pow(dstFloats[i] - gamma.fC, 1.0f / gamma.fG) - gamma.fB) - / gamma.fA; + // X = ((Y - C)^(1 / G) - B) / A + if (0.0f == gamma.fA || 0.0f == gamma.fG) { + // The gamma curve for this segment is constant, so the inverse + // is undefined. + dstFloats[i] = 0.0f; + } else { + dstFloats[i] = (powf(dstFloats[i] - gamma.fC, 1.0f / gamma.fG) - + gamma.fB) / gamma.fA; + } } } + } else { + // FIXME: Handle named gammas. + dstFloats[i] = powf(dstFloats[i], 1.0f / 2.2f); } } diff --git a/src/core/SkColorSpace_Base.h b/src/core/SkColorSpace_Base.h index ffab17a1fd..fc4f665e68 100644 --- a/src/core/SkColorSpace_Base.h +++ b/src/core/SkColorSpace_Base.h @@ -13,8 +13,17 @@ #include "SkTemplates.h" struct SkGammaCurve { + bool isNamed() const { + bool result = (SkColorSpace::kNonStandard_GammaNamed != fNamed); + SkASSERT(!result || (0.0f == fValue)); + SkASSERT(!result || (0 == fTableSize)); + SkASSERT(!result || (0.0f == fG && 0.0f == fE)); + return result; + } + bool isValue() const { bool result = (0.0f != fValue); + SkASSERT(!result || SkColorSpace::kNonStandard_GammaNamed == fNamed); SkASSERT(!result || (0 == fTableSize)); SkASSERT(!result || (0.0f == fG && 0.0f == fE)); return result; @@ -22,6 +31,7 @@ struct SkGammaCurve { bool isTable() const { bool result = (0 != fTableSize); + SkASSERT(!result || SkColorSpace::kNonStandard_GammaNamed == fNamed); SkASSERT(!result || (0.0f == fValue)); SkASSERT(!result || (0.0f == fG && 0.0f == fE)); SkASSERT(!result || fTable); @@ -30,20 +40,24 @@ struct SkGammaCurve { bool isParametric() const { bool result = (0.0f != fG || 0.0f != fE); + SkASSERT(!result || SkColorSpace::kNonStandard_GammaNamed == fNamed); SkASSERT(!result || (0.0f == fValue)); SkASSERT(!result || (0 == fTableSize)); return result; } - // We have three different ways to represent gamma. - // (1) A single value: + // We have four different ways to represent gamma. + // (1) A known, named type: + SkColorSpace::GammaNamed fNamed; + + // (2) A single value: float fValue; - // (2) A lookup table: + // (3) A lookup table: uint32_t fTableSize; std::unique_ptr<float[]> fTable; - // (3) Parameters for a curve: + // (4) Parameters for a curve: // Y = (aX + b)^g + c for X >= d // Y = eX + f otherwise float fG; @@ -54,12 +68,9 @@ struct SkGammaCurve { float fE; float fF; - SkGammaCurve() { - memset(this, 0, sizeof(struct SkGammaCurve)); - } - - SkGammaCurve(float value) - : fValue(value) + SkGammaCurve() + : fNamed(SkColorSpace::kNonStandard_GammaNamed) + , fValue(0.0f) , fTableSize(0) , fTable(nullptr) , fG(0.0f) @@ -74,8 +85,29 @@ struct SkGammaCurve { struct SkGammas : public SkRefCnt { public: - bool isValues() const { - return fRed.isValue() && fGreen.isValue() && fBlue.isValue(); + static SkColorSpace::GammaNamed Named(SkGammaCurve curves[3]) { + if (SkColorSpace::kLinear_GammaNamed == curves[0].fNamed && + SkColorSpace::kLinear_GammaNamed == curves[1].fNamed && + SkColorSpace::kLinear_GammaNamed == curves[2].fNamed) + { + return SkColorSpace::kLinear_GammaNamed; + } + + if (SkColorSpace::kSRGB_GammaNamed == curves[0].fNamed && + SkColorSpace::kSRGB_GammaNamed == curves[1].fNamed && + SkColorSpace::kSRGB_GammaNamed == curves[2].fNamed) + { + return SkColorSpace::kSRGB_GammaNamed; + } + + if (SkColorSpace::k2Dot2Curve_GammaNamed == curves[0].fNamed && + SkColorSpace::k2Dot2Curve_GammaNamed == curves[1].fNamed && + SkColorSpace::k2Dot2Curve_GammaNamed == curves[2].fNamed) + { + return SkColorSpace::k2Dot2Curve_GammaNamed; + } + + return SkColorSpace::kNonStandard_GammaNamed; } const SkGammaCurve& operator[](int i) { @@ -87,12 +119,6 @@ public: const SkGammaCurve fGreen; const SkGammaCurve fBlue; - SkGammas(float red, float green, float blue) - : fRed(red) - , fGreen(green) - , fBlue(blue) - {} - SkGammas(SkGammaCurve red, SkGammaCurve green, SkGammaCurve blue) : fRed(std::move(red)) , fGreen(std::move(green)) @@ -120,6 +146,8 @@ struct SkColorLookUpTable { class SkColorSpace_Base : public SkColorSpace { public: + static sk_sp<SkColorSpace> NewRGB(float gammas[3], const SkMatrix44& toXYZD50); + const sk_sp<SkGammas>& gammas() const { return fGammas; } SkColorLookUpTable* colorLUT() const { return fColorLUT.get(); } @@ -131,17 +159,14 @@ public: private: - static sk_sp<SkColorSpace> NewRGB(const float gammas[3], const SkMatrix44& toXYZD50, + static sk_sp<SkColorSpace> NewRGB(GammaNamed gammaNamed, const SkMatrix44& toXYZD50, sk_sp<SkData> profileData); - SkColorSpace_Base(sk_sp<SkGammas> gammas, const SkMatrix44& toXYZ, Named, + SkColorSpace_Base(GammaNamed gammaNamed, const SkMatrix44& toXYZ, Named named, sk_sp<SkData> profileData); - SkColorSpace_Base(sk_sp<SkGammas> gammas, GammaNamed gammaNamed, const SkMatrix44& toXYZ, - Named, sk_sp<SkData> profileData); - - SkColorSpace_Base(SkColorLookUpTable* colorLUT, sk_sp<SkGammas> gammas, - const SkMatrix44& toXYZ, sk_sp<SkData> profileData); + SkColorSpace_Base(SkColorLookUpTable* colorLUT, sk_sp<SkGammas> gammas, const SkMatrix44& toXYZ, + sk_sp<SkData> profileData); SkAutoTDelete<SkColorLookUpTable> fColorLUT; sk_sp<SkGammas> fGammas; diff --git a/src/core/SkMipMap.cpp b/src/core/SkMipMap.cpp index 69c8466f69..b9302cdb68 100644 --- a/src/core/SkMipMap.cpp +++ b/src/core/SkMipMap.cpp @@ -306,7 +306,7 @@ size_t SkMipMap::AllocLevelsSize(int levelCount, size_t pixelSize) { static bool treat_like_srgb(const SkImageInfo& info) { if (info.colorSpace()) { - return SkColorSpace::k2Dot2Curve_GammaNamed == info.colorSpace()->gammaNamed(); + return info.colorSpace()->gammaCloseToSRGB(); } else { return kSRGB_SkColorProfileType == info.profileType(); } diff --git a/tests/ColorSpaceTest.cpp b/tests/ColorSpaceTest.cpp index 6dd4789a8e..b06dc642fb 100644 --- a/tests/ColorSpaceTest.cpp +++ b/tests/ColorSpaceTest.cpp @@ -19,12 +19,9 @@ static bool almost_equal(float a, float b) { static void test_space(skiatest::Reporter* r, SkColorSpace* space, const float red[], const float green[], const float blue[], - const float expectedGammas[]) { + const SkColorSpace::GammaNamed expectedGamma) { - const sk_sp<SkGammas>& gammas = as_CSB(space)->gammas(); - REPORTER_ASSERT(r, almost_equal(expectedGammas[0], gammas->fRed.fValue)); - REPORTER_ASSERT(r, almost_equal(expectedGammas[1], gammas->fGreen.fValue)); - REPORTER_ASSERT(r, almost_equal(expectedGammas[2], gammas->fBlue.fValue)); + REPORTER_ASSERT(r, expectedGamma == space->gammaNamed()); SkMatrix44 mat = space->xyz(); @@ -46,11 +43,9 @@ const float g_sRGB_XYZ[] = { 0.4358f, 0.2224f, 0.0139f, // R 0.3853f, 0.7170f, 0.0971f, // G 0.1430f, 0.0606f, 0.7139f }; // B -const float g_sRGB_gamma[] = { 2.2f, 2.2f, 2.2f }; - DEF_TEST(ColorSpace_sRGB, r) { test_space(r, SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named).get(), - g_sRGB_XYZ, &g_sRGB_XYZ[3], &g_sRGB_XYZ[6], g_sRGB_gamma); + g_sRGB_XYZ, &g_sRGB_XYZ[3], &g_sRGB_XYZ[6], SkColorSpace::kSRGB_GammaNamed); } @@ -73,7 +68,8 @@ DEF_TEST(ColorSpaceParsePngICCProfile, r) { SkColorSpace* colorSpace = codec->getColorSpace(); REPORTER_ASSERT(r, nullptr != colorSpace); - test_space(r, colorSpace, &g_sRGB_XYZ[0], &g_sRGB_XYZ[3], &g_sRGB_XYZ[6], g_sRGB_gamma); + test_space(r, colorSpace, &g_sRGB_XYZ[0], &g_sRGB_XYZ[3], &g_sRGB_XYZ[6], + SkColorSpace::kSRGB_GammaNamed); #endif } @@ -96,7 +92,7 @@ DEF_TEST(ColorSpaceParseJpegICCProfile, r) { const float red[] = { 0.385117f, 0.716904f, 0.0970612f }; const float green[] = { 0.143051f, 0.0606079f, 0.713913f }; const float blue[] = { 0.436035f, 0.222488f, 0.013916f }; - test_space(r, colorSpace, red, green, blue, g_sRGB_gamma); + test_space(r, colorSpace, red, green, blue, SkColorSpace::k2Dot2Curve_GammaNamed); } DEF_TEST(ColorSpaceSRGBCompare, r) { @@ -106,12 +102,14 @@ DEF_TEST(ColorSpaceSRGBCompare, r) { // Create an sRGB color space by value SkMatrix44 srgbToxyzD50(SkMatrix44::kUninitialized_Constructor); srgbToxyzD50.set3x3ColMajorf(g_sRGB_XYZ); - sk_sp<SkColorSpace> rgbColorSpace = SkColorSpace::NewRGB(g_sRGB_gamma, srgbToxyzD50); + sk_sp<SkColorSpace> rgbColorSpace = SkColorSpace::NewRGB(SkColorSpace::kSRGB_GammaNamed, + srgbToxyzD50); REPORTER_ASSERT(r, rgbColorSpace == namedColorSpace); // Change a single value from the sRGB matrix srgbToxyzD50.set(2, 2, 0.5f); - sk_sp<SkColorSpace> strangeColorSpace = SkColorSpace::NewRGB(g_sRGB_gamma, srgbToxyzD50); + sk_sp<SkColorSpace> strangeColorSpace = SkColorSpace::NewRGB(SkColorSpace::kSRGB_GammaNamed, + srgbToxyzD50); REPORTER_ASSERT(r, strangeColorSpace != namedColorSpace); } @@ -120,8 +118,10 @@ DEF_TEST(ColorSpaceWriteICC, r) { sk_sp<SkColorSpace> namedColorSpace = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named); sk_sp<SkData> namedData = as_CSB(namedColorSpace)->writeToICC(); sk_sp<SkColorSpace> iccColorSpace = SkColorSpace::NewICC(namedData->data(), namedData->size()); - test_space(r, iccColorSpace.get(), g_sRGB_XYZ, &g_sRGB_XYZ[3], &g_sRGB_XYZ[6], g_sRGB_gamma); - REPORTER_ASSERT(r, iccColorSpace == namedColorSpace); + test_space(r, iccColorSpace.get(), g_sRGB_XYZ, &g_sRGB_XYZ[3], &g_sRGB_XYZ[6], + SkColorSpace::k2Dot2Curve_GammaNamed); + // FIXME (msarett): Test disabled. sRGB profiles are written approximately as 2.2f curves. + // REPORTER_ASSERT(r, iccColorSpace == namedColorSpace); // Test saving the original ICC data sk_sp<SkData> monitorData = SkData::MakeFromFileName( @@ -136,28 +136,33 @@ DEF_TEST(ColorSpaceWriteICC, r) { sk_sp<SkColorSpace> newMonitorSpace = SkColorSpace::NewICC(newMonitorData->data(), newMonitorData->size()); REPORTER_ASSERT(r, monitorSpace->xyz() == newMonitorSpace->xyz()); - REPORTER_ASSERT(r, as_CSB(monitorSpace)->gammas() == as_CSB(newMonitorSpace)->gammas()); + REPORTER_ASSERT(r, monitorSpace->gammaNamed() == newMonitorSpace->gammaNamed()); } DEF_TEST(ColorSpace_Named, r) { const struct { SkColorSpace::Named fNamed; bool fExpectedToSucceed; + bool fIsSRGB; } recs[] { - { SkColorSpace::kUnknown_Named, false }, - { SkColorSpace::kSRGB_Named, true }, - { SkColorSpace::kAdobeRGB_Named, true }, + { SkColorSpace::kUnknown_Named, false, false }, + { SkColorSpace::kSRGB_Named, true, true }, + { SkColorSpace::kAdobeRGB_Named, true, false }, }; for (auto rec : recs) { auto cs = SkColorSpace::NewNamed(rec.fNamed); REPORTER_ASSERT(r, !cs == !rec.fExpectedToSucceed); if (cs) { - REPORTER_ASSERT(r, SkColorSpace::k2Dot2Curve_GammaNamed == cs->gammaNamed()); + if (rec.fIsSRGB) { + REPORTER_ASSERT(r, SkColorSpace::kSRGB_GammaNamed == cs->gammaNamed()); + } else { + REPORTER_ASSERT(r, SkColorSpace::k2Dot2Curve_GammaNamed == cs->gammaNamed()); + } } } SkImageInfo info = SkImageInfo::MakeS32(10, 10, kPremul_SkAlphaType); REPORTER_ASSERT(r, kSRGB_SkColorProfileType == info.profileType()); - REPORTER_ASSERT(r, SkColorSpace::k2Dot2Curve_GammaNamed == info.colorSpace()->gammaNamed()); + REPORTER_ASSERT(r, SkColorSpace::kSRGB_GammaNamed == info.colorSpace()->gammaNamed()); } |