skcms→589b15b add skcms_EnsureUsableAsDestination
Change-Id: I6f5896299fec1a5fd6e593e3a831e080b30e6e21 Reviewed-on: https://skia-review.googlesource.com/122022 Reviewed-by: Mike Klein <mtklein@chromium.org> Commit-Queue: Mike Klein <mtklein@chromium.org>
This commit is contained in:
parent
366fc24752
commit
bef83531c7
5
third_party/skcms/skcms.h
vendored
5
third_party/skcms/skcms.h
vendored
@ -202,6 +202,11 @@ bool skcms_Transform(const void* src,
|
||||
const skcms_ICCProfile* dstProfile,
|
||||
size_t npixels);
|
||||
|
||||
// If profile cannot be used as a destination profile in skcms_Transform(),
|
||||
// rewrite it with approximations where reasonable or by pulling from fallback
|
||||
// (e.g. skcms_sRGB_profile) where not.
|
||||
void skcms_EnsureUsableAsDestination(skcms_ICCProfile* profile, const skcms_ICCProfile* fallback);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
97
third_party/skcms/src/Transform.c
vendored
97
third_party/skcms/src/Transform.c
vendored
@ -354,6 +354,24 @@ static skcms_Matrix3x3 concat_3x3(const skcms_Matrix3x3* A, const skcms_Matrix3x
|
||||
return m;
|
||||
}
|
||||
|
||||
static bool prep_for_destination(const skcms_ICCProfile* profile,
|
||||
skcms_Matrix3x3* fromXYZD50,
|
||||
skcms_TransferFunction* invR,
|
||||
skcms_TransferFunction* invG,
|
||||
skcms_TransferFunction* invB) {
|
||||
// We only support destinations with parametric transfer functions
|
||||
// and with gamuts that can be transformed from XYZD50.
|
||||
return profile->has_trc
|
||||
&& profile->has_toXYZD50
|
||||
&& profile->trc[0].table_entries == 0
|
||||
&& profile->trc[1].table_entries == 0
|
||||
&& profile->trc[2].table_entries == 0
|
||||
&& skcms_TransferFunction_invert(&profile->trc[0].parametric, invR)
|
||||
&& skcms_TransferFunction_invert(&profile->trc[1].parametric, invG)
|
||||
&& skcms_TransferFunction_invert(&profile->trc[2].parametric, invB)
|
||||
&& skcms_Matrix3x3_invert(&profile->toXYZD50, fromXYZD50);
|
||||
}
|
||||
|
||||
bool skcms_Transform(const void* src,
|
||||
skcms_PixelFormat srcFmt,
|
||||
skcms_AlphaFormat srcAlpha,
|
||||
@ -427,6 +445,11 @@ bool skcms_Transform(const void* src,
|
||||
srcAlpha == skcms_AlphaFormat_PremulLinear ||
|
||||
dstAlpha == skcms_AlphaFormat_PremulLinear) {
|
||||
|
||||
if (!prep_for_destination(dstProfile,
|
||||
&from_xyz, &inv_dst_tf_r, &inv_dst_tf_b, &inv_dst_tf_g)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (srcProfile->has_A2B) {
|
||||
if (srcProfile->A2B.input_channels) {
|
||||
for (int i = 0; i < (int)srcProfile->A2B.input_channels; i++) {
|
||||
@ -497,11 +520,6 @@ bool skcms_Transform(const void* src,
|
||||
*ops++ = Op_unpremul;
|
||||
}
|
||||
|
||||
// We only support destination gamuts that can be transformed from XYZD50.
|
||||
if (!dstProfile->has_toXYZD50) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// A2B sources should already be in XYZD50 at this point.
|
||||
// Others still need to be transformed using their toXYZD50 matrix.
|
||||
// N.B. There are profiles that contain both A2B tags and toXYZD50 matrices.
|
||||
@ -517,9 +535,6 @@ bool skcms_Transform(const void* src,
|
||||
// There's a chance the source and destination gamuts are identical,
|
||||
// in which case we can skip the gamut transform.
|
||||
if (0 != memcmp(&dstProfile->toXYZD50, to_xyz, sizeof(skcms_Matrix3x3))) {
|
||||
if (!skcms_Matrix3x3_invert(&dstProfile->toXYZD50, &from_xyz)) {
|
||||
return false;
|
||||
}
|
||||
// Concat the entire gamut transform into from_xyz,
|
||||
// now slightly misnamed but it's a handy spot to stash the result.
|
||||
from_xyz = concat_3x3(&from_xyz, to_xyz);
|
||||
@ -527,25 +542,14 @@ bool skcms_Transform(const void* src,
|
||||
*args++ = &from_xyz;
|
||||
}
|
||||
|
||||
// Encode back to dst RGB using its parametric transfer functions.
|
||||
if (dstProfile->has_trc &&
|
||||
dstProfile->trc[0].table_entries == 0 &&
|
||||
dstProfile->trc[1].table_entries == 0 &&
|
||||
dstProfile->trc[2].table_entries == 0 &&
|
||||
skcms_TransferFunction_invert(&dstProfile->trc[0].parametric, &inv_dst_tf_r) &&
|
||||
skcms_TransferFunction_invert(&dstProfile->trc[1].parametric, &inv_dst_tf_g) &&
|
||||
skcms_TransferFunction_invert(&dstProfile->trc[2].parametric, &inv_dst_tf_b)) {
|
||||
|
||||
if (dstAlpha == skcms_AlphaFormat_PremulLinear) {
|
||||
*ops++ = Op_premul;
|
||||
}
|
||||
|
||||
if (!is_identity_tf(&inv_dst_tf_r)) { *ops++ = Op_tf_r; *args++ = &inv_dst_tf_r; }
|
||||
if (!is_identity_tf(&inv_dst_tf_g)) { *ops++ = Op_tf_g; *args++ = &inv_dst_tf_g; }
|
||||
if (!is_identity_tf(&inv_dst_tf_b)) { *ops++ = Op_tf_b; *args++ = &inv_dst_tf_b; }
|
||||
} else {
|
||||
return false;
|
||||
if (dstAlpha == skcms_AlphaFormat_PremulLinear) {
|
||||
*ops++ = Op_premul;
|
||||
}
|
||||
|
||||
// Encode back to dst RGB using its parametric transfer functions.
|
||||
if (!is_identity_tf(&inv_dst_tf_r)) { *ops++ = Op_tf_r; *args++ = &inv_dst_tf_r; }
|
||||
if (!is_identity_tf(&inv_dst_tf_g)) { *ops++ = Op_tf_g; *args++ = &inv_dst_tf_g; }
|
||||
if (!is_identity_tf(&inv_dst_tf_b)) { *ops++ = Op_tf_b; *args++ = &inv_dst_tf_b; }
|
||||
}
|
||||
|
||||
if (dstAlpha == skcms_AlphaFormat_Opaque) {
|
||||
@ -582,3 +586,44 @@ bool skcms_Transform(const void* src,
|
||||
run(program, arguments, src, dst, n, src_bpp,dst_bpp);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void assert_usable_as_destination(const skcms_ICCProfile* profile) {
|
||||
#if defined(NDEBUG)
|
||||
(void)profile;
|
||||
#else
|
||||
skcms_Matrix3x3 fromXYZD50;
|
||||
skcms_TransferFunction invR, invG, invB;
|
||||
assert(prep_for_destination(profile, &fromXYZD50, &invR, &invG, &invB));
|
||||
#endif
|
||||
}
|
||||
|
||||
void skcms_EnsureUsableAsDestination(skcms_ICCProfile* profile, const skcms_ICCProfile* fallback) {
|
||||
assert_usable_as_destination(fallback);
|
||||
skcms_ICCProfile ok = *fallback;
|
||||
|
||||
skcms_Matrix3x3 fromXYZD50;
|
||||
if (profile->has_toXYZD50 && skcms_Matrix3x3_invert(&profile->toXYZD50, &fromXYZD50)) {
|
||||
ok.toXYZD50 = profile->toXYZD50;
|
||||
}
|
||||
|
||||
for (int i = 0; profile->has_trc && i < 3; i++) {
|
||||
skcms_TransferFunction inv;
|
||||
if (profile->trc[i].table_entries == 0
|
||||
&& skcms_TransferFunction_invert(&profile->trc[i].parametric, &inv)) {
|
||||
ok.trc[i] = profile->trc[i];
|
||||
continue;
|
||||
}
|
||||
|
||||
// Note there's a little gap here that we could fill by allowing fitting
|
||||
// parametric curves to non-invertible parametric curves.
|
||||
|
||||
float max_error;
|
||||
if (skcms_ApproximateCurve(&profile->trc[i], &ok.trc[i].parametric, &max_error)) {
|
||||
// Parametric curves from skcms_ApproximateCurve() are guaranteed to be invertible.
|
||||
ok.trc[i].table_entries = 0;
|
||||
}
|
||||
}
|
||||
|
||||
*profile = ok;
|
||||
assert_usable_as_destination(profile);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user