aboutsummaryrefslogtreecommitdiffhomepage
path: root/third_party/skcms
diff options
context:
space:
mode:
authorGravatar Mike Klein <mtklein@chromium.org>2018-04-16 14:48:27 -0400
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2018-04-16 19:29:40 +0000
commitc830e2a9ea6f4bdbbdeb76b6a2ddda1ef0da710e (patch)
treec9c71c4d91960e71a4760384d74e786b85ea624f /third_party/skcms
parent888fc05ef08971628a3b3044b7a99ec3dd53c386 (diff)
skcms→2667f0a Add skcms_BestSingleCurve utility
Change-Id: Ibfca9738770c6599826c6bcc18d7a117abd9a1eb Reviewed-on: https://skia-review.googlesource.com/121660 Reviewed-by: Mike Klein <mtklein@chromium.org> Commit-Queue: Mike Klein <mtklein@chromium.org> Auto-Submit: Mike Klein <mtklein@chromium.org>
Diffstat (limited to 'third_party/skcms')
-rw-r--r--third_party/skcms/skcms.h4
-rw-r--r--third_party/skcms/src/TransferFunction.c44
2 files changed, 48 insertions, 0 deletions
diff --git a/third_party/skcms/skcms.h b/third_party/skcms/skcms.h
index 2546f9c78c..4e1858098c 100644
--- a/third_party/skcms/skcms.h
+++ b/third_party/skcms/skcms.h
@@ -123,6 +123,10 @@ typedef struct {
bool skcms_ApproximateCurve13(const skcms_Curve* curve, skcms_TF13* approx, float* max_error);
+// What is the best single transfer function to use for the given profile? Note that there is
+// no real upper bound on the error of this transfer function.
+skcms_TransferFunction skcms_BestSingleCurve(const skcms_ICCProfile*);
+
typedef struct {
uint32_t signature;
uint32_t type;
diff --git a/third_party/skcms/src/TransferFunction.c b/third_party/skcms/src/TransferFunction.c
index 56245ad6d0..d5ecfdfe08 100644
--- a/third_party/skcms/src/TransferFunction.c
+++ b/third_party/skcms/src/TransferFunction.c
@@ -321,3 +321,47 @@ bool skcms_ApproximateCurve(const skcms_Curve* curve,
}
return isfinitef_(*max_error);
}
+
+static float max_error_over_curve(const skcms_TransferFunction* tf, const skcms_Curve* curve) {
+ int N = curve->table_entries ? (int)curve->table_entries : 256;
+ const float x_scale = 1.0f / (N - 1);
+ float err = 0;
+ for (int i = 0; i < N; i++) {
+ float x = i * x_scale;
+ err = fmaxf_(err, fabsf_(skcms_eval_curve(x, curve) - skcms_TransferFunction_eval(tf, x)));
+ }
+ return err;
+}
+
+skcms_TransferFunction skcms_BestSingleCurve(const skcms_ICCProfile* profile) {
+ if (!profile || !profile->has_trc) {
+ return skcms_sRGB_profile.trc[0].parametric;
+ }
+
+ skcms_TransferFunction tf[3];
+ for (int i = 0; i < 3; ++i) {
+ if (profile->trc[i].table_entries) {
+ float max_error;
+ if (!skcms_ApproximateCurve(&profile->trc[i], &tf[i], &max_error)) {
+ return skcms_sRGB_profile.trc[0].parametric;
+ }
+ } else {
+ tf[i] = profile->trc[i].parametric;
+ }
+ }
+
+ int best_tf = 0;
+ float min_max_error = INFINITY_;
+ for (int i = 0; i < 3; ++i) {
+ float err = 0;
+ for (int j = 0; j < 3; ++j) {
+ err = fmaxf_(err, max_error_over_curve(&tf[i], &profile->trc[j]));
+ }
+ if (min_max_error > err) {
+ min_max_error = err;
+ best_tf = i;
+ }
+ }
+
+ return tf[best_tf];
+}