Added CMYK support for ICC profiles.
Changed ICC parsing/SkGammas/SkColorLookUpTable to handle non-3-channel
inputs. Parsed CMYK A2B ICC profiles. Integrated this with SkJpegCodec
(the only file that supports CMYK) and SkColorSpaceXform_A2B to allow
parsing and color xforming of ICC CMYK images.
CQ_INCLUDE_TRYBOTS=skia.primary:Test-Ubuntu-GCC-GCE-CPU-AVX2-x86_64-Release-SKNX_NO_SIMD
Change-Id: I11e3d17180244281be3eb43fd608609925a7f71e
Reviewed-on: https://skia-review.googlesource.com/5444
Reviewed-by: Matt Sarett <msarett@google.com>
Commit-Queue: Matt Sarett <msarett@google.com>
diff --git a/tests/ColorSpaceXformTest.cpp b/tests/ColorSpaceXformTest.cpp
index 0e67fe4..d2bd2a3 100644
--- a/tests/ColorSpaceXformTest.cpp
+++ b/tests/ColorSpaceXformTest.cpp
@@ -16,6 +16,8 @@
#include "SkColorSpaceXform_Base.h"
#include "Test.h"
+static constexpr int kChannels = 3;
+
class ColorSpaceXformTest {
public:
static std::unique_ptr<SkColorSpaceXform> CreateIdentityXform(const sk_sp<SkGammas>& gammas) {
@@ -40,13 +42,16 @@
SkMatrix44 arbitraryMatrix{SkMatrix44::kUninitialized_Constructor};
arbitraryMatrix.setRowMajorf(values);
if (kNonStandard_SkGammaNamed == gammaNamed) {
+ SkASSERT(gammas);
srcElements.push_back(SkColorSpace_A2B::Element(gammas));
} else {
- srcElements.push_back(SkColorSpace_A2B::Element(gammaNamed));
+ srcElements.push_back(SkColorSpace_A2B::Element(gammaNamed, kChannels));
}
srcElements.push_back(SkColorSpace_A2B::Element(arbitraryMatrix));
- auto srcSpace = ColorSpaceXformTest::CreateA2BSpace(SkColorSpace_A2B::PCS::kXYZ,
- std::move(srcElements));
+ auto srcSpace =
+ ColorSpaceXformTest::CreateA2BSpace(SkColorSpace_A2B::PCS::kXYZ,
+ SkColorSpace_Base::InputColorFormat::kRGB,
+ std::move(srcElements));
sk_sp<SkColorSpace> dstSpace(new SkColorSpace_XYZ(gammaNamed, gammas, arbitraryMatrix,
nullptr));
@@ -55,13 +60,15 @@
}
static sk_sp<SkColorSpace> CreateA2BSpace(SkColorSpace_A2B::PCS pcs,
+ SkColorSpace_Base::InputColorFormat inputColorFormat,
std::vector<SkColorSpace_A2B::Element> elements) {
- return sk_sp<SkColorSpace>(new SkColorSpace_A2B(pcs, nullptr, std::move(elements)));
+ return sk_sp<SkColorSpace>(new SkColorSpace_A2B(inputColorFormat, std::move(elements),
+ pcs, nullptr));
}
};
static bool almost_equal(int x, int y) {
- return SkTAbs(x - y) <= 1 ;
+ return SkTAbs(x - y) <= 1;
}
static void test_identity_xform(skiatest::Reporter* r, const sk_sp<SkGammas>& gammas,
@@ -101,7 +108,7 @@
}
static void test_identity_xform_A2B(skiatest::Reporter* r, SkGammaNamed gammaNamed,
- const sk_sp<SkGammas>& gammas, bool repeat) {
+ const sk_sp<SkGammas>& gammas) {
// Arbitrary set of 10 pixels
constexpr int width = 10;
constexpr uint32_t srcPixels[width] = {
@@ -128,24 +135,19 @@
REPORTER_ASSERT(r, almost_equal(((srcPixels[i] >> 24) & 0xFF),
SkGetPackedA32(dstPixels[i])));
}
-
- if (repeat) {
- // We should cache part of the transform after the run. So it is interesting
- // to make sure it still runs correctly the second time.
- test_identity_xform_A2B(r, gammaNamed, gammas, false);
- }
}
DEF_TEST(ColorSpaceXform_TableGamma, r) {
// 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());
- gammas->fRedType = gammas->fGreenType = gammas->fBlueType = SkGammas::Type::kTable_Type;
- gammas->fRedData.fTable.fSize = gammas->fGreenData.fTable.fSize =
- gammas->fBlueData.fTable.fSize = tableSize;
- gammas->fRedData.fTable.fOffset = gammas->fGreenData.fTable.fOffset =
- gammas->fBlueData.fTable.fOffset = 0;
+ sk_sp<SkGammas> gammas = sk_sp<SkGammas>(new (memory) SkGammas(kChannels));
+ for (int i = 0; i < kChannels; ++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;
@@ -159,16 +161,18 @@
table[8] = 0.75f;
table[9] = 1.00f;
test_identity_xform(r, gammas, true);
- test_identity_xform_A2B(r, kNonStandard_SkGammaNamed, gammas, true);
+ test_identity_xform_A2B(r, kNonStandard_SkGammaNamed, gammas);
}
DEF_TEST(ColorSpaceXform_ParametricGamma, r) {
// Parametric gamma curves
void* memory = sk_malloc_throw(sizeof(SkGammas) + sizeof(SkColorSpaceTransferFn));
- sk_sp<SkGammas> gammas = sk_sp<SkGammas>(new (memory) SkGammas());
- gammas->fRedType = gammas->fGreenType = gammas->fBlueType = SkGammas::Type::kParam_Type;
- gammas->fRedData.fParamOffset = gammas->fGreenData.fParamOffset =
- gammas->fBlueData.fParamOffset = 0;
+ sk_sp<SkGammas> gammas = sk_sp<SkGammas>(new (memory) SkGammas(kChannels));
+ for (int i = 0; i < kChannels; ++i) {
+ gammas->fType[i] = SkGammas::Type::kParam_Type;
+ gammas->fData[i].fParamOffset = 0;
+ }
+
SkColorSpaceTransferFn* params = SkTAddOffset<SkColorSpaceTransferFn>
(memory, sizeof(SkGammas));
@@ -186,36 +190,38 @@
params->fC = 0.0f;
params->fG = 2.4f;
test_identity_xform(r, gammas, true);
- test_identity_xform_A2B(r, kNonStandard_SkGammaNamed, gammas, true);
+ test_identity_xform_A2B(r, kNonStandard_SkGammaNamed, gammas);
}
DEF_TEST(ColorSpaceXform_ExponentialGamma, r) {
// Exponential gamma curves
- sk_sp<SkGammas> gammas = sk_sp<SkGammas>(new SkGammas());
- gammas->fRedType = gammas->fGreenType = gammas->fBlueType = SkGammas::Type::kValue_Type;
- gammas->fRedData.fValue = gammas->fGreenData.fValue = gammas->fBlueData.fValue = 1.4f;
+ sk_sp<SkGammas> gammas = sk_sp<SkGammas>(new SkGammas(kChannels));
+ for (int i = 0; i < kChannels; ++i) {
+ gammas->fType[i] = SkGammas::Type::kValue_Type;
+ gammas->fData[i].fValue = 1.4f;
+ }
test_identity_xform(r, gammas, true);
- test_identity_xform_A2B(r, kNonStandard_SkGammaNamed, gammas, true);
+ test_identity_xform_A2B(r, kNonStandard_SkGammaNamed, gammas);
}
DEF_TEST(ColorSpaceXform_NamedGamma, r) {
- sk_sp<SkGammas> gammas = sk_sp<SkGammas>(new SkGammas());
- gammas->fRedType = gammas->fGreenType = gammas->fBlueType = SkGammas::Type::kNamed_Type;
- gammas->fRedData.fNamed = kSRGB_SkGammaNamed;
- gammas->fGreenData.fNamed = k2Dot2Curve_SkGammaNamed;
- gammas->fBlueData.fNamed = kLinear_SkGammaNamed;
+ sk_sp<SkGammas> gammas = sk_sp<SkGammas>(new SkGammas(kChannels));
+ 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;
test_identity_xform(r, gammas, true);
- test_identity_xform_A2B(r, kNonStandard_SkGammaNamed, gammas, true);
- test_identity_xform_A2B(r, kSRGB_SkGammaNamed, nullptr, true);
- test_identity_xform_A2B(r, k2Dot2Curve_SkGammaNamed, nullptr, true);
- test_identity_xform_A2B(r, kLinear_SkGammaNamed, nullptr, true);
+ test_identity_xform_A2B(r, kNonStandard_SkGammaNamed, gammas);
+ test_identity_xform_A2B(r, kSRGB_SkGammaNamed, nullptr);
+ test_identity_xform_A2B(r, k2Dot2Curve_SkGammaNamed, nullptr);
+ test_identity_xform_A2B(r, kLinear_SkGammaNamed, nullptr);
}
DEF_TEST(ColorSpaceXform_NonMatchingGamma, r) {
constexpr size_t tableSize = 10;
void* memory = sk_malloc_throw(sizeof(SkGammas) + sizeof(float) * tableSize +
sizeof(SkColorSpaceTransferFn));
- sk_sp<SkGammas> gammas = sk_sp<SkGammas>(new (memory) SkGammas());
+ sk_sp<SkGammas> gammas = sk_sp<SkGammas>(new (memory) SkGammas(kChannels));
float* table = SkTAddOffset<float>(memory, sizeof(SkGammas));
table[0] = 0.00f;
@@ -239,18 +245,18 @@
params->fF = 0.0f;
params->fG = 2.4f;
- gammas->fRedType = SkGammas::Type::kValue_Type;
- gammas->fRedData.fValue = 1.2f;
+ gammas->fType[0] = SkGammas::Type::kValue_Type;
+ gammas->fData[0].fValue = 1.2f;
- gammas->fGreenType = SkGammas::Type::kTable_Type;
- gammas->fGreenData.fTable.fSize = tableSize;
- gammas->fGreenData.fTable.fOffset = 0;
+ gammas->fType[1] = SkGammas::Type::kTable_Type;
+ gammas->fData[1].fTable.fSize = tableSize;
+ gammas->fData[1].fTable.fOffset = 0;
- gammas->fBlueType = SkGammas::Type::kParam_Type;
- gammas->fBlueData.fParamOffset = sizeof(float) * tableSize;
+ gammas->fType[2] = SkGammas::Type::kParam_Type;
+ gammas->fData[2].fParamOffset = sizeof(float) * tableSize;
test_identity_xform(r, gammas, true);
- test_identity_xform_A2B(r, kNonStandard_SkGammaNamed, gammas, true);
+ test_identity_xform_A2B(r, kNonStandard_SkGammaNamed, gammas);
}
DEF_TEST(ColorSpaceXform_A2BCLUT, r) {
@@ -258,7 +264,7 @@
constexpr int gp = 4; // # grid points
constexpr int numEntries = gp*gp*gp*3;
- uint8_t gridPoints[3] = {gp, gp, gp};
+ const uint8_t gridPoints[3] = {gp, gp, gp};
void* memory = sk_malloc_throw(sizeof(SkColorLookUpTable) + sizeof(float) * numEntries);
sk_sp<SkColorLookUpTable> colorLUT(new (memory) SkColorLookUpTable(inputChannels, gridPoints));
// make a CLUT that rotates R, G, and B ie R->G, G->B, B->R
@@ -296,6 +302,7 @@
std::vector<SkColorSpace_A2B::Element> srcElements;
srcElements.push_back(SkColorSpace_A2B::Element(std::move(colorLUT)));
auto srcSpace = ColorSpaceXformTest::CreateA2BSpace(SkColorSpace_A2B::PCS::kXYZ,
+ SkColorSpace_Base::InputColorFormat::kRGB,
std::move(srcElements));
// dst space is entirely identity
auto dstSpace = SkColorSpace::MakeRGB(SkColorSpace::kLinear_RenderTargetGamma, SkMatrix44::I());