aboutsummaryrefslogtreecommitdiffhomepage
path: root/third_party/skcms/src/Transform.c
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/skcms/src/Transform.c')
-rw-r--r--third_party/skcms/src/Transform.c44
1 files changed, 44 insertions, 0 deletions
diff --git a/third_party/skcms/src/Transform.c b/third_party/skcms/src/Transform.c
index b3a6b55705..16cfaec0a2 100644
--- a/third_party/skcms/src/Transform.c
+++ b/third_party/skcms/src/Transform.c
@@ -6,6 +6,7 @@
*/
#include "../skcms.h"
+#include "GaussNewton.h"
#include "LinearAlgebra.h"
#include "Macros.h"
#include "PortableMath.h"
@@ -643,3 +644,46 @@ void skcms_EnsureUsableAsDestination(skcms_ICCProfile* profile, const skcms_ICCP
*profile = ok;
assert_usable_as_destination(profile);
}
+
+static float max_roundtrip_error(const skcms_TransferFunction* inv_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,
+ y = skcms_eval_curve(x, curve);
+ err = fmaxf_(err, fabsf_(x - skcms_TransferFunction_eval(inv_tf, y)));
+ }
+ return err;
+}
+
+void skcms_EnsureUsableAsDestinationWithSingleCurve(skcms_ICCProfile* profile,
+ const skcms_ICCProfile* fallback) {
+ // Operate on a copy of profile, so we can choose the best TF for the original curves
+ skcms_ICCProfile result = *profile;
+ skcms_EnsureUsableAsDestination(&result, fallback);
+
+ int best_tf = 0;
+ float min_max_error = INFINITY_;
+ const skcms_ICCProfile* ref = profile->has_trc ? profile : fallback;
+ for (int i = 0; i < 3; i++) {
+ skcms_TransferFunction inv;
+ skcms_TransferFunction_invert(&result.trc[i].parametric, &inv);
+
+ float err = 0;
+ for (int j = 0; j < 3; ++j) {
+ err = fmaxf_(err, max_roundtrip_error(&inv, &ref->trc[j]));
+ }
+ if (min_max_error > err) {
+ min_max_error = err;
+ best_tf = i;
+ }
+ }
+
+ for (int i = 0; i < 3; i++) {
+ result.trc[i].parametric = result.trc[best_tf].parametric;
+ }
+
+ *profile = result;
+ assert_usable_as_destination(profile);
+}