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>
This commit is contained in:
Mike Klein 2018-04-16 14:48:27 -04:00 committed by Skia Commit-Bot
parent 888fc05ef0
commit c830e2a9ea
2 changed files with 48 additions and 0 deletions

View File

@ -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;

View File

@ -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];
}