diff options
-rw-r--r-- | src/core/SkColorSpace.cpp | 26 | ||||
-rw-r--r-- | src/core/SkColorSpacePriv.h | 28 | ||||
-rw-r--r-- | src/core/SkColorSpace_Base.h | 10 | ||||
-rw-r--r-- | src/core/SkColorSpace_ICC.cpp | 8 | ||||
-rw-r--r-- | src/core/SkColorSpace_XYZ.cpp | 6 | ||||
-rw-r--r-- | src/core/SkICC.cpp | 193 | ||||
-rw-r--r-- | src/core/SkICCPriv.h | 9 | ||||
-rw-r--r-- | tests/ColorSpaceTest.cpp | 37 | ||||
-rw-r--r-- | tests/ICCTest.cpp | 43 |
9 files changed, 170 insertions, 190 deletions
diff --git a/src/core/SkColorSpace.cpp b/src/core/SkColorSpace.cpp index 54c85f1330..f6cbf0acac 100644 --- a/src/core/SkColorSpace.cpp +++ b/src/core/SkColorSpace.cpp @@ -87,32 +87,6 @@ SkColorSpace_Base::SkColorSpace_Base(sk_sp<SkData> profileData) : fProfileData(std::move(profileData)) {} -#if defined(SK_USE_LEGACY_D50_MATRICES) -static constexpr float gSRGB_toXYZD50[] { - 0.4358f, 0.3853f, 0.1430f, // Rx, Gx, Bx - 0.2224f, 0.7170f, 0.0606f, // Ry, Gy, Gz - 0.0139f, 0.0971f, 0.7139f, // Rz, Gz, Bz -}; - -static constexpr float gAdobeRGB_toXYZD50[] { - 0.6098f, 0.2052f, 0.1492f, // Rx, Gx, Bx - 0.3111f, 0.6257f, 0.0632f, // Ry, Gy, By - 0.0195f, 0.0609f, 0.7448f, // Rz, Gz, Bz -}; -#else -static constexpr float gSRGB_toXYZD50[] { - 0.4360747f, 0.3850649f, 0.1430804f, // Rx, Gx, Bx - 0.2225045f, 0.7168786f, 0.0606169f, // Ry, Gy, Gz - 0.0139322f, 0.0971045f, 0.7141733f, // Rz, Gz, Bz -}; - -static constexpr float gAdobeRGB_toXYZD50[] { - 0.6097559f, 0.2052401f, 0.1492240f, // Rx, Gx, Bx - 0.3111242f, 0.6256560f, 0.0632197f, // Ry, Gy, Gz - 0.0194811f, 0.0608902f, 0.7448387f, // Rz, Gz, Bz -}; -#endif - /** * Checks if our toXYZ matrix is a close match to a known color gamut. * diff --git a/src/core/SkColorSpacePriv.h b/src/core/SkColorSpacePriv.h index f1ef8dc6d6..5488939099 100644 --- a/src/core/SkColorSpacePriv.h +++ b/src/core/SkColorSpacePriv.h @@ -7,8 +7,36 @@ #include <math.h> +#include "SkColorSpace_Base.h" + #define SkColorSpacePrintf(...) +#if defined(SK_USE_LEGACY_D50_MATRICES) +static constexpr float gSRGB_toXYZD50[] { + 0.4358f, 0.3853f, 0.1430f, // Rx, Gx, Bx + 0.2224f, 0.7170f, 0.0606f, // Ry, Gy, Gz + 0.0139f, 0.0971f, 0.7139f, // Rz, Gz, Bz +}; + +static constexpr float gAdobeRGB_toXYZD50[] { + 0.6098f, 0.2052f, 0.1492f, // Rx, Gx, Bx + 0.3111f, 0.6257f, 0.0632f, // Ry, Gy, By + 0.0195f, 0.0609f, 0.7448f, // Rz, Gz, Bz +}; +#else +static constexpr float gSRGB_toXYZD50[] { + 0.4360747f, 0.3850649f, 0.1430804f, // Rx, Gx, Bx + 0.2225045f, 0.7168786f, 0.0606169f, // Ry, Gy, Gz + 0.0139322f, 0.0971045f, 0.7141733f, // Rz, Gz, Bz +}; + +static constexpr float gAdobeRGB_toXYZD50[] { + 0.6097559f, 0.2052401f, 0.1492240f, // Rx, Gx, Bx + 0.3111242f, 0.6256560f, 0.0632197f, // Ry, Gy, Gz + 0.0194811f, 0.0608902f, 0.7448387f, // Rz, Gz, Bz +}; +#endif + static inline bool color_space_almost_equal(float a, float b) { return SkTAbs(a - b) < 0.01f; } diff --git a/src/core/SkColorSpace_Base.h b/src/core/SkColorSpace_Base.h index af8ec3133f..c2e0dc57c3 100644 --- a/src/core/SkColorSpace_Base.h +++ b/src/core/SkColorSpace_Base.h @@ -200,16 +200,6 @@ protected: SkColorSpace_Base(sk_sp<SkData> profileData); private: - - /** - * FIXME (msarett): - * Hiding this function until we can determine if we need it. Known issues include: - * Only writes 3x3 matrices - * Only writes float gammas - * Rejected by some parsers because the "profile description" is empty - */ - sk_sp<SkData> writeToICC() const; - SkColorSpace_Base(SkGammaNamed gammaNamed, const SkMatrix44& toXYZ); sk_sp<SkData> fProfileData; diff --git a/src/core/SkColorSpace_ICC.cpp b/src/core/SkColorSpace_ICC.cpp index adb54565d6..29291a3e00 100644 --- a/src/core/SkColorSpace_ICC.cpp +++ b/src/core/SkColorSpace_ICC.cpp @@ -375,14 +375,6 @@ static SkGammas::Type parse_gamma(SkGammas::Data* outData, SkColorSpaceTransferF return SkGammas::Type::kTable_Type; } case kTAG_ParaCurveType: { - enum ParaCurveType { - kExponential_ParaCurveType = 0, - kGAB_ParaCurveType = 1, - kGABC_ParaCurveType = 2, - kGABDE_ParaCurveType = 3, - kGABCDEF_ParaCurveType = 4, - }; - // Determine the format of the parametric curve tag. uint16_t format = read_big_endian_u16(src + 8); if (format > kGABCDEF_ParaCurveType) { diff --git a/src/core/SkColorSpace_XYZ.cpp b/src/core/SkColorSpace_XYZ.cpp index 30f70b6e26..4329ed8ef2 100644 --- a/src/core/SkColorSpace_XYZ.cpp +++ b/src/core/SkColorSpace_XYZ.cpp @@ -10,12 +10,6 @@ #include "SkColorSpacePriv.h" #include "SkColorSpaceXform_Base.h" -static constexpr float gSRGB_toXYZD50[] { - 0.4358f, 0.3853f, 0.1430f, // Rx, Gx, Bx - 0.2224f, 0.7170f, 0.0606f, // Ry, Gy, Gz - 0.0139f, 0.0971f, 0.7139f, // Rz, Gz, Bz -}; - SkColorSpace_XYZ::SkColorSpace_XYZ(SkGammaNamed gammaNamed, const SkMatrix44& toXYZD50) : INHERITED(nullptr) , fGammaNamed(gammaNamed) diff --git a/src/core/SkICC.cpp b/src/core/SkICC.cpp index 7b8ae9f5a0..b47cc71574 100644 --- a/src/core/SkICC.cpp +++ b/src/core/SkICC.cpp @@ -7,6 +7,7 @@ #include "SkColorSpace_Base.h" #include "SkColorSpace_XYZ.h" +#include "SkColorSpacePriv.h" #include "SkEndian.h" #include "SkFixed.h" #include "SkICC.h" @@ -41,33 +42,77 @@ bool SkICC::isNumericalTransferFn(SkColorSpaceTransferFn* coeffs) const { /////////////////////////////////////////////////////////////////////////////////////////////////// +// Google Skia (UTF-16) +static constexpr uint8_t kDescriptionTagBody[] = { + 0x00, 0x47, 0x00, 0x6f, 0x00, 0x6f, 0x00, 0x67, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x20, 0x00, + 0x53, 0x00, 0x6b, 0x00, 0x69, 0x00, 0x61, 0x00, 0x20, + }; +static_assert(SkIsAlign4(sizeof(kDescriptionTagBody)), "Description must be aligned to 4-bytes."); +static constexpr uint32_t kDescriptionTagHeader[7] { + SkEndian_SwapBE32(kTAG_TextType), // Type signature + 0, // Reserved + SkEndian_SwapBE32(1), // Number of records + SkEndian_SwapBE32(12), // Record size (must be 12) + SkEndian_SwapBE32(SkSetFourByteTag('e', 'n', 'U', 'S')), // English USA + SkEndian_SwapBE32(sizeof(kDescriptionTagBody)), // Length of string + SkEndian_SwapBE32(28), // Offset of string +}; + +static constexpr uint32_t kWhitePointTag[5] { + SkEndian_SwapBE32(kXYZ_PCSSpace), + 0, + SkEndian_SwapBE32(0x0000f6d6), // X = 0.96420 (D50) + SkEndian_SwapBE32(0x00010000), // Y = 1.00000 (D50) + SkEndian_SwapBE32(0x0000d32d), // Z = 0.82491 (D50) +}; + +// Google Inc. 2016 (UTF-16) +static constexpr uint8_t kCopyrightTagBody[] = { + 0x00, 0x47, 0x00, 0x6f, 0x00, 0x6f, 0x00, 0x67, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x20, 0x00, + 0x49, 0x00, 0x6e, 0x00, 0x63, 0x00, 0x2e, 0x00, 0x20, 0x00, 0x32, 0x00, 0x30, 0x00, 0x31, + 0x00, 0x36, +}; +static_assert(SkIsAlign4(sizeof(kCopyrightTagBody)), "Copyright must be aligned to 4-bytes."); +static constexpr uint32_t kCopyrightTagHeader[7] { + SkEndian_SwapBE32(kTAG_TextType), // Type signature + 0, // Reserved + SkEndian_SwapBE32(1), // Number of records + SkEndian_SwapBE32(12), // Record size (must be 12) + SkEndian_SwapBE32(SkSetFourByteTag('e', 'n', 'U', 'S')), // English USA + SkEndian_SwapBE32(sizeof(kCopyrightTagBody)), // Length of string + SkEndian_SwapBE32(28), // Offset of string +}; + // We will write a profile with the minimum nine required tags. static constexpr uint32_t kICCNumEntries = 9; static constexpr uint32_t kTAG_desc = SkSetFourByteTag('d', 'e', 's', 'c'); -static constexpr uint32_t kTAG_desc_Bytes = 12; -static constexpr uint32_t kTAG_desc_Offset = kICCHeaderSize + kICCNumEntries*kICCTagTableEntrySize; +static constexpr uint32_t kTAG_desc_Bytes = sizeof(kDescriptionTagHeader) + + sizeof(kDescriptionTagBody); +static constexpr uint32_t kTAG_desc_Offset = kICCHeaderSize + + kICCNumEntries * kICCTagTableEntrySize; static constexpr uint32_t kTAG_XYZ_Bytes = 20; static constexpr uint32_t kTAG_rXYZ_Offset = kTAG_desc_Offset + kTAG_desc_Bytes; static constexpr uint32_t kTAG_gXYZ_Offset = kTAG_rXYZ_Offset + kTAG_XYZ_Bytes; static constexpr uint32_t kTAG_bXYZ_Offset = kTAG_gXYZ_Offset + kTAG_XYZ_Bytes; -static constexpr uint32_t kTAG_TRC_Bytes = 14; +static constexpr uint32_t kTAG_TRC_Bytes = 40; static constexpr uint32_t kTAG_rTRC_Offset = kTAG_bXYZ_Offset + kTAG_XYZ_Bytes; -static constexpr uint32_t kTAG_gTRC_Offset = kTAG_rTRC_Offset + SkAlign4(kTAG_TRC_Bytes); -static constexpr uint32_t kTAG_bTRC_Offset = kTAG_gTRC_Offset + SkAlign4(kTAG_TRC_Bytes); +static constexpr uint32_t kTAG_gTRC_Offset = kTAG_rTRC_Offset; +static constexpr uint32_t kTAG_bTRC_Offset = kTAG_rTRC_Offset; static constexpr uint32_t kTAG_wtpt = SkSetFourByteTag('w', 't', 'p', 't'); -static constexpr uint32_t kTAG_wtpt_Offset = kTAG_bTRC_Offset + SkAlign4(kTAG_TRC_Bytes); +static constexpr uint32_t kTAG_wtpt_Offset = kTAG_bTRC_Offset + kTAG_TRC_Bytes; static constexpr uint32_t kTAG_cprt = SkSetFourByteTag('c', 'p', 'r', 't'); -static constexpr uint32_t kTAG_cprt_Bytes = 12; +static constexpr uint32_t kTAG_cprt_Bytes = sizeof(kCopyrightTagHeader) + + sizeof(kCopyrightTagBody); static constexpr uint32_t kTAG_cprt_Offset = kTAG_wtpt_Offset + kTAG_XYZ_Bytes; static constexpr uint32_t kICCProfileSize = kTAG_cprt_Offset + kTAG_cprt_Bytes; -static constexpr uint32_t gICCHeader[kICCHeaderSize / 4] { +static constexpr uint32_t kICCHeader[kICCHeaderSize / 4] { SkEndian_SwapBE32(kICCProfileSize), // Size of the profile 0, // Preferred CMM type (ignored) SkEndian_SwapBE32(0x02100000), // Version 2.1 @@ -91,7 +136,7 @@ static constexpr uint32_t gICCHeader[kICCHeaderSize / 4] { SkEndian_SwapBE32(kICCNumEntries), // Number of tags }; -static constexpr uint32_t gICCTagTable[3 * kICCNumEntries] { +static constexpr uint32_t kICCTagTable[3 * kICCNumEntries] { // Profile description SkEndian_SwapBE32(kTAG_desc), SkEndian_SwapBE32(kTAG_desc_Offset), @@ -138,13 +183,6 @@ static constexpr uint32_t gICCTagTable[3 * kICCNumEntries] { SkEndian_SwapBE32(kTAG_cprt_Bytes), }; -static constexpr uint32_t kTAG_TextType = SkSetFourByteTag('m', 'l', 'u', 'c'); -static constexpr uint32_t gEmptyTextTag[3] { - SkEndian_SwapBE32(kTAG_TextType), // Type signature - 0, // Reserved - 0, // Zero records -}; - static void write_xyz_tag(uint32_t* ptr, const SkMatrix44& toXYZ, int col) { ptr[0] = SkEndian_SwapBE32(kXYZ_PCSSpace); ptr[1] = 0; @@ -153,39 +191,27 @@ static void write_xyz_tag(uint32_t* ptr, const SkMatrix44& toXYZ, int col) { ptr[4] = SkEndian_SwapBE32(SkFloatToFixed(toXYZ.getFloat(2, col))); } -static void write_trc_tag(uint32_t* ptr, float value) { - ptr[0] = SkEndian_SwapBE32(kTAG_CurveType); +static void write_trc_tag(uint32_t* ptr, const SkColorSpaceTransferFn& fn) { + ptr[0] = SkEndian_SwapBE32(kTAG_ParaCurveType); ptr[1] = 0; + ptr[2] = (uint32_t) (SkEndian_SwapBE16(kGABCDEF_ParaCurveType)); + ptr[3] = SkEndian_SwapBE32(SkFloatToFixed(fn.fG)); + ptr[4] = SkEndian_SwapBE32(SkFloatToFixed(fn.fA)); + ptr[5] = SkEndian_SwapBE32(SkFloatToFixed(fn.fB)); + ptr[6] = SkEndian_SwapBE32(SkFloatToFixed(fn.fC)); + ptr[7] = SkEndian_SwapBE32(SkFloatToFixed(fn.fD)); + ptr[8] = SkEndian_SwapBE32(SkFloatToFixed(fn.fE)); + ptr[9] = SkEndian_SwapBE32(SkFloatToFixed(fn.fF)); +} - // Gamma will be specified with a single value. - ptr[2] = SkEndian_SwapBE32(1); - - // Convert gamma to 16-bit fixed point. - uint16_t* ptr16 = (uint16_t*) (ptr + 3); - ptr16[0] = SkEndian_SwapBE16((uint16_t) (value * 256.0f)); - - // Pad tag with zero. - ptr16[1] = 0; +static bool is_3x3(const SkMatrix44& toXYZD50) { + return 0.0f == toXYZD50.get(3, 0) && 0.0f == toXYZD50.get(3, 1) && 0.0f == toXYZD50.get(3, 2) && + 0.0f == toXYZD50.get(0, 3) && 0.0f == toXYZD50.get(1, 3) && 0.0f == toXYZD50.get(2, 3) && + 1.0f == toXYZD50.get(3, 3); } -sk_sp<SkData> SkColorSpace_Base::writeToICC() const { - // Return if this object was created from a profile, or if we have already serialized - // the profile. - if (fProfileData) { - return fProfileData; - } - // Profile Data is be mandatory for A2B0 Color Spaces - SkASSERT(type() == Type::kXYZ); - - // The client may create an SkColorSpace using an SkMatrix44, but currently we only - // support writing profiles with 3x3 matrices. - // TODO (msarett): Fix this! - const SkColorSpace_XYZ* thisXYZ = static_cast<const SkColorSpace_XYZ*>(this); - const SkMatrix44& toXYZD50 = *thisXYZ->toXYZD50(); - if (0.0f != toXYZD50.getFloat(3, 0) || 0.0f != toXYZD50.getFloat(3, 1) || - 0.0f != toXYZD50.getFloat(3, 2) || 0.0f != toXYZD50.getFloat(0, 3) || - 0.0f != toXYZD50.getFloat(1, 3) || 0.0f != toXYZD50.getFloat(2, 3)) - { +sk_sp<SkData> SkICC::WriteToICC(const SkColorSpaceTransferFn& fn, const SkMatrix44& toXYZD50) { + if (!is_3x3(toXYZD50) || !is_valid_transfer_fn(fn)) { return nullptr; } @@ -193,16 +219,18 @@ sk_sp<SkData> SkColorSpace_Base::writeToICC() const { uint8_t* ptr = (uint8_t*) profile.get(); // Write profile header - memcpy(ptr, gICCHeader, sizeof(gICCHeader)); - ptr += sizeof(gICCHeader); + memcpy(ptr, kICCHeader, sizeof(kICCHeader)); + ptr += sizeof(kICCHeader); // Write tag table - memcpy(ptr, gICCTagTable, sizeof(gICCTagTable)); - ptr += sizeof(gICCTagTable); + memcpy(ptr, kICCTagTable, sizeof(kICCTagTable)); + ptr += sizeof(kICCTagTable); // Write profile description tag - memcpy(ptr, gEmptyTextTag, sizeof(gEmptyTextTag)); - ptr += sizeof(gEmptyTextTag); + memcpy(ptr, kDescriptionTagHeader, sizeof(kDescriptionTagHeader)); + ptr += sizeof(kDescriptionTagHeader); + memcpy(ptr, kDescriptionTagBody, sizeof(kDescriptionTagBody)); + ptr += sizeof(kDescriptionTagBody); // Write XYZ tags write_xyz_tag((uint32_t*) ptr, toXYZD50, 0); @@ -212,61 +240,20 @@ sk_sp<SkData> SkColorSpace_Base::writeToICC() const { write_xyz_tag((uint32_t*) ptr, toXYZD50, 2); ptr += kTAG_XYZ_Bytes; - // Write TRC tags - SkGammaNamed gammaNamed = thisXYZ->gammaNamed(); - if (kNonStandard_SkGammaNamed == gammaNamed) { - // FIXME (msarett): - // Write the correct gamma representation rather than 2.2f. - 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); - } else { - switch (gammaNamed) { - case kSRGB_SkGammaNamed: - // 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 k2Dot2Curve_SkGammaNamed: - 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 kLinear_SkGammaNamed: - 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 TRC tag + write_trc_tag((uint32_t*) ptr, fn); + ptr += kTAG_TRC_Bytes; - // Write white point tag - uint32_t* ptr32 = (uint32_t*) ptr; - ptr32[0] = SkEndian_SwapBE32(kXYZ_PCSSpace); - ptr32[1] = 0; - // TODO (msarett): These values correspond to the D65 white point. This may not always be - // correct. - ptr32[2] = SkEndian_SwapBE32(0x0000f351); - ptr32[3] = SkEndian_SwapBE32(0x00010000); - ptr32[4] = SkEndian_SwapBE32(0x000116cc); - ptr += kTAG_XYZ_Bytes; + // Write white point tag (must be D50) + memcpy(ptr, kWhitePointTag, sizeof(kWhitePointTag)); + ptr += sizeof(kWhitePointTag); // Write copyright tag - memcpy(ptr, gEmptyTextTag, sizeof(gEmptyTextTag)); + memcpy(ptr, kCopyrightTagHeader, sizeof(kCopyrightTagHeader)); + ptr += sizeof(kCopyrightTagHeader); + memcpy(ptr, kCopyrightTagBody, sizeof(kCopyrightTagBody)); + ptr += sizeof(kCopyrightTagBody); - // TODO (msarett): Should we try to hold onto the data so we can return immediately if - // the client calls again? + SkASSERT(kICCProfileSize == ptr - (uint8_t*) profile.get()); return SkData::MakeFromMalloc(profile.release(), kICCProfileSize); } diff --git a/src/core/SkICCPriv.h b/src/core/SkICCPriv.h index ac8566778d..bc8a9e9533 100644 --- a/src/core/SkICCPriv.h +++ b/src/core/SkICCPriv.h @@ -35,3 +35,12 @@ static constexpr uint32_t kTAG_A2B0 = SkSetFourByteTag('A', '2', 'B', '0'); static constexpr uint32_t kTAG_CurveType = SkSetFourByteTag('c', 'u', 'r', 'v'); static constexpr uint32_t kTAG_ParaCurveType = SkSetFourByteTag('p', 'a', 'r', 'a'); +static constexpr uint32_t kTAG_TextType = SkSetFourByteTag('m', 'l', 'u', 'c'); + +enum ParaCurveType { + kExponential_ParaCurveType = 0, + kGAB_ParaCurveType = 1, + kGABC_ParaCurveType = 2, + kGABDE_ParaCurveType = 3, + kGABCDEF_ParaCurveType = 4, +}; diff --git a/tests/ColorSpaceTest.cpp b/tests/ColorSpaceTest.cpp index 070d50264f..df253c09e3 100644 --- a/tests/ColorSpaceTest.cpp +++ b/tests/ColorSpaceTest.cpp @@ -142,43 +142,6 @@ DEF_TEST(ColorSpaceSRGBLinearCompare, r) { REPORTER_ASSERT(r, strangeColorSpace != namedColorSpace); } -class ColorSpaceTest { -public: - static sk_sp<SkData> WriteToICC(SkColorSpace* space) { - return as_CSB(space)->writeToICC(); - } -}; - -DEF_TEST(ColorSpaceWriteICC, r) { - // Test writing a new ICC profile - sk_sp<SkColorSpace> namedColorSpace = SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named); - sk_sp<SkData> namedData = ColorSpaceTest::WriteToICC(namedColorSpace.get()); - sk_sp<SkColorSpace> iccColorSpace = SkColorSpace::MakeICC(namedData->data(), namedData->size()); - test_space(r, iccColorSpace.get(), g_sRGB_R, g_sRGB_G, g_sRGB_B, k2Dot2Curve_SkGammaNamed); - // 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( - GetResourcePath("icc_profiles/HP_ZR30w.icc").c_str()); - REPORTER_ASSERT(r, monitorData); - if (!monitorData) { - return; - } - sk_sp<SkColorSpace> monitorSpace = SkColorSpace::MakeICC(monitorData->data(), - monitorData->size()); - sk_sp<SkData> newMonitorData = ColorSpaceTest::WriteToICC(monitorSpace.get()); - sk_sp<SkColorSpace> newMonitorSpace = SkColorSpace::MakeICC(newMonitorData->data(), - newMonitorData->size()); - SkASSERT(SkColorSpace_Base::Type::kXYZ == as_CSB(monitorSpace)->type()); - SkColorSpace_XYZ* monitorSpaceXYZ = static_cast<SkColorSpace_XYZ*>(monitorSpace.get()); - SkASSERT(SkColorSpace_Base::Type::kXYZ == as_CSB(newMonitorSpace)->type()); - SkColorSpace_XYZ* newMonitorSpaceXYZ = static_cast<SkColorSpace_XYZ*>(newMonitorSpace.get()); - REPORTER_ASSERT(r, *monitorSpaceXYZ->toXYZD50() == *newMonitorSpaceXYZ->toXYZD50()); - REPORTER_ASSERT(r, monitorSpaceXYZ->toXYZD50Hash() == newMonitorSpaceXYZ->toXYZD50Hash()); - REPORTER_ASSERT(r, monitorSpaceXYZ->gammaNamed() == newMonitorSpaceXYZ->gammaNamed()); -} - DEF_TEST(ColorSpace_Named, r) { const struct { SkColorSpace::Named fNamed; diff --git a/tests/ICCTest.cpp b/tests/ICCTest.cpp index 38d6801c5f..4bc296d140 100644 --- a/tests/ICCTest.cpp +++ b/tests/ICCTest.cpp @@ -7,9 +7,11 @@ #include "Resources.h" #include "SkColorSpace.h" +#include "SkColorSpacePriv.h" #include "SkData.h" #include "SkICC.h" #include "SkMatrix44.h" +#include "SkStream.h" #include "Test.h" static bool almost_equal(float a, float b) { @@ -95,3 +97,44 @@ DEF_TEST(ICC_IsNumericalTransferFn, r) { sk_sp<SkICC> upperRight = SkICC::Make(data->data(), data->size()); test_is_numerical_transfer_fn(r, upperRight.get(), false, referenceFn); } + +static inline void test_write_icc(skiatest::Reporter* r, const SkColorSpaceTransferFn& fn, + const SkMatrix44& toXYZD50, SkColorSpace* reference, + bool writeToFile) { + sk_sp<SkData> profile = SkICC::WriteToICC(fn, toXYZD50); + if (writeToFile) { + SkFILEWStream stream("out.icc"); + stream.write(profile->data(), profile->size()); + } + + sk_sp<SkColorSpace> colorSpace = SkColorSpace::MakeICC(profile->data(), profile->size()); + REPORTER_ASSERT(r, SkColorSpace::Equals(reference, colorSpace.get())); +} + +DEF_TEST(ICC_WriteICC, r) { + SkColorSpaceTransferFn adobeFn; + adobeFn.fA = 1.0f; + adobeFn.fB = 0.0f; + adobeFn.fC = 0.0f; + adobeFn.fD = 0.0f; + adobeFn.fE = 0.0f; + adobeFn.fF = 0.0f; + adobeFn.fG = 2.2f; + SkMatrix44 adobeMatrix(SkMatrix44::kUninitialized_Constructor); + adobeMatrix.set3x3RowMajorf(gAdobeRGB_toXYZD50); + test_write_icc(r, adobeFn, adobeMatrix, + SkColorSpace::MakeNamed(SkColorSpace::kAdobeRGB_Named).get(), false); + + 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; + SkMatrix44 srgbMatrix(SkMatrix44::kUninitialized_Constructor); + srgbMatrix.set3x3RowMajorf(gSRGB_toXYZD50); + test_write_icc(r, srgbFn, srgbMatrix, SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named).get(), + false); +} |