aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core
diff options
context:
space:
mode:
authorGravatar msarett <msarett@google.com>2016-06-01 14:43:36 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2016-06-01 14:43:36 -0700
commit81e4cc7723ea87de8b8917e52cc25f524225fa43 (patch)
treef46e15ca0713ec4259522a97a6cdd8240bb73694 /src/core
parentf7cfa920f41e39bcae4996288dffae53408ca0ed (diff)
Recognize common parametric gamma
5% of images with ICC profiles (in my test set of 10k) have this exact gamma representation, which is very close to 2.2f. BUG=skia: GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2027413002 Review-Url: https://codereview.chromium.org/2027413002
Diffstat (limited to 'src/core')
-rw-r--r--src/core/SkColorSpace.cpp179
1 files changed, 100 insertions, 79 deletions
diff --git a/src/core/SkColorSpace.cpp b/src/core/SkColorSpace.cpp
index 3ca131d427..18b07bca28 100644
--- a/src/core/SkColorSpace.cpp
+++ b/src/core/SkColorSpace.cpp
@@ -483,22 +483,20 @@ bool load_gammas(SkGammaCurve* gammas, uint32_t numGammas, const uint8_t* src, s
}
break;
}
- case kTAG_ParaCurveType:
+ case kTAG_ParaCurveType: {
// Determine the format of the parametric curve tag.
- switch(read_big_endian_short(src + 8)) {
- 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;
+ uint16_t format = read_big_endian_short(src + 8);
+ if (0 == format) {
+ 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);
+ } else {
// Here's where the real parametric gammas start. There are many
// permutations of the same equations.
//
@@ -506,77 +504,100 @@ bool load_gammas(SkGammaCurve* gammas, uint32_t numGammas, const uint8_t* src, s
// 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;
+ float g = 0.0f, a = 0.0f, b = 0.0f, c = 0.0f, d = 0.0f, e = 0.0f, f = 0.0f;
+ switch(format) {
+ 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
+ g = SkFixedToFloat(read_big_endian_int(src + 12));
+ a = SkFixedToFloat(read_big_endian_int(src + 16));
+ b = SkFixedToFloat(read_big_endian_int(src + 20));
+ d = -b / a;
+ break;
}
-
- // 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);
+ 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
+ g = SkFixedToFloat(read_big_endian_int(src + 12));
+ a = SkFixedToFloat(read_big_endian_int(src + 16));
+ b = SkFixedToFloat(read_big_endian_int(src + 20));
+ c = SkFixedToFloat(read_big_endian_int(src + 24));
+ d = -b / a;
+ f = c;
+ 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
+ g = SkFixedToFloat(read_big_endian_int(src + 12));
+ a = SkFixedToFloat(read_big_endian_int(src + 16));
+ b = SkFixedToFloat(read_big_endian_int(src + 20));
+ d = SkFixedToFloat(read_big_endian_int(src + 28));
+ e = 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" in place of "eX" but I think
+ // it's a typo.
+ g = SkFixedToFloat(read_big_endian_int(src + 12));
+ a = SkFixedToFloat(read_big_endian_int(src + 16));
+ b = SkFixedToFloat(read_big_endian_int(src + 20));
+ c = SkFixedToFloat(read_big_endian_int(src + 24));
+ d = SkFixedToFloat(read_big_endian_int(src + 28));
+ e = SkFixedToFloat(read_big_endian_int(src + 32));
+ f = SkFixedToFloat(read_big_endian_int(src + 36));
+ break;
+ default:
+ SkColorSpacePrintf("Invalid parametric curve type\n");
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");
- return false;
+ // Recognize and simplify a very common parametric representation of sRGB gamma.
+ if (color_space_almost_equal(0.9479f, a) &&
+ color_space_almost_equal(0.0521f, b) &&
+ color_space_almost_equal(0.0000f, c) &&
+ color_space_almost_equal(0.0405f, d) &&
+ color_space_almost_equal(0.0774f, e) &&
+ color_space_almost_equal(0.0000f, f) &&
+ color_space_almost_equal(2.4000f, g)) {
+ gammas[i].fValue = 2.2f;
+ } else {
+ gammas[i].fG = g;
+ gammas[i].fA = a;
+ gammas[i].fB = b;
+ gammas[i].fC = c;
+ gammas[i].fD = d;
+ gammas[i].fE = e;
+ gammas[i].fF = f;
+ }
}
+
break;
+ }
default:
SkColorSpacePrintf("Unsupported gamma tag type %d\n", type);
return false;