diff options
author | 2018-04-11 10:26:09 -0400 | |
---|---|---|
committer | 2018-04-11 15:01:37 +0000 | |
commit | 73297197b2a27e288d7b9a4d8ff67f6ce5e25b10 (patch) | |
tree | 451a392fdbb78ecbac53afbc12c5f96d6987fafb /third_party/skcms/src | |
parent | 06a610c159615015fa134401e8876fd542e13117 (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.c | 46 | ||||
-rw-r--r-- | third_party/skcms/src/TransferFunction.c | 10 | ||||
-rw-r--r-- | third_party/skcms/src/TransferFunction.h | 4 |
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*); |