diff options
author | 2016-05-18 06:28:43 -0700 | |
---|---|---|
committer | 2016-05-18 06:28:43 -0700 | |
commit | 61a999ca3e2c865a121a6eb378ff85a837b87a44 (patch) | |
tree | a26f61c68ee7b2e8f359482f1280cc41fce0b1f6 /src/core | |
parent | d1227a7417922ce26252d55815d0d1e98f0eb070 (diff) |
Parse parametric gamma curves
BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1972403002
Review-Url: https://codereview.chromium.org/1972403002
Diffstat (limited to 'src/core')
-rw-r--r-- | src/core/SkColorSpace.cpp | 84 | ||||
-rw-r--r-- | src/core/SkColorSpacePriv.h | 26 |
2 files changed, 99 insertions, 11 deletions
diff --git a/src/core/SkColorSpace.cpp b/src/core/SkColorSpace.cpp index 59013fe7cb..52e4ced85d 100644 --- a/src/core/SkColorSpace.cpp +++ b/src/core/SkColorSpace.cpp @@ -362,7 +362,7 @@ bool SkColorSpace::LoadGammas(SkGammaCurve* gammas, uint32_t numGammas, const ui // a count of 0. gammas[i].fValue = 1.0f; break; - } else if (len < 12 + 2 * count) { + } else if (len < tagBytes) { SkColorSpacePrintf("gamma tag is too small (%d bytes)", len); return false; } @@ -429,27 +429,93 @@ bool SkColorSpace::LoadGammas(SkGammaCurve* gammas, uint32_t numGammas, const ui break; } case kTAG_ParaCurveType: - // Guess 2.2f. - // FIXME (msarett): Handle parametric curves. - SkColorSpacePrintf("parametric curve\n"); - gammas[i].fValue = 2.2f; - - // Determine the size of the parametric curve tag. + // Determine the format of the parametric curve tag. switch(read_big_endian_short(src + 8)) { - case 0: + case 0: { tagBytes = 12 + 4; + if (len < tagBytes) { + SkColorSpacePrintf("gamma tag is too small (%d bytes)", len); + return false; + } + + // Y = X^g + int32_t g = read_big_endian_int(src + 12); + gammas[i].fValue = SkFixedToFloat(g); break; - case 1: + } + + // Here's where the real parametric gammas start. There are many + // permutations of the same equations. + // + // Y = (aX + b)^g + c for X >= d + // Y = eX + f otherwise + // + // We will fill in with zeros as necessary to always match the above form. + // Note that there is no need to actually write zero, since the struct is + // zero initialized. + case 1: { tagBytes = 12 + 12; + if (len < tagBytes) { + SkColorSpacePrintf("gamma tag is too small (%d bytes)", len); + return false; + } + + // Y = (aX + b)^g for X >= -b/a + // Y = 0 otherwise + gammas[i].fG = SkFixedToFloat(read_big_endian_int(src + 12)); + gammas[i].fA = SkFixedToFloat(read_big_endian_int(src + 16)); + gammas[i].fB = SkFixedToFloat(read_big_endian_int(src + 20)); + gammas[i].fD = -gammas[i].fB / gammas[i].fA; break; + } case 2: tagBytes = 12 + 16; + if (len < tagBytes) { + SkColorSpacePrintf("gamma tag is too small (%d bytes)", len); + return false; + } + + // Y = (aX + b)^g + c for X >= -b/a + // Y = c otherwise + gammas[i].fG = SkFixedToFloat(read_big_endian_int(src + 12)); + gammas[i].fA = SkFixedToFloat(read_big_endian_int(src + 16)); + gammas[i].fB = SkFixedToFloat(read_big_endian_int(src + 20)); + gammas[i].fC = SkFixedToFloat(read_big_endian_int(src + 24)); + gammas[i].fD = -gammas[i].fB / gammas[i].fA; + gammas[i].fF = gammas[i].fC; break; case 3: tagBytes = 12 + 20; + if (len < tagBytes) { + SkColorSpacePrintf("gamma tag is too small (%d bytes)", len); + return false; + } + + // Y = (aX + b)^g for X >= d + // Y = cX otherwise + gammas[i].fG = SkFixedToFloat(read_big_endian_int(src + 12)); + gammas[i].fA = SkFixedToFloat(read_big_endian_int(src + 16)); + gammas[i].fB = SkFixedToFloat(read_big_endian_int(src + 20)); + gammas[i].fD = SkFixedToFloat(read_big_endian_int(src + 28)); + gammas[i].fE = SkFixedToFloat(read_big_endian_int(src + 24)); break; case 4: tagBytes = 12 + 28; + if (len < tagBytes) { + SkColorSpacePrintf("gamma tag is too small (%d bytes)", len); + return false; + } + + // Y = (aX + b)^g + c for X >= d + // Y = eX + f otherwise + // NOTE: The ICC spec writes "cX" instead of "eX" but I think it's a typo. + gammas[i].fG = SkFixedToFloat(read_big_endian_int(src + 12)); + gammas[i].fA = SkFixedToFloat(read_big_endian_int(src + 16)); + gammas[i].fB = SkFixedToFloat(read_big_endian_int(src + 20)); + gammas[i].fC = SkFixedToFloat(read_big_endian_int(src + 24)); + gammas[i].fD = SkFixedToFloat(read_big_endian_int(src + 28)); + gammas[i].fE = SkFixedToFloat(read_big_endian_int(src + 32)); + gammas[i].fF = SkFixedToFloat(read_big_endian_int(src + 36)); break; default: SkColorSpacePrintf("Invalid parametric curve type\n"); diff --git a/src/core/SkColorSpacePriv.h b/src/core/SkColorSpacePriv.h index 47fab647ff..a6274c7823 100644 --- a/src/core/SkColorSpacePriv.h +++ b/src/core/SkColorSpacePriv.h @@ -12,17 +12,24 @@ struct SkGammaCurve { bool isValue() const { bool result = (0.0f != fValue); SkASSERT(!result || (0 == fTableSize)); + SkASSERT(!result || (0.0f == fG)); return result; } bool isTable() const { bool result = (0 != fTableSize); SkASSERT(!result || (0.0f == fValue)); + SkASSERT(!result || (0.0f == fG)); SkASSERT(!result || fTable); return result; } - bool isParametric() const { return false; } + bool isParametric() const { + bool result = (0.0f != fG); + SkASSERT(!result || (0.0f == fValue)); + SkASSERT(!result || (0 == fTableSize)); + return result; + } // We have three different ways to represent gamma. // (1) A single value: @@ -33,7 +40,15 @@ struct SkGammaCurve { std::unique_ptr<float[]> fTable; // (3) Parameters for a curve: - // FIXME (msarett): Handle parametric curves. + // Y = (aX + b)^g + c for X >= d + // Y = eX + f otherwise + float fG; + float fA; + float fB; + float fC; + float fD; + float fE; + float fF; SkGammaCurve() { memset(this, 0, sizeof(struct SkGammaCurve)); @@ -43,6 +58,13 @@ struct SkGammaCurve { : fValue(value) , fTableSize(0) , fTable(nullptr) + , fG(0.0f) + , fA(0.0f) + , fB(0.0f) + , fC(0.0f) + , fD(0.0f) + , fE(0.0f) + , fF(0.0f) {} }; |