aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Mike Klein <mtklein@google.com>2018-05-22 13:47:52 +0000
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2018-05-22 14:17:15 +0000
commit5b58b7c14c4405163e2af68dd3951a83fa1dabf2 (patch)
treef6d940bd35e271e139613a23e295b47dd4da631b
parent89735a0f47d2a06542d966a383dcba9f7a00d675 (diff)
Reland "strip down SkICC.cpp"
This reverts commit 27fe397bc0cc1b091f9f85863c62b88156239cf0. Reason for revert: time to fly. Original change's description: > Revert "strip down SkICC.cpp" > > This reverts commit eab50eb9c6117c2a9d0e5648f89cebbb4dbd9d30 > and this tiny bit of e61b969a07ba3ebe9e47e61381ad16c5d2c549a2: > > https://skia-review.googlesource.com/c/skia/+/127122/3/tests/ICCTest.cpp > > Change-Id: I4306e5118a4e5eb88c05078186a28bd443fd76f7 > Reviewed-on: https://skia-review.googlesource.com/127305 > Reviewed-by: Mike Klein <mtklein@chromium.org> > Commit-Queue: Mike Klein <mtklein@chromium.org> TBR=mtklein@chromium.org,brianosman@google.com # Not skipping CQ checks because original CL landed > 1 day ago. Change-Id: I93a6cfb66f0da0e098fdcb77ac1cd619e41614b1 Reviewed-on: https://skia-review.googlesource.com/129446 Reviewed-by: Mike Klein <mtklein@google.com> Commit-Queue: Mike Klein <mtklein@google.com>
-rw-r--r--include/core/SkICC.h106
-rw-r--r--src/core/SkICC.cpp213
-rw-r--r--src/core/SkICCPriv.h7
-rw-r--r--src/images/SkImageEncoderFns.h2
-rw-r--r--tests/ICCTest.cpp347
5 files changed, 107 insertions, 568 deletions
diff --git a/include/core/SkICC.h b/include/core/SkICC.h
index 8c5ec566b7..9d2ada347e 100644
--- a/include/core/SkICC.h
+++ b/include/core/SkICC.h
@@ -12,98 +12,26 @@
#include "SkRefCnt.h"
struct SkColorSpaceTransferFn;
-class SkColorSpace;
-class SkData;
-class SkMatrix44;
-class SK_API SkICC : public SkRefCnt {
-public:
+SK_API sk_sp<SkData> SkWriteICCProfile(const SkColorSpaceTransferFn&, const float toXYZD50[9]);
- /**
- * Parse an ICC profile.
- *
- * Returns nullptr if the data is not a valid ICC profile or if the profile
- * input space is not RGB.
- */
- static sk_sp<SkICC> Make(const void*, size_t);
+namespace SkICC {
+ static inline sk_sp<SkData> WriteToICC(const SkColorSpaceTransferFn& fn,
+ const SkMatrix44& toXYZD50) {
+ if (toXYZD50.get(3,0) == 0 && toXYZD50.get(3,1) == 0 && toXYZD50.get(3,2) == 0 &&
+ toXYZD50.get(3,3) == 1 &&
+ toXYZD50.get(0,3) == 0 && toXYZD50.get(1,3) == 0 && toXYZD50.get(2,3) == 0) {
- /**
- * If the gamut can be represented as transformation into XYZ D50, returns
- * true and sets the proper values in |toXYZD50|.
- *
- * If not, returns false. This indicates that the ICC data is too complex
- * to isolate a simple gamut transformation.
- */
- bool toXYZD50(SkMatrix44* toXYZD50) const;
+ float m33[9];
+ for (int r = 0; r < 3; r++)
+ for (int c = 0; c < 3; c++) {
+ m33[3*r+c] = toXYZD50.get(r,c);
+ }
+ return SkWriteICCProfile(fn, m33);
- /**
- * If the transfer function can be represented as coefficients to the standard
- * equation, returns true and sets |fn| to the proper values.
- *
- * If not, returns false. This indicates one of the following:
- * (1) The R, G, and B transfer functions are not the same.
- * (2) The transfer function is represented as a table that we have not managed
- * to match to a standard curve.
- * (3) The ICC data is too complex to isolate a single transfer function.
- */
- bool isNumericalTransferFn(SkColorSpaceTransferFn* fn) const;
-
- /**
- * Please do not call this unless isNumericalTransferFn() has been called and it
- * fails. SkColorSpaceTransferFn is the preferred representation.
- *
- * If it is not possible to represent the R, G, and B transfer functions numerically
- * and it is still necessary to get the transfer function, this will return the
- * transfer functions as three tables (R, G, and B).
- *
- * If possible, this will return tables of the same length as they were specified in
- * the ICC profile. This means that the lengths of the three tables are not
- * guaranteed to be the same. If the ICC representation was not a table, the length
- * will be chosen arbitrarily.
- *
- * The lengths of the tables are all guaranteed to be at least 2. Entries in the
- * tables are guaranteed to be in [0, 1].
- *
- * This API may be deleted in favor of a numerical approximation of the raw data.
- *
- * This function may fail, indicating that the ICC profile does not have transfer
- * functions.
- */
- struct Channel {
- // Byte offset of the start of the table in |fStorage|
- size_t fOffset;
- int fCount;
- };
- struct Tables {
- Channel fRed;
- Channel fGreen;
- Channel fBlue;
-
- const float* red() {
- return (const float*) (fStorage->bytes() + fRed.fOffset);
- }
- const float* green() {
- return (const float*) (fStorage->bytes() + fGreen.fOffset);
}
- const float* blue() {
- return (const float*) (fStorage->bytes() + fBlue.fOffset);
- }
-
- sk_sp<SkData> fStorage;
- };
- bool rawTransferFnData(Tables* tables) const;
-
- /**
- * Write an ICC profile with transfer function |fn| and gamut |toXYZD50|.
- */
- static sk_sp<SkData> WriteToICC(const SkColorSpaceTransferFn& fn, const SkMatrix44& toXYZD50);
-
-private:
- SkICC(sk_sp<SkColorSpace> colorSpace);
-
- sk_sp<SkColorSpace> fColorSpace;
-
- friend class ICCTest;
-};
+ return nullptr;
+ }
+}
-#endif
+#endif//SkICC_DEFINED
diff --git a/src/core/SkICC.cpp b/src/core/SkICC.cpp
index 3a77dfc200..aa9c45e50b 100644
--- a/src/core/SkICC.cpp
+++ b/src/core/SkICC.cpp
@@ -7,134 +7,13 @@
#include "SkAutoMalloc.h"
#include "SkColorSpacePriv.h"
-#include "SkColorSpaceXformPriv.h"
-#include "SkColorSpace_XYZ.h"
#include "SkEndian.h"
#include "SkFixed.h"
#include "SkICC.h"
#include "SkICCPriv.h"
#include "SkMD5.h"
-#include "SkString.h"
#include "SkUtils.h"
-SkICC::SkICC(sk_sp<SkColorSpace> colorSpace)
- : fColorSpace(std::move(colorSpace))
-{}
-
-sk_sp<SkICC> SkICC::Make(const void* ptr, size_t len) {
- sk_sp<SkColorSpace> colorSpace = SkColorSpace::MakeICC(ptr, len);
- if (!colorSpace) {
- return nullptr;
- }
-
- return sk_sp<SkICC>(new SkICC(std::move(colorSpace)));
-}
-
-bool SkICC::toXYZD50(SkMatrix44* toXYZD50) const {
- return fColorSpace->toXYZD50(toXYZD50);
-}
-
-bool SkICC::isNumericalTransferFn(SkColorSpaceTransferFn* coeffs) const {
- return fColorSpace->isNumericalTransferFn(coeffs);
-}
-
-static const int kDefaultTableSize = 512; // Arbitrary
-
-void fn_to_table(float* tablePtr, const SkColorSpaceTransferFn& fn) {
- // Y = (aX + b)^g + e for X >= d
- // Y = cX + f otherwise
- for (int i = 0; i < kDefaultTableSize; i++) {
- float x = ((float) i) / ((float) (kDefaultTableSize - 1));
- if (x >= fn.fD) {
- tablePtr[i] = clamp_0_1(powf(fn.fA * x + fn.fB, fn.fG) + fn.fE);
- } else {
- tablePtr[i] = clamp_0_1(fn.fC * x + fn.fF);
- }
- }
-}
-
-void copy_to_table(float* tablePtr, const SkGammas* gammas, int index) {
- SkASSERT(gammas->isTable(index));
- const float* ptr = gammas->table(index);
- const size_t bytes = gammas->tableSize(index) * sizeof(float);
- memcpy(tablePtr, ptr, bytes);
-}
-
-bool SkICC::rawTransferFnData(Tables* tables) const {
- if (!fColorSpace->toXYZD50()) {
- return false; // Can't even dream of handling A2B here...
- }
- SkColorSpace_XYZ* colorSpace = (SkColorSpace_XYZ*) fColorSpace.get();
-
- SkColorSpaceTransferFn fn;
- if (this->isNumericalTransferFn(&fn)) {
- tables->fStorage = SkData::MakeUninitialized(kDefaultTableSize * sizeof(float));
- fn_to_table((float*) tables->fStorage->writable_data(), fn);
- tables->fRed.fOffset = tables->fGreen.fOffset = tables->fBlue.fOffset = 0;
- tables->fRed.fCount = tables->fGreen.fCount = tables->fBlue.fCount = kDefaultTableSize;
- return true;
- }
-
- const SkGammas* gammas = colorSpace->gammas();
- SkASSERT(gammas);
- if (gammas->allChannelsSame()) {
- SkASSERT(gammas->isTable(0));
- tables->fStorage = SkData::MakeUninitialized(gammas->tableSize(0) * sizeof(float));
- copy_to_table((float*) tables->fStorage->writable_data(), gammas, 0);
- tables->fRed.fOffset = tables->fGreen.fOffset = tables->fBlue.fOffset = 0;
- tables->fRed.fCount = tables->fGreen.fCount = tables->fBlue.fCount = gammas->tableSize(0);
- return true;
- }
-
- // Determine the storage size.
- size_t storageSize = 0;
- for (int i = 0; i < 3; i++) {
- if (gammas->isTable(i)) {
- storageSize += gammas->tableSize(i) * sizeof(float);
- } else {
- storageSize += kDefaultTableSize * sizeof(float);
- }
- }
-
- // Fill in the tables.
- tables->fStorage = SkData::MakeUninitialized(storageSize);
- float* ptr = (float*) tables->fStorage->writable_data();
- size_t offset = 0;
- Channel rgb[3];
- for (int i = 0; i < 3; i++) {
- if (gammas->isTable(i)) {
- copy_to_table(ptr, gammas, i);
- rgb[i].fOffset = offset;
- rgb[i].fCount = gammas->tableSize(i);
- offset += rgb[i].fCount * sizeof(float);
- ptr += rgb[i].fCount;
- continue;
- }
-
- if (gammas->isNamed(i)) {
- SkAssertResult(named_to_parametric(&fn, gammas->data(i).fNamed));
- } else if (gammas->isValue(i)) {
- value_to_parametric(&fn, gammas->data(i).fValue);
- } else {
- SkASSERT(gammas->isParametric(i));
- fn = gammas->params(i);
- }
-
- fn_to_table(ptr, fn);
- rgb[i].fOffset = offset;
- rgb[i].fCount = kDefaultTableSize;
- offset += kDefaultTableSize * sizeof(float);
- ptr += kDefaultTableSize;
- }
-
- tables->fRed = rgb[0];
- tables->fGreen = rgb[1];
- tables->fBlue = rgb[2];
- return true;
-}
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
static constexpr char kDescriptionTagBodyPrefix[12] =
{ 'G', 'o', 'o', 'g', 'l', 'e', '/', 'S', 'k', 'i', 'a' , '/'};
@@ -165,9 +44,14 @@ static constexpr uint32_t kWhitePointTag[5] {
// 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,
+ 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] {
@@ -288,12 +172,12 @@ static SkFixed float_round_to_fixed(float x) {
return sk_float_saturate2int((float)floor((double)x * SK_Fixed1 + 0.5));
}
-static void write_xyz_tag(uint32_t* ptr, const SkMatrix44& toXYZ, int col) {
+static void write_xyz_tag(uint32_t* ptr, const float toXYZD50[9], int col) {
ptr[0] = SkEndian_SwapBE32(kXYZ_PCSSpace);
ptr[1] = 0;
- ptr[2] = SkEndian_SwapBE32(float_round_to_fixed(toXYZ.getFloat(0, col)));
- ptr[3] = SkEndian_SwapBE32(float_round_to_fixed(toXYZ.getFloat(1, col)));
- ptr[4] = SkEndian_SwapBE32(float_round_to_fixed(toXYZ.getFloat(2, col)));
+ ptr[2] = SkEndian_SwapBE32(float_round_to_fixed(toXYZD50[0*3 + col]));
+ ptr[3] = SkEndian_SwapBE32(float_round_to_fixed(toXYZD50[1*3 + col]));
+ ptr[4] = SkEndian_SwapBE32(float_round_to_fixed(toXYZD50[2*3 + col]));
}
static void write_trc_tag(uint32_t* ptr, const SkColorSpaceTransferFn& fn) {
@@ -309,12 +193,6 @@ static void write_trc_tag(uint32_t* ptr, const SkColorSpaceTransferFn& fn) {
ptr[9] = SkEndian_SwapBE32(float_round_to_fixed(fn.fF));
}
-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);
-}
-
static bool nearly_equal(float x, float y) {
// A note on why I chose this tolerance: transfer_fn_almost_equal() uses a
// tolerance of 0.001f, which doesn't seem to be enough to distinguish
@@ -338,28 +216,18 @@ static bool nearly_equal(const SkColorSpaceTransferFn& u,
&& nearly_equal(u.fF, v.fF);
}
-static bool nearly_equal(const SkMatrix44& toXYZD50, const float standard[9]) {
- return nearly_equal(toXYZD50.getFloat(0, 0), standard[0])
- && nearly_equal(toXYZD50.getFloat(0, 1), standard[1])
- && nearly_equal(toXYZD50.getFloat(0, 2), standard[2])
- && nearly_equal(toXYZD50.getFloat(1, 0), standard[3])
- && nearly_equal(toXYZD50.getFloat(1, 1), standard[4])
- && nearly_equal(toXYZD50.getFloat(1, 2), standard[5])
- && nearly_equal(toXYZD50.getFloat(2, 0), standard[6])
- && nearly_equal(toXYZD50.getFloat(2, 1), standard[7])
- && nearly_equal(toXYZD50.getFloat(2, 2), standard[8])
- && nearly_equal(toXYZD50.getFloat(0, 3), 0.0f)
- && nearly_equal(toXYZD50.getFloat(1, 3), 0.0f)
- && nearly_equal(toXYZD50.getFloat(2, 3), 0.0f)
- && nearly_equal(toXYZD50.getFloat(3, 0), 0.0f)
- && nearly_equal(toXYZD50.getFloat(3, 1), 0.0f)
- && nearly_equal(toXYZD50.getFloat(3, 2), 0.0f)
- && nearly_equal(toXYZD50.getFloat(3, 3), 1.0f);
+static bool nearly_equal(const float u[9], const float v[9]) {
+ for (int i = 0; i < 9; i++) {
+ if (!nearly_equal(u[i], v[i])) {
+ return false;
+ }
+ }
+ return true;
}
// Return nullptr if the color profile doen't have a special name.
const char* get_color_profile_description(const SkColorSpaceTransferFn& fn,
- const SkMatrix44& toXYZD50) {
+ const float toXYZD50[9]) {
bool srgb_xfer = nearly_equal(fn, gSRGB_TransferFn);
bool srgb_gamut = nearly_equal(toXYZD50, gSRGB_toXYZD50);
if (srgb_xfer && srgb_gamut) {
@@ -400,7 +268,7 @@ const char* get_color_profile_description(const SkColorSpaceTransferFn& fn,
static void get_color_profile_tag(char dst[kICCDescriptionTagSize],
const SkColorSpaceTransferFn& fn,
- const SkMatrix44& toXYZD50) {
+ const float toXYZD50[9]) {
SkASSERT(dst);
if (const char* description = get_color_profile_description(fn, toXYZD50)) {
SkASSERT(strlen(description) < kICCDescriptionTagSize);
@@ -410,12 +278,7 @@ static void get_color_profile_tag(char dst[kICCDescriptionTagSize],
} else {
strncpy(dst, kDescriptionTagBodyPrefix, sizeof(kDescriptionTagBodyPrefix));
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));
- }
- }
+ md5.write(toXYZD50, 9*sizeof(float));
static_assert(sizeof(fn) == sizeof(float) * 7, "packed");
md5.write(&fn, sizeof(fn));
SkMD5::Digest digest;
@@ -430,29 +293,8 @@ static void get_color_profile_tag(char dst[kICCDescriptionTagSize],
}
}
-SkString SkICCGetColorProfileTag(const SkColorSpaceTransferFn& fn,
- const SkMatrix44& toXYZD50) {
- char tag[kICCDescriptionTagSize];
- get_color_profile_tag(tag, fn, toXYZD50);
- size_t len = kICCDescriptionTagSize;
- while (len > 0 && tag[len - 1] == '\0') {
- --len; // tag is padded out with zeros
- }
- SkASSERT(len != 0);
- return SkString(tag, len);
-}
-
-// returns pointer just beyond where we just wrote.
-static uint8_t* string_copy_ascii_to_utf16be(uint8_t* dst, const char* src, size_t count) {
- while (count-- > 0) {
- *dst++ = 0;
- *dst++ = (uint8_t)(*src++);
- }
- return dst;
-}
-
-sk_sp<SkData> SkICC::WriteToICC(const SkColorSpaceTransferFn& fn, const SkMatrix44& toXYZD50) {
- if (!is_3x3(toXYZD50) || !is_valid_transfer_fn(fn)) {
+sk_sp<SkData> SkWriteICCProfile(const SkColorSpaceTransferFn& fn, const float toXYZD50[9]) {
+ if (!is_valid_transfer_fn(fn)) {
return nullptr;
}
@@ -473,7 +315,12 @@ sk_sp<SkData> SkICC::WriteToICC(const SkColorSpaceTransferFn& fn, const SkMatrix
{
char colorProfileTag[kICCDescriptionTagSize];
get_color_profile_tag(colorProfileTag, fn, toXYZD50);
- ptr = string_copy_ascii_to_utf16be(ptr, colorProfileTag, kICCDescriptionTagSize);
+
+ // ASCII --> big-endian UTF-16.
+ for (size_t i = 0; i < kICCDescriptionTagSize; i++) {
+ *ptr++ = 0;
+ *ptr++ = colorProfileTag[i];
+ }
}
// Write XYZ tags
diff --git a/src/core/SkICCPriv.h b/src/core/SkICCPriv.h
index a50d362a55..3d2b8965a9 100644
--- a/src/core/SkICCPriv.h
+++ b/src/core/SkICCPriv.h
@@ -51,11 +51,4 @@ enum ParaCurveType {
kGABCDEF_ParaCurveType = 4,
};
-/*
- * Given fn and toXYZD50, generate a decription tag that either includes a hash
- * of the function and gamut or is a special name.
- * Exposed for unit testing and tools.
- */
-SkString SkICCGetColorProfileTag(const SkColorSpaceTransferFn& fn,
- const SkMatrix44& toXYZD50);
#endif // SkICCPriv_DEFINED
diff --git a/src/images/SkImageEncoderFns.h b/src/images/SkImageEncoderFns.h
index 8637541720..d8d1c64bb8 100644
--- a/src/images/SkImageEncoderFns.h
+++ b/src/images/SkImageEncoderFns.h
@@ -427,8 +427,6 @@ static inline sk_sp<SkData> icc_from_color_space(const SkImageInfo& info) {
if (cs->isNumericalTransferFn(&fn) && cs->toXYZD50(&toXYZD50)) {
return SkICC::WriteToICC(fn, toXYZD50);
}
-
- // TODO: Should we support writing ICC profiles for additional color spaces?
return nullptr;
}
diff --git a/tests/ICCTest.cpp b/tests/ICCTest.cpp
index 34ed52984c..e88255b2cd 100644
--- a/tests/ICCTest.cpp
+++ b/tests/ICCTest.cpp
@@ -5,296 +5,69 @@
* found in the LICENSE file.
*/
-#include "Resources.h"
-#include "SkColorSpace.h"
-#include "SkColorSpacePriv.h"
-#include "SkColorSpace_XYZ.h"
-#include "SkData.h"
-#include "SkICC.h"
-#include "SkICCPriv.h"
-#include "SkMatrix44.h"
-#include "SkStream.h"
-#include "Test.h"
-
-static bool almost_equal(float a, float b) {
- return SkTAbs(a - b) < 0.001f;
-}
-
-static inline void test_to_xyz_d50(skiatest::Reporter* r, SkICC* icc, bool shouldSucceed,
- const float* reference) {
- SkMatrix44 result(SkMatrix44::kUninitialized_Constructor);
- REPORTER_ASSERT(r, shouldSucceed == icc->toXYZD50(&result));
- if (shouldSucceed) {
- float resultVals[16];
- result.asColMajorf(resultVals);
- for (int i = 0; i < 16; i++) {
- REPORTER_ASSERT(r, almost_equal(resultVals[i], reference[i]));
+#include "SkTypes.h"
+
+#if defined(SK_USE_SKCMS)
+
+ #include "Resources.h"
+ #include "SkColorSpacePriv.h"
+ #include "SkICC.h"
+ #include "SkString.h"
+ #include "Test.h"
+ #include "skcms.h"
+
+ DEF_TEST(WriteICCProfile, r) {
+ auto adobeRGB = SkColorSpace::MakeRGB(g2Dot2_TransferFn, SkColorSpace::kAdobeRGB_Gamut);
+
+ struct {
+ SkColorSpaceTransferFn fn;
+ const float* toXYZD50;
+ const char* desc;
+ sk_sp<SkColorSpace> want;
+ } tests[] = {
+ {g2Dot2_TransferFn, gAdobeRGB_toXYZD50, "AdobeRGB", adobeRGB},
+ { gSRGB_TransferFn, gSRGB_toXYZD50, "sRGB", SkColorSpace::MakeSRGB()},
+ };
+
+ for (auto test : tests) {
+ sk_sp<SkData> profile = SkWriteICCProfile(test.fn, test.toXYZD50);
+ REPORTER_ASSERT(r, profile);
+
+ skcms_ICCProfile parsed;
+ REPORTER_ASSERT(r, skcms_Parse(profile->data(), profile->size(), &parsed));
+
+ sk_sp<SkColorSpace> got = SkColorSpace::Make(parsed);
+ REPORTER_ASSERT(r, got);
+ REPORTER_ASSERT(r, SkColorSpace::Equals(got.get(), test.want.get()));
+
+ skcms_ICCTag desc;
+ REPORTER_ASSERT(r, skcms_GetTagBySignature(&parsed,
+ SkSetFourByteTag('d','e','s','c'),
+ &desc));
+
+ // Rather than really carefully break down the 'desc' tag,
+ // just check our expected description is somewhere in there (as big-endian UTF-16).
+ uint8_t big_endian_utf16[16];
+ for (size_t i = 0; i < strlen(test.desc); i++) {
+ big_endian_utf16[2*i+0] = 0;
+ big_endian_utf16[2*i+1] = test.desc[i];
+ }
+
+ SkString haystack((const char*)desc.buf, desc.size),
+ needle ((const char*)big_endian_utf16, 2*strlen(test.desc));
+ REPORTER_ASSERT(r, haystack.contains(needle.c_str()));
}
}
-}
-
-DEF_TEST(ICC_ToXYZD50, r) {
- const float z30Reference[16] = {
- 0.59825f, 0.27103f, 0.00603f, 0.0f, 0.22243f, 0.67447f, 0.07368f, 0.0f, 0.14352f, 0.05449f,
- 0.74519f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f,
- };
-
- sk_sp<SkData> data = GetResourceAsData("icc_profiles/HP_ZR30w.icc");
- sk_sp<SkICC> z30 = SkICC::Make(data->data(), data->size());
- test_to_xyz_d50(r, z30.get(), true, z30Reference);
-
- const float z32Reference[16] = {
- 0.61583f, 0.28789f, 0.00513f, 0.0f, 0.20428f, 0.66972f, 0.06609f, 0.0f, 0.14409f, 0.04237f,
- 0.75368f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f,
- };
-
- data = GetResourceAsData("icc_profiles/HP_Z32x.icc");
- sk_sp<SkICC> z32 = SkICC::Make(data->data(), data->size());
- test_to_xyz_d50(r, z32.get(), true, z32Reference);
-
- data = GetResourceAsData("icc_profiles/upperLeft.icc");
- sk_sp<SkICC> upperLeft = SkICC::Make(data->data(), data->size());
- test_to_xyz_d50(r, upperLeft.get(), false, z32Reference);
-
- data = GetResourceAsData("icc_profiles/upperRight.icc");
- sk_sp<SkICC> upperRight = SkICC::Make(data->data(), data->size());
- test_to_xyz_d50(r, upperRight.get(), false, z32Reference);
-}
-
-static inline void test_is_numerical_transfer_fn(skiatest::Reporter* r, SkICC* icc,
- bool shouldSucceed,
- const SkColorSpaceTransferFn& reference) {
- SkColorSpaceTransferFn result;
- REPORTER_ASSERT(r, shouldSucceed == icc->isNumericalTransferFn(&result));
- if (shouldSucceed) {
- REPORTER_ASSERT(r, 0 == memcmp(&result, &reference, sizeof(SkColorSpaceTransferFn)));
- }
-}
-
-DEF_TEST(ICC_IsNumericalTransferFn, r) {
- SkColorSpaceTransferFn referenceFn;
- referenceFn.fA = 1.0f;
- referenceFn.fB = 0.0f;
- referenceFn.fC = 0.0f;
- referenceFn.fD = 0.0f;
- referenceFn.fE = 0.0f;
- referenceFn.fF = 0.0f;
- referenceFn.fG = 2.2f;
-
- sk_sp<SkData> data = GetResourceAsData("icc_profiles/HP_ZR30w.icc");
- sk_sp<SkICC> z30 = SkICC::Make(data->data(), data->size());
- test_is_numerical_transfer_fn(r, z30.get(), true, referenceFn);
-
- data = GetResourceAsData("icc_profiles/HP_Z32x.icc");
- sk_sp<SkICC> z32 = SkICC::Make(data->data(), data->size());
- test_is_numerical_transfer_fn(r, z32.get(), true, referenceFn);
-
- data = GetResourceAsData("icc_profiles/upperLeft.icc");
- sk_sp<SkICC> upperLeft = SkICC::Make(data->data(), data->size());
- test_is_numerical_transfer_fn(r, upperLeft.get(), false, referenceFn);
-
- data = GetResourceAsData("icc_profiles/upperRight.icc");
- sk_sp<SkICC> upperRight = SkICC::Make(data->data(), data->size());
- test_is_numerical_transfer_fn(r, upperRight.get(), false, referenceFn);
-}
-
-DEF_TEST(ICC_Adobe, r) {
- // Test that the color spaces produced by our procedural Adobe factory, and the official
- // Adobe ICC profile match exactly.
- sk_sp<SkData> data = GetResourceAsData("icc_profiles/AdobeRGB1998.icc");
- sk_sp<SkColorSpace> fromIcc = SkColorSpace::MakeICC(data->data(), data->size());
- sk_sp<SkColorSpace> procedural = SkColorSpace::MakeRGB(g2Dot2_TransferFn,
- SkColorSpace::kAdobeRGB_Gamut);
- REPORTER_ASSERT(r, SkColorSpace::Equals(fromIcc.get(), procedural.get()));
-}
-
-static inline void test_write_icc(skiatest::Reporter* r, const SkColorSpaceTransferFn& fn,
- const SkMatrix44& toXYZD50, 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());
- sk_sp<SkColorSpace> reference = SkColorSpace::MakeRGB(fn, toXYZD50);
- REPORTER_ASSERT(r, SkColorSpace::Equals(reference.get(), 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, 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, false);
-
- SkString adobeTag = SkICCGetColorProfileTag(adobeFn, adobeMatrix);
- SkString srgbTag = SkICCGetColorProfileTag(srgbFn, srgbMatrix);
- REPORTER_ASSERT(r, adobeTag != srgbTag);
- REPORTER_ASSERT(r, srgbTag.equals("sRGB"));
- REPORTER_ASSERT(r, adobeTag.equals("AdobeRGB"));
-}
-
-static inline void test_raw_transfer_fn(skiatest::Reporter* r, SkICC* icc) {
- SkICC::Tables tables;
- bool result = icc->rawTransferFnData(&tables);
- REPORTER_ASSERT(r, result);
- REPORTER_ASSERT(r, 0.0f == tables.red()[0]);
- REPORTER_ASSERT(r, 0.0f == tables.green()[0]);
- REPORTER_ASSERT(r, 0.0f == tables.blue()[0]);
- REPORTER_ASSERT(r, 1.0f == tables.red()[tables.fRed.fCount - 1]);
- REPORTER_ASSERT(r, 1.0f == tables.green()[tables.fGreen.fCount - 1]);
- REPORTER_ASSERT(r, 1.0f == tables.blue()[tables.fBlue.fCount - 1]);
-}
+ DEF_TEST(AdobeRGB, r) {
+ if (sk_sp<SkData> profile = GetResourceAsData("icc_profiles/AdobeRGB1998.icc")) {
+ skcms_ICCProfile parsed;
+ REPORTER_ASSERT(r, skcms_Parse(profile->data(), profile->size(), &parsed));
-class ICCTest {
-public:
- static sk_sp<SkICC> MakeICC(sk_sp<SkColorSpace> space) {
- return sk_sp<SkICC>(new SkICC(std::move(space)));
- }
- static sk_sp<SkICC> MakeICC(sk_sp<SkGammas> gammas) {
- return MakeICC(sk_sp<SkColorSpace>(new SkColorSpace_XYZ(
- kNonStandard_SkGammaNamed, std::move(gammas),
- SkMatrix44(SkMatrix44::kIdentity_Constructor), nullptr)));
- }
-};
-
-DEF_TEST(ICC_RawTransferFns, r) {
- sk_sp<SkICC> srgb = ICCTest::MakeICC(SkColorSpace::MakeSRGB());
- test_raw_transfer_fn(r, srgb.get());
-
- // Lookup-table based gamma curves
- constexpr size_t tableSize = 10;
- void* memory = sk_malloc_throw(sizeof(SkGammas) + sizeof(float) * tableSize);
- sk_sp<SkGammas> gammas = sk_sp<SkGammas>(new (memory) SkGammas(3));
- for (int i = 0; i < 3; ++i) {
- gammas->fType[i] = SkGammas::Type::kTable_Type;
- gammas->fData[i].fTable.fSize = tableSize;
- gammas->fData[i].fTable.fOffset = 0;
- }
-
- float* table = SkTAddOffset<float>(memory, sizeof(SkGammas));
- table[0] = 0.00f;
- table[1] = 0.05f;
- table[2] = 0.10f;
- table[3] = 0.15f;
- table[4] = 0.25f;
- table[5] = 0.35f;
- table[6] = 0.45f;
- table[7] = 0.60f;
- table[8] = 0.75f;
- table[9] = 1.00f;
- sk_sp<SkICC> tbl = ICCTest::MakeICC(gammas);
- test_raw_transfer_fn(r, tbl.get());
-
- // Parametric gamma curves
- memory = sk_malloc_throw(sizeof(SkGammas) + sizeof(SkColorSpaceTransferFn));
- gammas = sk_sp<SkGammas>(new (memory) SkGammas(3));
- for (int i = 0; i < 3; ++i) {
- gammas->fType[i] = SkGammas::Type::kParam_Type;
- gammas->fData[i].fParamOffset = 0;
- }
-
- SkColorSpaceTransferFn* params = SkTAddOffset<SkColorSpaceTransferFn>
- (memory, sizeof(SkGammas));
-
- // Interval.
- params->fD = 0.04045f;
-
- // First equation:
- params->fC = 1.0f / 12.92f;
- params->fF = 0.0f;
-
- // Second equation:
- // Note that the function is continuous (it's actually sRGB).
- params->fA = 1.0f / 1.055f;
- params->fB = 0.055f / 1.055f;
- params->fE = 0.0f;
- params->fG = 2.4f;
- sk_sp<SkICC> param = ICCTest::MakeICC(gammas);
- test_raw_transfer_fn(r, param.get());
-
- // Exponential gamma curves
- gammas = sk_sp<SkGammas>(new SkGammas(3));
- for (int i = 0; i < 3; ++i) {
- gammas->fType[i] = SkGammas::Type::kValue_Type;
- gammas->fData[i].fValue = 1.4f;
+ auto got = SkColorSpace::Make(parsed);
+ auto want = SkColorSpace::MakeRGB(g2Dot2_TransferFn, SkColorSpace::kAdobeRGB_Gamut);
+ REPORTER_ASSERT(r, SkColorSpace::Equals(got.get(), want.get()));
+ }
}
- sk_sp<SkICC> exp = ICCTest::MakeICC(gammas);
- test_raw_transfer_fn(r, exp.get());
-
- gammas = sk_sp<SkGammas>(new SkGammas(3));
- gammas->fType[0] = gammas->fType[1] = gammas->fType[2] = SkGammas::Type::kNamed_Type;
- gammas->fData[0].fNamed = kSRGB_SkGammaNamed;
- gammas->fData[1].fNamed = k2Dot2Curve_SkGammaNamed;
- gammas->fData[2].fNamed = kLinear_SkGammaNamed;
- sk_sp<SkICC> named = ICCTest::MakeICC(gammas);
- test_raw_transfer_fn(r, named.get());
-
- memory = sk_malloc_throw(sizeof(SkGammas) + sizeof(float) * tableSize +
- sizeof(SkColorSpaceTransferFn));
- gammas = sk_sp<SkGammas>(new (memory) SkGammas(3));
-
- table = SkTAddOffset<float>(memory, sizeof(SkGammas));
- table[0] = 0.00f;
- table[1] = 0.15f;
- table[2] = 0.20f;
- table[3] = 0.25f;
- table[4] = 0.35f;
- table[5] = 0.45f;
- table[6] = 0.55f;
- table[7] = 0.70f;
- table[8] = 0.85f;
- table[9] = 1.00f;
-
- params = SkTAddOffset<SkColorSpaceTransferFn>(memory,
- sizeof(SkGammas) + sizeof(float) * tableSize);
- params->fA = 1.0f / 1.055f;
- params->fB = 0.055f / 1.055f;
- params->fC = 1.0f / 12.92f;
- params->fD = 0.04045f;
- params->fE = 0.0f;
- params->fF = 0.0f;
- params->fG = 2.4f;
-
- gammas->fType[0] = SkGammas::Type::kValue_Type;
- gammas->fData[0].fValue = 1.2f;
-
- gammas->fType[1] = SkGammas::Type::kTable_Type;
- gammas->fData[1].fTable.fSize = tableSize;
- gammas->fData[1].fTable.fOffset = 0;
-
- gammas->fType[2] = SkGammas::Type::kParam_Type;
- gammas->fData[2].fParamOffset = sizeof(float) * tableSize;
- sk_sp<SkICC> nonstd = ICCTest::MakeICC(gammas);
- test_raw_transfer_fn(r, nonstd.get());
-
- // Reverse order of table and exponent
- gammas->fType[1] = SkGammas::Type::kValue_Type;
- gammas->fData[1].fValue = 1.2f;
- gammas->fType[0] = SkGammas::Type::kTable_Type;
- gammas->fData[0].fTable.fSize = tableSize;
- gammas->fData[0].fTable.fOffset = 0;
- sk_sp<SkICC> nonstd2 = ICCTest::MakeICC(gammas);
- test_raw_transfer_fn(r, nonstd2.get());
-}
+#endif