Index: src/core/SkColorSpace_ICC.cpp |
diff --git a/src/core/SkColorSpace_ICC.cpp b/src/core/SkColorSpace_ICC.cpp |
index 6fc3090caf2ce21ae98b783aec4ab362a110c0aa..6154e59d4ff6c0ded82e856d1033bf29bc22a35a 100644 |
--- a/src/core/SkColorSpace_ICC.cpp |
+++ b/src/core/SkColorSpace_ICC.cpp |
@@ -131,9 +131,18 @@ struct ICCProfileHeader { |
// All the profiles we've tested so far use RGB as the input color space. |
return_if_false(fInputColorSpace == kRGB_ColorSpace, "Unsupported color space"); |
- // TODO (msarett): |
- // All the profiles we've tested so far use XYZ as the profile connection space. |
- return_if_false(fPCS == kXYZ_PCSSpace || fPCS == kLAB_PCSSpace, "Unsupported PCS space"); |
+ switch (fPCS) { |
+ case kXYZ_PCSSpace: |
+ SkColorSpacePrintf("XYZ PCS\n"); |
+ break; |
+ case kLAB_PCSSpace: |
+ SkColorSpacePrintf("Lab PCS\n"); |
+ break; |
+ default: |
+ // ICC currently (V4.3) only specifices XYZ and Lab PCS spaces |
+ SkColorSpacePrintf("Unsupported PCS space\n"); |
+ return false; |
+ } |
return_if_false(fSignature == kACSP_Signature, "Bad signature"); |
@@ -724,6 +733,8 @@ static bool parse_and_load_gamma(SkGammaNamed* gammaNamed, sk_sp<SkGammas>* gamm |
SkGammas::Data rData; |
SkColorSpaceTransferFn rParams; |
+ *gammaNamed = kNonStandard_SkGammaNamed; |
+ |
// On an invalid first gamma, tagBytes remains set as zero. This causes the two |
// subsequent to be treated as identical (which is what we want). |
size_t tagBytes = 0; |
@@ -807,27 +818,12 @@ static bool parse_and_load_gamma(SkGammaNamed* gammaNamed, sk_sp<SkGammas>* gamm |
return true; |
} |
-static bool load_a2b0(sk_sp<SkColorLookUpTable>* colorLUT, |
- SkGammaNamed* aCurveNamed, sk_sp<SkGammas>* aCurve, |
- SkGammaNamed* mCurveNamed, sk_sp<SkGammas>* mCurve, |
- SkGammaNamed* bCurveNamed, sk_sp<SkGammas>* bCurve, |
- SkMatrix44* matrix, const uint8_t* src, size_t len) { |
- if (len < 32) { |
- SkColorSpacePrintf("A to B tag is too small (%d bytes).", len); |
- return false; |
- } |
- |
- uint32_t type = read_big_endian_u32(src); |
- if (kTAG_AtoBType != type) { |
- // FIXME (msarett): Need to support lut8Type and lut16Type. |
- SkColorSpacePrintf("Unsupported A to B tag type.\n"); |
- return false; |
- } |
- |
- // Read the number of channels. The four bytes that we skipped are reserved and |
+bool load_a2b0_a_to_b_type(std::vector<SkColorSpace_A2B::Element>* elements, const uint8_t* src, |
+ size_t len) { |
+ // Read the number of channels. The four bytes (4-7) that we skipped are reserved and |
// must be zero. |
- uint8_t inputChannels = src[8]; |
- uint8_t outputChannels = src[9]; |
+ const uint8_t inputChannels = src[8]; |
+ const uint8_t outputChannels = src[9]; |
if (3 != inputChannels || SkColorLookUpTable::kOutputChannels != outputChannels) { |
// We only handle (supposedly) RGB inputs and RGB outputs. The numbers of input |
// channels and output channels both must be 3. |
@@ -836,52 +832,98 @@ static bool load_a2b0(sk_sp<SkColorLookUpTable>* colorLUT, |
SkColorSpacePrintf("Input and output channels must equal 3 in A to B tag.\n"); |
return false; |
} |
+ |
+ // It is important that these are loaded in the order of application, as the |
+ // order you construct an A2B color space's elements is the order it is applied |
// If the offset is non-zero it indicates that the element is present. |
- uint32_t offsetToACurves = read_big_endian_i32(src + 28); |
+ const uint32_t offsetToACurves = read_big_endian_i32(src + 28); |
if (0 != offsetToACurves && offsetToACurves < len) { |
const size_t tagLen = len - offsetToACurves; |
- if (!parse_and_load_gamma(aCurveNamed, aCurve, src + offsetToACurves, tagLen)) { |
+ SkGammaNamed gammaNamed; |
+ sk_sp<SkGammas> gammas; |
+ if (!parse_and_load_gamma(&gammaNamed, &gammas, src + offsetToACurves, tagLen)) { |
return false; |
} |
+ if (gammas) { |
+ elements->push_back(SkColorSpace_A2B::Element(std::move(gammas))); |
+ } else { |
+ elements->push_back(SkColorSpace_A2B::Element(gammaNamed)); |
+ } |
} |
- uint32_t offsetToColorLUT = read_big_endian_i32(src + 24); |
+ const uint32_t offsetToColorLUT = read_big_endian_i32(src + 24); |
if (0 != offsetToColorLUT && offsetToColorLUT < len) { |
- if (!load_color_lut(colorLUT, inputChannels, src + offsetToColorLUT, |
+ sk_sp<SkColorLookUpTable> colorLUT; |
+ if (!load_color_lut(&colorLUT, inputChannels, src + offsetToColorLUT, |
len - offsetToColorLUT)) { |
SkColorSpacePrintf("Failed to read color LUT from A to B tag.\n"); |
return false; |
} |
+ elements->push_back(SkColorSpace_A2B::Element(std::move(colorLUT))); |
} |
- uint32_t offsetToMCurves = read_big_endian_i32(src + 20); |
+ const uint32_t offsetToMCurves = read_big_endian_i32(src + 20); |
if (0 != offsetToMCurves && offsetToMCurves < len) { |
const size_t tagLen = len - offsetToMCurves; |
- if (!parse_and_load_gamma(mCurveNamed, mCurve, src + offsetToMCurves, tagLen)) { |
+ SkGammaNamed gammaNamed; |
+ sk_sp<SkGammas> gammas; |
+ if (!parse_and_load_gamma(&gammaNamed, &gammas, src + offsetToMCurves, tagLen)) { |
return false; |
} |
+ if (gammas) { |
+ elements->push_back(SkColorSpace_A2B::Element(std::move(gammas))); |
+ } else { |
+ elements->push_back(SkColorSpace_A2B::Element(gammaNamed)); |
+ } |
} |
- uint32_t offsetToMatrix = read_big_endian_i32(src + 16); |
+ const uint32_t offsetToMatrix = read_big_endian_i32(src + 16); |
if (0 != offsetToMatrix && offsetToMatrix < len) { |
- if (!load_matrix(matrix, src + offsetToMatrix, len - offsetToMatrix)) { |
+ SkMatrix44 matrix(SkMatrix44::kUninitialized_Constructor); |
+ if (!load_matrix(&matrix, src + offsetToMatrix, len - offsetToMatrix)) { |
SkColorSpacePrintf("Failed to read matrix from A to B tag.\n"); |
- matrix->setIdentity(); |
+ } else { |
+ elements->push_back(SkColorSpace_A2B::Element(matrix)); |
} |
} |
- uint32_t offsetToBCurves = read_big_endian_i32(src + 12); |
+ const uint32_t offsetToBCurves = read_big_endian_i32(src + 12); |
if (0 != offsetToBCurves && offsetToBCurves < len) { |
const size_t tagLen = len - offsetToBCurves; |
- if (!parse_and_load_gamma(bCurveNamed, bCurve, src + offsetToBCurves, tagLen)) { |
+ SkGammaNamed gammaNamed; |
+ sk_sp<SkGammas> gammas; |
+ if (!parse_and_load_gamma(&gammaNamed, &gammas, src + offsetToBCurves, tagLen)) { |
return false; |
} |
+ if (gammas) { |
+ elements->push_back(SkColorSpace_A2B::Element(std::move(gammas))); |
+ } else { |
+ elements->push_back(SkColorSpace_A2B::Element(gammaNamed)); |
+ } |
} |
return true; |
} |
+static bool load_a2b0(std::vector<SkColorSpace_A2B::Element>* elements, const uint8_t* src, |
+ size_t len) { |
+ const uint32_t type = read_big_endian_u32(src); |
+ switch (type) { |
+ case kTAG_AtoBType: |
+ if (len < 32) { |
+ SkColorSpacePrintf("A to B tag is too small (%d bytes).", len); |
+ return false; |
+ } |
+ SkColorSpacePrintf("A2B0 tag is of type lutAtoBType\n"); |
+ return load_a2b0_a_to_b_type(elements, src, len); |
+ default: |
+ SkColorSpacePrintf("Unsupported A to B tag type: %c%c%c%c\n", (type>>24)&0xFF, |
+ (type>>16)&0xFF, (type>>8)&0xFF, type&0xFF); |
+ } |
+ return false; |
+} |
+ |
static bool tag_equals(const ICCTag* a, const ICCTag* b, const uint8_t* base) { |
if (!a || !b) { |
return a == b; |
@@ -952,12 +994,9 @@ sk_sp<SkColorSpace> SkColorSpace::NewICC(const void* input, size_t len) { |
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); |
- if (r && g && b) { |
- // 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 (kXYZ_PCSSpace != header.fPCS) { |
- return_null("Unsupported PCS space"); |
- } |
+ // 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) { |
float toXYZ[9]; |
if (!load_xyz(&toXYZ[0], r->addr(base), r->fLength) || |
!load_xyz(&toXYZ[3], g->addr(base), g->fLength) || |
@@ -1089,32 +1128,15 @@ sk_sp<SkColorSpace> SkColorSpace::NewICC(const void* input, size_t len) { |
// Recognize color profile specified by A2B0 tag. |
const ICCTag* a2b0 = ICCTag::Find(tags.get(), tagCount, kTAG_A2B0); |
if (a2b0) { |
- // default to Linear transforms for when the curves are not |
- // in the profile (which is legal behavior for a profile) |
- SkGammaNamed aCurveNamed = kLinear_SkGammaNamed; |
- SkGammaNamed mCurveNamed = kLinear_SkGammaNamed; |
- SkGammaNamed bCurveNamed = kLinear_SkGammaNamed; |
- sk_sp<SkGammas> aCurve = nullptr; |
- sk_sp<SkGammas> mCurve = nullptr; |
- sk_sp<SkGammas> bCurve = nullptr; |
- sk_sp<SkColorLookUpTable> colorLUT = nullptr; |
- SkMatrix44 matrix(SkMatrix44::kUninitialized_Constructor); |
- if (!load_a2b0(&colorLUT, &aCurveNamed, &aCurve, &mCurveNamed, &mCurve, |
- &bCurveNamed, &bCurve, &matrix, a2b0->addr(base), a2b0->fLength)) { |
+ const SkColorSpace_A2B::PCS pcs = kXYZ_PCSSpace == header.fPCS |
+ ? SkColorSpace_A2B::PCS::kXYZ |
+ : SkColorSpace_A2B::PCS::kLAB; |
+ std::vector<SkColorSpace_A2B::Element> elements; |
+ if (!load_a2b0(&elements, a2b0->addr(base), a2b0->fLength)) { |
return_null("Failed to parse A2B0 tag"); |
} |
- |
- SkColorSpace_A2B::PCS pcs = SkColorSpace_A2B::PCS::kLAB; |
- if (header.fPCS == kXYZ_PCSSpace) { |
- pcs = SkColorSpace_A2B::PCS::kXYZ; |
- } |
- |
- return sk_sp<SkColorSpace>(new SkColorSpace_A2B(aCurveNamed, std::move(aCurve), |
- std::move(colorLUT), |
- mCurveNamed, std::move(mCurve), |
- matrix, |
- bCurveNamed, std::move(bCurve), |
- pcs, std::move(data))); |
+ return sk_sp<SkColorSpace>(new SkColorSpace_A2B(pcs, std::move(data), |
+ std::move(elements))); |
} |
} |
default: |