aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/SkColorSpace_ICC.cpp
diff options
context:
space:
mode:
authorGravatar raftias <raftias@google.com>2016-12-02 11:56:59 -0500
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2016-12-05 16:38:40 +0000
commit91db12d89c214235e24599f3ec18df2f952e99eb (patch)
treebcc7ca2428499bbc85173fa39f3f90cdf8babea4 /src/core/SkColorSpace_ICC.cpp
parentaa2219c69b81b2258862a45cd82cc9fdc06c987a (diff)
Color-correct Gray JPEG image decoding via ICC profiles.
SkColorSpace::MakeICC now parses Gray ICC profiles and SkColorSpaceXform_A2B can now render color spaces from Gray ICC profiles. This is not enabled for SkPngCodec as of right now as we don't have any Gray PNG test images currently. BUG=skia: GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=5214 CQ_INCLUDE_TRYBOTS=skia.primary:Test-Ubuntu-GCC-GCE-CPU-AVX2-x86_64-Release-SKNX_NO_SIMD Change-Id: Iea7136d1c163cd17cf0818af57f93efdbcb577e7 Reviewed-on: https://skia-review.googlesource.com/5214 Reviewed-by: Matt Sarett <msarett@google.com> Commit-Queue: Robert Aftias <raftias@google.com>
Diffstat (limited to 'src/core/SkColorSpace_ICC.cpp')
-rw-r--r--src/core/SkColorSpace_ICC.cpp81
1 files changed, 55 insertions, 26 deletions
diff --git a/src/core/SkColorSpace_ICC.cpp b/src/core/SkColorSpace_ICC.cpp
index 84a29f0c6f..d27de96c3f 100644
--- a/src/core/SkColorSpace_ICC.cpp
+++ b/src/core/SkColorSpace_ICC.cpp
@@ -50,6 +50,7 @@ static constexpr size_t kICCTagTableEntrySize = 12;
static constexpr uint32_t kRGB_ColorSpace = SkSetFourByteTag('R', 'G', 'B', ' ');
static constexpr uint32_t kCMYK_ColorSpace = SkSetFourByteTag('C', 'M', 'Y', 'K');
+static constexpr uint32_t kGray_ColorSpace = SkSetFourByteTag('G', 'R', 'A', 'Y');
static constexpr uint32_t kDisplay_Profile = SkSetFourByteTag('m', 'n', 't', 'r');
static constexpr uint32_t kInput_Profile = SkSetFourByteTag('s', 'c', 'n', 'r');
static constexpr uint32_t kOutput_Profile = SkSetFourByteTag('p', 'r', 't', 'r');
@@ -135,6 +136,9 @@ struct ICCProfileHeader {
case kCMYK_ColorSpace:
SkColorSpacePrintf("CMYK Input Color Space\n");
break;
+ case kGray_ColorSpace:
+ SkColorSpacePrintf("Gray Input Color Space\n");
+ break;
default:
SkColorSpacePrintf("Unsupported Input Color Space: %c%c%c%c\n",
(fInputColorSpace>>24)&0xFF, (fInputColorSpace>>16)&0xFF,
@@ -245,6 +249,7 @@ static constexpr uint32_t kTAG_bXYZ = SkSetFourByteTag('b', 'X', 'Y', 'Z');
static constexpr uint32_t kTAG_rTRC = SkSetFourByteTag('r', 'T', 'R', 'C');
static constexpr uint32_t kTAG_gTRC = SkSetFourByteTag('g', 'T', 'R', 'C');
static constexpr uint32_t kTAG_bTRC = SkSetFourByteTag('b', 'T', 'R', 'C');
+static constexpr uint32_t kTAG_kTRC = SkSetFourByteTag('k', 'T', 'R', 'C');
static constexpr uint32_t kTAG_A2B0 = SkSetFourByteTag('A', '2', 'B', '0');
static bool load_xyz(float dst[3], const uint8_t* src, size_t len) {
@@ -1187,6 +1192,8 @@ static inline int icf_channels(SkColorSpace_Base::InputColorFormat inputColorFor
return 3;
case SkColorSpace_Base::InputColorFormat::kCMYK:
return 4;
+ case SkColorSpace_Base::InputColorFormat::kGray:
+ return 1;
default:
SkASSERT(false);
return -1;
@@ -1303,8 +1310,8 @@ sk_sp<SkColorSpace> SkColorSpace_Base::MakeICC(const void* input, size_t len,
// Create our own copy of the input.
void* memory = sk_malloc_throw(len);
memcpy(memory, input, len);
- sk_sp<SkData> data = SkData::MakeFromMalloc(memory, len);
- const uint8_t* base = data->bytes();
+ sk_sp<SkData> profileData = SkData::MakeFromMalloc(memory, len);
+ const uint8_t* base = profileData->bytes();
const uint8_t* ptr = base;
// Read the ICC profile header and check to make sure that it is valid.
@@ -1323,7 +1330,11 @@ sk_sp<SkColorSpace> SkColorSpace_Base::MakeICC(const void* input, size_t len,
case InputColorFormat::kCMYK:
if (header.fInputColorSpace != kCMYK_ColorSpace) {
return_null("Provided input color format (CMYK) does not match profile.\n");
- return nullptr;
+ }
+ break;
+ case InputColorFormat::kGray:
+ if (header.fInputColorSpace != kGray_ColorSpace) {
+ return_null("Provided input color format (Gray) does not match profile.\n");
}
break;
default:
@@ -1371,19 +1382,24 @@ sk_sp<SkColorSpace> SkColorSpace_Base::MakeICC(const void* input, size_t len,
std::vector<SkColorSpace_A2B::Element> elements;
if (load_a2b0(&elements, a2b0->addr(base), a2b0->fLength, pcs, inputColorFormat)) {
return sk_sp<SkColorSpace>(new SkColorSpace_A2B(inputColorFormat, std::move(elements),
- pcs, std::move(data)));
+ pcs, std::move(profileData)));
}
SkColorSpacePrintf("Ignoring malformed A2B0 tag.\n");
}
+ // Lab PCS means the profile is required to be an n-component LUT-based
+ // profile, so monochrome/3-component matrix-based profiles can only have an XYZ PCS
+ if (kLAB_PCSSpace == header.fPCS) {
+ return_null("Invalid PCS. PCSLAB only supported on A2B0 profiles.");
+ }
+ SkASSERT(kXYZ_PCSSpace == header.fPCS);
+
if (kRGB_ColorSpace == header.fInputColorSpace) {
// Recognize the rXYZ, gXYZ, and bXYZ tags.
const ICCTag* r = ICCTag::Find(tags.get(), tagCount, kTAG_rXYZ);
const ICCTag* g = ICCTag::Find(tags.get(), tagCount, kTAG_gXYZ);
const ICCTag* b = ICCTag::Find(tags.get(), tagCount, kTAG_bXYZ);
- // Lab PCS means the profile is required to be an n-component LUT-based
- // profile, so 3-component matrix-based profiles can only have an XYZ PCS
- if (r && g && b && kXYZ_PCSSpace == header.fPCS) {
+ if (r && g && b) {
float toXYZ[9];
if (!load_xyz(&toXYZ[0], r->addr(base), r->fLength) ||
!load_xyz(&toXYZ[3], g->addr(base), g->fLength) ||
@@ -1438,24 +1454,6 @@ sk_sp<SkColorSpace> SkColorSpace_Base::MakeICC(const void* input, size_t len,
if (SkGammas::Type::kNamed_Type == type) {
gammaNamed = data.fNamed;
} else {
- SkGammas::Data rData;
- SkColorSpaceTransferFn rParams;
- SkGammas::Type rType =
- parse_gamma(&rData, &rParams, &tagBytes, r->addr(base), r->fLength);
- handle_invalid_gamma(&rType, &rData);
-
- SkGammas::Data gData;
- SkColorSpaceTransferFn gParams;
- SkGammas::Type gType =
- parse_gamma(&gData, &gParams, &tagBytes, g->addr(base), g->fLength);
- handle_invalid_gamma(&gType, &gData);
-
- SkGammas::Data bData;
- SkColorSpaceTransferFn bParams;
- SkGammas::Type bType =
- parse_gamma(&bData, &bParams, &tagBytes, b->addr(base), b->fLength);
- handle_invalid_gamma(&bType, &bData);
-
size_t allocSize = sizeof(SkGammas);
if (!safe_add(allocSize, gamma_alloc_size(type, data), &allocSize)) {
return_null("SkGammas struct is too large to allocate");
@@ -1527,11 +1525,42 @@ sk_sp<SkColorSpace> SkColorSpace_Base::MakeICC(const void* input, size_t len,
if (kNonStandard_SkGammaNamed == gammaNamed) {
return sk_sp<SkColorSpace>(new SkColorSpace_XYZ(gammaNamed,
std::move(gammas),
- mat, std::move(data)));
+ mat, std::move(profileData)));
}
return SkColorSpace_Base::MakeRGB(gammaNamed, mat);
}
+ } else if (kGray_ColorSpace == header.fInputColorSpace) {
+ const ICCTag* grayTRC = ICCTag::Find(tags.get(), tagCount, kTAG_kTRC);
+ if (!grayTRC) {
+ return_null("grayTRC tag required for monochrome profiles.");
+ }
+ SkGammas::Data data;
+ SkColorSpaceTransferFn params;
+ size_t tagBytes;
+ SkGammas::Type type =
+ parse_gamma(&data, &params, &tagBytes, grayTRC->addr(base), grayTRC->fLength);
+ handle_invalid_gamma(&type, &data);
+
+ std::vector<SkColorSpace_A2B::Element> elements;
+ if (SkGammas::Type::kNamed_Type == type) {
+ elements.push_back(SkColorSpace_A2B::Element(data.fNamed, 1));
+ } else {
+ size_t allocSize = sizeof(SkGammas);
+ if (!safe_add(allocSize, gamma_alloc_size(type, data), &allocSize)) {
+ return_null("SkGammas struct is too large to allocate");
+ }
+ void* memory = sk_malloc_throw(allocSize);
+ sk_sp<SkGammas> gammas = sk_sp<SkGammas>(new (memory) SkGammas(1));
+ load_gammas(memory, 0, type, &data, params, grayTRC->addr(base));
+ gammas->fType[0] = type;
+ gammas->fData[0] = data;
+ elements.push_back(SkColorSpace_A2B::Element(std::move(gammas)));
+ }
+ return sk_sp<SkColorSpace>(new SkColorSpace_A2B(inputColorFormat,
+ std::move(elements),
+ SkColorSpace_A2B::PCS::kXYZ,
+ std::move(profileData)));
}
return_null("ICC profile contains unsupported colorspace");