diff options
author | 2017-06-16 13:38:34 -0400 | |
---|---|---|
committer | 2017-06-16 21:30:37 +0000 | |
commit | 7a808d618e90e216cf4fa6369f658350319deb02 (patch) | |
tree | 1de807337207c8bb60e30bcf8686689c64f44b83 | |
parent | 93323eb401dc9003dda881ac83222d115151947f (diff) |
ICC: SkICC::WriteToICC Description Tag is function of input
BUG=skia:6720
Change-Id: I038079a6e15f884eb77b84d9c7c75f6b7fbedd37
Reviewed-on: https://skia-review.googlesource.com/20152
Commit-Queue: Hal Canary <halcanary@google.com>
Reviewed-by: Matt Sarett <msarett@google.com>
-rw-r--r-- | src/core/SkICC.cpp | 58 | ||||
-rw-r--r-- | src/core/SkICCPriv.h | 11 | ||||
-rw-r--r-- | tests/ICCTest.cpp | 19 |
3 files changed, 76 insertions, 12 deletions
diff --git a/src/core/SkICC.cpp b/src/core/SkICC.cpp index 40a733f872..c26f6d8e58 100644 --- a/src/core/SkICC.cpp +++ b/src/core/SkICC.cpp @@ -14,6 +14,7 @@ #include "SkFixed.h" #include "SkICC.h" #include "SkICCPriv.h" +#include "SkMD5.h" SkICC::SkICC(sk_sp<SkColorSpace> colorSpace) : fColorSpace(std::move(colorSpace)) @@ -139,19 +140,19 @@ bool SkICC::rawTransferFnData(Tables* tables) 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 char kDescriptionTagBodyPrefix[12] = + { 'G', 'o', 'o', 'g', 'l', 'e', '/', 'S', 'k', 'i', 'a' , '/'}; +static constexpr size_t kDescriptionTagBodySize = + (sizeof(kDescriptionTagBodyPrefix) + 2 * sizeof(SkMD5::Digest)) * 2; + +static_assert(SkIsAlign4(kDescriptionTagBodySize), "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(kDescriptionTagBodySize), // Length of string SkEndian_SwapBE32(28), // Offset of string }; @@ -185,7 +186,7 @@ static constexpr uint32_t kICCNumEntries = 9; static constexpr uint32_t kTAG_desc = SkSetFourByteTag('d', 'e', 's', 'c'); static constexpr uint32_t kTAG_desc_Bytes = sizeof(kDescriptionTagHeader) + - sizeof(kDescriptionTagBody); + kDescriptionTagBodySize; static constexpr uint32_t kTAG_desc_Offset = kICCHeaderSize + kICCNumEntries * kICCTagTableEntrySize; @@ -307,6 +308,42 @@ static bool is_3x3(const SkMatrix44& toXYZD50) { 1.0f == toXYZD50.get(3, 3); } +size_t SkICCWriteDescriptionTag(uint8_t* ptr, + const SkColorSpaceTransferFn& fn, + const SkMatrix44& toXYZD50) { + if (ptr) { + SkDEBUGCODE(const uint8_t* const ptrCheck = ptr); + memcpy(ptr, kDescriptionTagHeader, sizeof(kDescriptionTagHeader)); + ptr += sizeof(kDescriptionTagHeader); + + for (unsigned i = 0; i < sizeof(kDescriptionTagBodyPrefix); ++i) { + *ptr++ = 0; + *ptr++ = kDescriptionTagBodyPrefix[i]; + } + SkMD5 md5; + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 3; ++j) { + float value = toXYZD50.getFloat(i,j); + md5.write(&value, sizeof(value)); + } + } + static_assert(sizeof(fn) == sizeof(float) * 7, "packed"); + md5.write(&fn, sizeof(fn)); + SkMD5::Digest digest; + md5.finish(digest); + for (unsigned i = 0; i < sizeof(SkMD5::Digest); ++i) { + static const char gHex[] = "0123456789ABCDEF"; + *ptr++ = 0; + *ptr++ = gHex[digest.data[i] >> 4]; + *ptr++ = 0; + *ptr++ = gHex[digest.data[i] & 0xF]; + } + SkASSERT(ptr == ptrCheck + kDescriptionTagBodySize + sizeof(kDescriptionTagHeader)); + } + return kDescriptionTagBodySize + sizeof(kDescriptionTagHeader); +} + + sk_sp<SkData> SkICC::WriteToICC(const SkColorSpaceTransferFn& fn, const SkMatrix44& toXYZD50) { if (!is_3x3(toXYZD50) || !is_valid_transfer_fn(fn)) { return nullptr; @@ -324,10 +361,7 @@ sk_sp<SkData> SkICC::WriteToICC(const SkColorSpaceTransferFn& fn, const SkMatrix ptr += sizeof(kICCTagTable); // Write profile description tag - memcpy(ptr, kDescriptionTagHeader, sizeof(kDescriptionTagHeader)); - ptr += sizeof(kDescriptionTagHeader); - memcpy(ptr, kDescriptionTagBody, sizeof(kDescriptionTagBody)); - ptr += sizeof(kDescriptionTagBody); + ptr += SkICCWriteDescriptionTag(ptr, fn, toXYZD50); // Write XYZ tags write_xyz_tag((uint32_t*) ptr, toXYZD50, 0); diff --git a/src/core/SkICCPriv.h b/src/core/SkICCPriv.h index 4c656f17d8..eb5c13d595 100644 --- a/src/core/SkICCPriv.h +++ b/src/core/SkICCPriv.h @@ -49,4 +49,15 @@ enum ParaCurveType { kGABDE_ParaCurveType = 3, kGABCDEF_ParaCurveType = 4, }; + +/* + * Given fn and toXYZD50, generate a ICC decription tag that includes a hash of + * the input. If ptr is not nullptr, write the tag there. Always returns + * length of the tag. + * + * Exposed for unit testing. + */ +size_t SkICCWriteDescriptionTag(uint8_t* ptr, + const SkColorSpaceTransferFn& fn, + const SkMatrix44& toXYZD50); #endif // SkICCPriv_DEFINED diff --git a/tests/ICCTest.cpp b/tests/ICCTest.cpp index 5d541bdc27..3c855fb22d 100644 --- a/tests/ICCTest.cpp +++ b/tests/ICCTest.cpp @@ -11,6 +11,7 @@ #include "SkColorSpace_XYZ.h" #include "SkData.h" #include "SkICC.h" +#include "SkICCPriv.h" #include "SkMatrix44.h" #include "SkStream.h" #include "Test.h" @@ -112,6 +113,14 @@ static inline void test_write_icc(skiatest::Reporter* r, const SkColorSpaceTrans REPORTER_ASSERT(r, SkColorSpace::Equals(reference, colorSpace.get())); } +template <typename T> +static bool equal(const SkTArray<T>& u, const SkTArray<T>& v) { + if (u.count() != v.count()) { + return false; + } + return u.count() == 0 || 0 == memcmp(&u[0], &v[0], sizeof(T) * u.count()); +} + DEF_TEST(ICC_WriteICC, r) { SkColorSpaceTransferFn adobeFn; adobeFn.fA = 1.0f; @@ -138,6 +147,16 @@ DEF_TEST(ICC_WriteICC, r) { srgbMatrix.set3x3RowMajorf(gSRGB_toXYZD50); test_write_icc(r, srgbFn, srgbMatrix, SkColorSpace::MakeSRGB().get(), false); + + SkTArray<uint8_t> adobeTag; + adobeTag.reset(SkToInt(SkICCWriteDescriptionTag(nullptr, adobeFn, adobeMatrix))); + SkICCWriteDescriptionTag(&adobeTag[0], adobeFn, adobeMatrix); + + SkTArray<uint8_t> srgbTag; + srgbTag.reset(SkToInt(SkICCWriteDescriptionTag(nullptr, srgbFn, srgbMatrix))); + SkICCWriteDescriptionTag(&srgbTag[0], srgbFn, srgbMatrix); + + REPORTER_ASSERT(r, !equal(adobeTag, srgbTag)); } static inline void test_raw_transfer_fn(skiatest::Reporter* r, SkICC* icc) { |