aboutsummaryrefslogtreecommitdiffhomepage
path: root/third_party/skcms/src
diff options
context:
space:
mode:
authorGravatar Mike Klein <mtklein@chromium.org>2018-04-11 10:26:09 -0400
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2018-04-11 15:01:37 +0000
commit73297197b2a27e288d7b9a4d8ff67f6ce5e25b10 (patch)
tree451a392fdbb78ecbac53afbc12c5f96d6987fafb /third_party/skcms/src
parent06a610c159615015fa134401e8876fd542e13117 (diff)
skcms→91a8958 Detect and canonicalize identity tables
Change-Id: I36957b8d7d96ac262b509c218779775c90864314 Reviewed-on: https://skia-review.googlesource.com/120420 Reviewed-by: Mike Klein <mtklein@chromium.org> Commit-Queue: Mike Klein <mtklein@chromium.org>
Diffstat (limited to 'third_party/skcms/src')
-rw-r--r--third_party/skcms/src/ICCProfile.c46
-rw-r--r--third_party/skcms/src/TransferFunction.c10
-rw-r--r--third_party/skcms/src/TransferFunction.h4
3 files changed, 50 insertions, 10 deletions
diff --git a/third_party/skcms/src/ICCProfile.c b/third_party/skcms/src/ICCProfile.c
index 9c504cd3ce..a21abd0041 100644
--- a/third_party/skcms/src/ICCProfile.c
+++ b/third_party/skcms/src/ICCProfile.c
@@ -226,7 +226,7 @@ static bool read_curve_curv(const uint8_t* buf, uint32_t size,
curve->parametric.e = 0.0f;
curve->parametric.f = 0.0f;
if (value_count == 0) {
- // Empty tables are a shorthand for linear
+ // Empty tables are a shorthand for an identity curve
curve->parametric.g = 1.0f;
} else {
// Single entry tables are a shorthand for simple gamma
@@ -581,15 +581,51 @@ static bool read_tag_mab(const skcms_ICCTag* tag, skcms_A2B* a2b, bool pcs_is_xy
}
static bool read_a2b(const skcms_ICCTag* tag, skcms_A2B* a2b, bool pcs_is_xyz) {
+ bool ok = false;
if (tag->type == make_signature('m', 'f', 't', '1')) {
- return read_tag_mft1(tag, a2b);
+ ok = read_tag_mft1(tag, a2b);
} else if (tag->type == make_signature('m', 'f', 't', '2')) {
- return read_tag_mft2(tag, a2b);
+ ok = read_tag_mft2(tag, a2b);
} else if (tag->type == make_signature('m', 'A', 'B', ' ')) {
- return read_tag_mab(tag, a2b, pcs_is_xyz);
+ ok = read_tag_mab(tag, a2b, pcs_is_xyz);
+ }
+ if (!ok) {
+ return false;
}
- return false;
+ // Detect and canonicalize identity tables.
+ skcms_Curve* curves[] = {
+ a2b->input_channels > 0 ? a2b->input_curves + 0 : NULL,
+ a2b->input_channels > 1 ? a2b->input_curves + 1 : NULL,
+ a2b->input_channels > 2 ? a2b->input_curves + 2 : NULL,
+ a2b->input_channels > 3 ? a2b->input_curves + 3 : NULL,
+ a2b->matrix_channels > 0 ? a2b->matrix_curves + 0 : NULL,
+ a2b->matrix_channels > 1 ? a2b->matrix_curves + 1 : NULL,
+ a2b->matrix_channels > 2 ? a2b->matrix_curves + 2 : NULL,
+ a2b->output_channels > 0 ? a2b->output_curves + 0 : NULL,
+ a2b->output_channels > 1 ? a2b->output_curves + 1 : NULL,
+ a2b->output_channels > 2 ? a2b->output_curves + 2 : NULL,
+ };
+
+ for (int i = 0; i < ARRAY_COUNT(curves); i++) {
+ skcms_Curve* curve = curves[i];
+
+ if (curve && curve->table_entries && curve->table_entries <= (uint32_t)INT_MAX) {
+ int N = (int)curve->table_entries;
+
+ skcms_TransferFunction tf;
+ if (N == skcms_fit_linear(curve, N, 1.0f/(2*N), &tf)
+ && tf.c == 1.0f
+ && tf.f == 0.0f) {
+ curve->table_entries = 0;
+ curve->table_8 = NULL;
+ curve->table_16 = NULL;
+ curve->parametric = (skcms_TransferFunction){1,1,0,0,0,0,0};
+ }
+ }
+ }
+
+ return true;
}
void skcms_GetTagByIndex(const skcms_ICCProfile* profile, uint32_t idx, skcms_ICCTag* tag) {
diff --git a/third_party/skcms/src/TransferFunction.c b/third_party/skcms/src/TransferFunction.c
index 6ddc9772d0..56245ad6d0 100644
--- a/third_party/skcms/src/TransferFunction.c
+++ b/third_party/skcms/src/TransferFunction.c
@@ -116,8 +116,8 @@ bool skcms_TransferFunction_invert(const skcms_TransferFunction* src, skcms_Tran
//
// Our overall strategy is then:
// For a couple tolerances,
-// - fit_linear(): fit c,d,f iteratively to as many points as our tolerance allows
-// - fit_nonlinear(): fit g,a,b using Gauss-Newton given c,d,f (and by constraint, e)
+// - skcms_fit_linear(): fit c,d,f iteratively to as many points as our tolerance allows
+// - fit_nonlinear(): fit g,a,b using Gauss-Newton given c,d,f (and by constraint, e)
// Return the parameters with least maximum error.
//
// To run Gauss-Newton to find g,a,b, we'll also need the gradient of the non-linear piece:
@@ -161,8 +161,8 @@ static void grad_nonlinear(float x, const void* ctx, const float P[4], float dfd
- g*powf_(D, g-1);
}
-// Returns the number of points that are approximated by the line, to within tol.
-static int fit_linear(const skcms_Curve* curve, int N, float tol, skcms_TransferFunction* tf) {
+int skcms_fit_linear(const skcms_Curve* curve, int N, float tol, skcms_TransferFunction* tf) {
+ assert(N > 1);
// We iteratively fit the first points to the TF's linear piece.
// We want the cx + f line to pass through the first and last points we fit exactly.
//
@@ -267,7 +267,7 @@ bool skcms_ApproximateCurve(const skcms_Curve* curve,
const float kTolerances[] = { 1.5f / 65535.0f, 1.0f / 512.0f };
for (int t = 0; t < ARRAY_COUNT(kTolerances); t++) {
skcms_TransferFunction tf;
- int L = fit_linear(curve, N, kTolerances[t], &tf);
+ int L = skcms_fit_linear(curve, N, kTolerances[t], &tf);
if (L == N) {
// If the entire data set was linear, move the coefficients to the nonlinear portion
diff --git a/third_party/skcms/src/TransferFunction.h b/third_party/skcms/src/TransferFunction.h
index c98c78d7e7..284b1364ed 100644
--- a/third_party/skcms/src/TransferFunction.h
+++ b/third_party/skcms/src/TransferFunction.h
@@ -14,3 +14,7 @@
float skcms_TransferFunction_eval(const skcms_TransferFunction*, float);
bool skcms_TransferFunction_invert(const skcms_TransferFunction*, skcms_TransferFunction*);
+
+// Fit c,d,f parameters of an skcms_TransferFunction to the first 2 < L ≤ N
+// evenly-spaced points on an skcms_Curve within a given tolerance, returning L.
+int skcms_fit_linear(const skcms_Curve*, int N, float tol, skcms_TransferFunction*);