aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core
diff options
context:
space:
mode:
authorGravatar msarett <msarett@google.com>2016-05-18 06:28:43 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2016-05-18 06:28:43 -0700
commit61a999ca3e2c865a121a6eb378ff85a837b87a44 (patch)
treea26f61c68ee7b2e8f359482f1280cc41fce0b1f6 /src/core
parentd1227a7417922ce26252d55815d0d1e98f0eb070 (diff)
Parse parametric gamma curves
Diffstat (limited to 'src/core')
-rw-r--r--src/core/SkColorSpace.cpp84
-rw-r--r--src/core/SkColorSpacePriv.h26
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)
{}
};