diff options
-rw-r--r-- | gyp/core.gypi | 1 | ||||
-rw-r--r-- | include/core/SkColorSpace.h | 75 | ||||
-rw-r--r-- | src/core/SkColorSpace.cpp | 115 | ||||
-rw-r--r-- | src/core/SkColorSpace.h | 80 | ||||
-rw-r--r-- | src/core/SkColorSpace_Base.h (renamed from src/core/SkColorSpacePriv.h) | 32 | ||||
-rw-r--r-- | tests/ColorSpaceTest.cpp | 4 |
6 files changed, 175 insertions, 132 deletions
diff --git a/gyp/core.gypi b/gyp/core.gypi index 477a9e7108..38aa1b750e 100644 --- a/gyp/core.gypi +++ b/gyp/core.gypi @@ -76,7 +76,6 @@ '<(skia_src_path)/core/SkColorShader.cpp', '<(skia_src_path)/core/SkColorShader.h', '<(skia_src_path)/core/SkColorSpace.cpp', - '<(skia_src_path)/core/SkColorSpace.h', '<(skia_src_path)/core/SkColorTable.cpp', '<(skia_src_path)/core/SkComposeShader.cpp', '<(skia_src_path)/core/SkConfig8888.cpp', diff --git a/include/core/SkColorSpace.h b/include/core/SkColorSpace.h new file mode 100644 index 0000000000..9630fe4c25 --- /dev/null +++ b/include/core/SkColorSpace.h @@ -0,0 +1,75 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkColorSpace_DEFINED +#define SkColorSpace_DEFINED + +#include "SkMatrix44.h" +#include "SkRefCnt.h" +#include "../private/SkTemplates.h" + +class SkColorSpace : public SkRefCnt { +public: + + /** + * Common, named profiles that we can recognize. + */ + enum Named { + kUnknown_Named, + kSRGB_Named, + kAdobeRGB_Named, + }; + + /** + * Create an SkColorSpace from the src gamma and a transform from src gamut to D50 XYZ. + */ + static sk_sp<SkColorSpace> NewRGB(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. + */ + k2Dot2Curve_GammaNamed, + + /** + * Gamma is represented by a look-up table, a parametric curve, or an uncommon + * exponential curve. Or there is an additional pre-processing step before the + * applying the gamma. + */ + kNonStandard_GammaNamed, + }; + + GammaNamed gammaNamed() const { return fGammaNamed; } + + /** + * Returns the matrix used to transform src gamut to XYZ D50. + */ + SkMatrix44 xyz() const { return fToXYZD50; } + +protected: + + SkColorSpace(GammaNamed gammaNamed, const SkMatrix44& toXYZD50, Named named); + + const GammaNamed fGammaNamed; + const SkMatrix44 fToXYZD50; + const Named fNamed; +}; + +#endif diff --git a/src/core/SkColorSpace.cpp b/src/core/SkColorSpace.cpp index 52e4ced85d..e2f983f7b8 100644 --- a/src/core/SkColorSpace.cpp +++ b/src/core/SkColorSpace.cpp @@ -5,9 +5,8 @@ * found in the LICENSE file. */ -#include "SkAtomics.h" #include "SkColorSpace.h" -#include "SkColorSpacePriv.h" +#include "SkColorSpace_Base.h" #include "SkOnce.h" static bool color_space_almost_equal(float a, float b) { @@ -16,22 +15,29 @@ static bool color_space_almost_equal(float a, float b) { ////////////////////////////////////////////////////////////////////////////////////////////////// -static int32_t gUniqueColorSpaceID; - -SkColorSpace::SkColorSpace(sk_sp<SkGammas> gammas, const SkMatrix44& toXYZD50, Named named) - : fGammas(gammas) +SkColorSpace::SkColorSpace(GammaNamed gammaNamed, const SkMatrix44& toXYZD50, Named named) + : fGammaNamed(kNonStandard_GammaNamed) , fToXYZD50(toXYZD50) - , fUniqueID(sk_atomic_inc(&gUniqueColorSpaceID)) , fNamed(named) {} -SkColorSpace::SkColorSpace(SkColorLookUpTable* colorLUT, sk_sp<SkGammas> gammas, - const SkMatrix44& toXYZD50) - : fColorLUT(colorLUT) +SkColorSpace_Base::SkColorSpace_Base(sk_sp<SkGammas> gammas, const SkMatrix44& toXYZD50, + Named named) + : INHERITED(kNonStandard_GammaNamed, toXYZD50, named) + , fGammas(gammas) +{} + +SkColorSpace_Base::SkColorSpace_Base(sk_sp<SkGammas> gammas, GammaNamed gammaNamed, + const SkMatrix44& toXYZD50, Named named) + : INHERITED(gammaNamed, toXYZD50, named) + , fGammas(gammas) +{} + +SkColorSpace_Base::SkColorSpace_Base(SkColorLookUpTable* colorLUT, sk_sp<SkGammas> gammas, + const SkMatrix44& toXYZD50) + : INHERITED(kNonStandard_GammaNamed, toXYZD50, kUnknown_Named) + , fColorLUT(colorLUT) , fGammas(gammas) - , fToXYZD50(toXYZD50) - , fUniqueID(sk_atomic_inc(&gUniqueColorSpaceID)) - , fNamed(kUnknown_Named) {} const float gSRGB_toXYZD50[] { @@ -71,33 +77,46 @@ static bool xyz_almost_equal(const SkMatrix44& toXYZD50, const float* standard) color_space_almost_equal(toXYZD50.getFloat(3, 3), 1.0f); } -static SkOnce gStandardGammasOnce; -static SkGammas* gStandardGammas; +static SkOnce g2Dot2CurveGammasOnce; +static SkGammas* g2Dot2CurveGammas; +static SkOnce gLinearGammasOnce; +static SkGammas* gLinearGammas; sk_sp<SkColorSpace> SkColorSpace::NewRGB(float gammaVals[3], const SkMatrix44& toXYZD50) { 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])) { - gStandardGammasOnce([] { - gStandardGammas = new SkGammas(2.2f, 2.2f, 2.2f); + g2Dot2CurveGammasOnce([] { + g2Dot2CurveGammas = new SkGammas(2.2f, 2.2f, 2.2f); }); - gammas = sk_ref_sp(gStandardGammas); + 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; } if (!gammas) { gammas = sk_sp<SkGammas>(new SkGammas(gammaVals[0], gammaVals[1], gammaVals[2])); } - return sk_sp<SkColorSpace>(new SkColorSpace(gammas, toXYZD50, kUnknown_Named)); + return sk_sp<SkColorSpace>(new SkColorSpace_Base(gammas, gammaNamed, toXYZD50, kUnknown_Named)); } sk_sp<SkColorSpace> SkColorSpace::NewNamed(Named named) { @@ -108,27 +127,29 @@ sk_sp<SkColorSpace> SkColorSpace::NewNamed(Named named) { switch (named) { case kSRGB_Named: { - gStandardGammasOnce([] { - gStandardGammas = new SkGammas(2.2f, 2.2f, 2.2f); + g2Dot2CurveGammasOnce([] { + g2Dot2CurveGammas = new SkGammas(2.2f, 2.2f, 2.2f); }); sRGBOnce([] { SkMatrix44 srgbToxyzD50(SkMatrix44::kUninitialized_Constructor); srgbToxyzD50.set3x3ColMajorf(gSRGB_toXYZD50); - sRGB = new SkColorSpace(sk_ref_sp(gStandardGammas), srgbToxyzD50, kSRGB_Named); + sRGB = new SkColorSpace_Base(sk_ref_sp(g2Dot2CurveGammas), k2Dot2Curve_GammaNamed, + srgbToxyzD50, kSRGB_Named); }); return sk_ref_sp(sRGB); } case kAdobeRGB_Named: { - gStandardGammasOnce([] { - gStandardGammas = new SkGammas(2.2f, 2.2f, 2.2f); + g2Dot2CurveGammasOnce([] { + g2Dot2CurveGammas = new SkGammas(2.2f, 2.2f, 2.2f); }); adobeRGBOnce([] { SkMatrix44 adobergbToxyzD50(SkMatrix44::kUninitialized_Constructor); adobergbToxyzD50.set3x3ColMajorf(gAdobeRGB_toXYZD50); - adobeRGB = new SkColorSpace(sk_ref_sp(gStandardGammas), adobergbToxyzD50, - kAdobeRGB_Named); + adobeRGB = new SkColorSpace_Base(sk_ref_sp(g2Dot2CurveGammas), + k2Dot2Curve_GammaNamed, adobergbToxyzD50, + kAdobeRGB_Named); }); return sk_ref_sp(adobeRGB); } @@ -336,8 +357,7 @@ bool load_xyz(float dst[3], const uint8_t* src, size_t len) { static const uint32_t kTAG_CurveType = SkSetFourByteTag('c', 'u', 'r', 'v'); static const uint32_t kTAG_ParaCurveType = SkSetFourByteTag('p', 'a', 'r', 'a'); -bool SkColorSpace::LoadGammas(SkGammaCurve* gammas, uint32_t numGammas, const uint8_t* src, - size_t len) { +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): @@ -545,8 +565,8 @@ bool SkColorSpace::LoadGammas(SkGammaCurve* gammas, uint32_t numGammas, const ui static const uint32_t kTAG_AtoBType = SkSetFourByteTag('m', 'A', 'B', ' '); -bool SkColorSpace::LoadColorLUT(SkColorLookUpTable* colorLUT, uint32_t inputChannels, - uint32_t outputChannels, const uint8_t* src, size_t len) { +bool load_color_lut(SkColorLookUpTable* colorLUT, uint32_t inputChannels, uint32_t outputChannels, + const uint8_t* src, size_t len) { if (len < 20) { SkColorSpacePrintf("Color LUT tag is too small (%d bytes).", len); return false; @@ -620,8 +640,8 @@ bool load_matrix(SkMatrix44* toXYZ, const uint8_t* src, size_t len) { return true; } -bool SkColorSpace::LoadA2B0(SkColorLookUpTable* colorLUT, SkGammaCurve* gammas, SkMatrix44* toXYZ, - const uint8_t* src, size_t len) { +bool load_a2b0(SkColorLookUpTable* colorLUT, SkGammaCurve* gammas, SkMatrix44* toXYZ, + const uint8_t* src, size_t len) { if (len < 32) { SkColorSpacePrintf("A to B tag is too small (%d bytes).", len); return false; @@ -662,16 +682,15 @@ bool SkColorSpace::LoadA2B0(SkColorLookUpTable* colorLUT, SkGammaCurve* gammas, uint32_t offsetToColorLUT = read_big_endian_int(src + 24); if (0 != offsetToColorLUT && offsetToColorLUT < len) { - if (!SkColorSpace::LoadColorLUT(colorLUT, inputChannels, outputChannels, - src + offsetToColorLUT, len - offsetToColorLUT)) { + if (!load_color_lut(colorLUT, inputChannels, outputChannels, src + offsetToColorLUT, + len - offsetToColorLUT)) { SkColorSpacePrintf("Failed to read color LUT from A to B tag.\n"); } } uint32_t offsetToMCurves = read_big_endian_int(src + 20); if (0 != offsetToMCurves && offsetToMCurves < len) { - if (!SkColorSpace::LoadGammas(gammas, outputChannels, src + offsetToMCurves, - len - offsetToMCurves)) { + if (!load_gammas(gammas, outputChannels, src + offsetToMCurves, len - offsetToMCurves)) { SkColorSpacePrintf("Failed to read M curves from A to B tag.\n"); } } @@ -750,16 +769,16 @@ sk_sp<SkColorSpace> SkColorSpace::NewICC(const void* base, size_t len) { r = ICCTag::Find(tags.get(), tagCount, kTAG_rTRC); g = ICCTag::Find(tags.get(), tagCount, kTAG_gTRC); b = ICCTag::Find(tags.get(), tagCount, kTAG_bTRC); - if (!r || !SkColorSpace::LoadGammas(&curves[0], 1, - r->addr((const uint8_t*) base), r->fLength)) { + if (!r || !load_gammas(&curves[0], 1, r->addr((const uint8_t*) base), r->fLength)) + { SkColorSpacePrintf("Failed to read R gamma tag.\n"); } - if (!g || !SkColorSpace::LoadGammas(&curves[1], 1, - g->addr((const uint8_t*) base), g->fLength)) { + if (!g || !load_gammas(&curves[1], 1, g->addr((const uint8_t*) base), g->fLength)) + { SkColorSpacePrintf("Failed to read G gamma tag.\n"); } - if (!b || !SkColorSpace::LoadGammas(&curves[2], 1, - b->addr((const uint8_t*) base), b->fLength)) { + if (!b || !load_gammas(&curves[2], 1, b->addr((const uint8_t*) base), b->fLength)) + { SkColorSpacePrintf("Failed to read B gamma tag.\n"); } @@ -776,7 +795,7 @@ sk_sp<SkColorSpace> SkColorSpace::NewICC(const void* base, size_t len) { gammaVals[2] = gammas->fBlue.fValue; return SkColorSpace::NewRGB(gammaVals, mat); } else { - return sk_sp<SkColorSpace>(new SkColorSpace(gammas, mat, kUnknown_Named)); + return sk_sp<SkColorSpace>(new SkColorSpace_Base(gammas, mat, kUnknown_Named)); } } @@ -786,15 +805,16 @@ sk_sp<SkColorSpace> SkColorSpace::NewICC(const void* base, size_t len) { SkAutoTDelete<SkColorLookUpTable> colorLUT(new SkColorLookUpTable()); SkGammaCurve curves[3]; SkMatrix44 toXYZ(SkMatrix44::kUninitialized_Constructor); - if (!SkColorSpace::LoadA2B0(colorLUT, curves, &toXYZ, - a2b0->addr((const uint8_t*) base), a2b0->fLength)) { + if (!load_a2b0(colorLUT, curves, &toXYZ, a2b0->addr((const uint8_t*) base), + a2b0->fLength)) { 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) { - return sk_sp<SkColorSpace>(new SkColorSpace(colorLUT.release(), gammas, toXYZ)); + return sk_sp<SkColorSpace>(new SkColorSpace_Base(colorLUT.release(), gammas, + toXYZ)); } 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. @@ -804,7 +824,8 @@ sk_sp<SkColorSpace> SkColorSpace::NewICC(const void* base, size_t len) { gammaVals[2] = gammas->fBlue.fValue; return SkColorSpace::NewRGB(gammaVals, toXYZ); } else { - return sk_sp<SkColorSpace>(new SkColorSpace(gammas, toXYZ, kUnknown_Named)); + return sk_sp<SkColorSpace>(new SkColorSpace_Base(gammas, toXYZ, + kUnknown_Named)); } } diff --git a/src/core/SkColorSpace.h b/src/core/SkColorSpace.h deleted file mode 100644 index 299ffbca71..0000000000 --- a/src/core/SkColorSpace.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright 2016 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkColorSpace_DEFINED -#define SkColorSpace_DEFINED - -// Some terms -// -// PCS : Profile Connection Space : where color number values have an absolute meaning. -// Part of the work float is to convert colors to and from this space... -// src_linear_unit_floats --> PCS --> PCS' --> dst_linear_unit_floats -// -// Some nice documents -// -// http://www.cambridgeincolour.com/tutorials/color-space-conversion.htm -// https://www.w3.org/Graphics/Color/srgb -// http://www.poynton.com/notes/colour_and_gamma/ColorFAQ.html -// - -#include "SkMatrix44.h" -#include "SkRefCnt.h" -#include "../private/SkTemplates.h" - -struct SkColorLookUpTable; -struct SkGammaCurve; -struct SkGammas; - -class SkColorSpace : public SkRefCnt { -public: - - enum Named { - kUnknown_Named, - kSRGB_Named, - kAdobeRGB_Named, - }; - - /** - * Given the src gamma and a transform from src gamut to D50_XYZ, return a SkColorSpace. - */ - static sk_sp<SkColorSpace> NewRGB(float gammas[3], const SkMatrix44& toXYZD50); - - static sk_sp<SkColorSpace> NewNamed(Named); - static sk_sp<SkColorSpace> NewICC(const void*, size_t); - - /** - * Used only by test code. - */ - SkGammas* gammas() const { return fGammas.get(); } - - SkMatrix44 xyz() const { return fToXYZD50; } - Named named() const { return fNamed; } - uint32_t uniqueID() const { return fUniqueID; } - -private: - - static bool LoadGammas(SkGammaCurve* gammas, uint32_t num, const uint8_t* src, size_t len); - - static bool LoadColorLUT(SkColorLookUpTable* colorLUT, uint32_t inputChannels, - uint32_t outputChannels, const uint8_t* src, size_t len); - - static bool LoadA2B0(SkColorLookUpTable* colorLUT, SkGammaCurve*, SkMatrix44* toXYZ, - const uint8_t* src, size_t len); - - SkColorSpace(sk_sp<SkGammas> gammas, const SkMatrix44& toXYZ, Named); - - SkColorSpace(SkColorLookUpTable* colorLUT, sk_sp<SkGammas> gammas, const SkMatrix44& toXYZ); - - SkAutoTDelete<SkColorLookUpTable> fColorLUT; - sk_sp<SkGammas> fGammas; - const SkMatrix44 fToXYZD50; - - const uint32_t fUniqueID; - const Named fNamed; -}; - -#endif diff --git a/src/core/SkColorSpacePriv.h b/src/core/SkColorSpace_Base.h index a6274c7823..dbfe7338cd 100644 --- a/src/core/SkColorSpacePriv.h +++ b/src/core/SkColorSpace_Base.h @@ -5,8 +5,10 @@ * found in the LICENSE file. */ -#ifndef SkColorSpacePriv_DEFINED -#define SkColorSpacePriv_DEFINED +#ifndef SkColorSpace_Base_DEFINED +#define SkColorSpace_Base_DEFINED + +#include "SkColorSpace.h" struct SkGammaCurve { bool isValue() const { @@ -108,4 +110,30 @@ struct SkColorLookUpTable { } }; +class SkColorSpace_Base : public SkColorSpace { +public: + + SkGammas* gammas() const { return fGammas.get(); } + +private: + + SkColorSpace_Base(sk_sp<SkGammas> gammas, const SkMatrix44& toXYZ, Named); + + SkColorSpace_Base(sk_sp<SkGammas> gammas, GammaNamed gammaNamed, const SkMatrix44& toXYZ, + Named); + + SkColorSpace_Base(SkColorLookUpTable* colorLUT, sk_sp<SkGammas> gammas, + const SkMatrix44& toXYZ); + + SkAutoTDelete<SkColorLookUpTable> fColorLUT; + sk_sp<SkGammas> fGammas; + + friend class SkColorSpace; + typedef SkColorSpace INHERITED; +}; + +static inline SkColorSpace_Base* as_CSB(SkColorSpace* colorSpace) { + return static_cast<SkColorSpace_Base*>(colorSpace); +} + #endif diff --git a/tests/ColorSpaceTest.cpp b/tests/ColorSpaceTest.cpp index 698c3e9c61..097ca0929a 100644 --- a/tests/ColorSpaceTest.cpp +++ b/tests/ColorSpaceTest.cpp @@ -8,7 +8,7 @@ #include "Resources.h" #include "SkCodec.h" #include "SkColorSpace.h" -#include "SkColorSpacePriv.h" +#include "SkColorSpace_Base.h" #include "Test.h" #include "png.h" @@ -21,7 +21,7 @@ static void test_space(skiatest::Reporter* r, SkColorSpace* space, const float red[], const float green[], const float blue[], const float expectedGammas[]) { - SkGammas* gammas = space->gammas(); + 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)); |