Index: third_party/qcms/src/chain.c |
diff --git a/third_party/qcms/src/chain.c b/third_party/qcms/src/chain.c |
index aa8506e41deeed4f2e19f2997cac000dc1c54b12..525507084b54596dc0dff6a14e6c2f61e223caa6 100644 |
--- a/third_party/qcms/src/chain.c |
+++ b/third_party/qcms/src/chain.c |
@@ -897,6 +897,7 @@ static struct qcms_modular_transform* qcms_modular_transform_create(qcms_profile |
{ |
struct qcms_modular_transform *first_transform = NULL; |
struct qcms_modular_transform **next_transform = &first_transform; |
+ qcms_bool transform_to_pcs_xyz_only = (out == NULL); |
if (in->color_space == RGB_SIGNATURE) { |
struct qcms_modular_transform* rgb_to_pcs; |
@@ -909,7 +910,7 @@ static struct qcms_modular_transform* qcms_modular_transform_create(qcms_profile |
goto fail; |
} |
- if (in->pcs == LAB_SIGNATURE && out->pcs == XYZ_SIGNATURE) { |
+ if (in->pcs == LAB_SIGNATURE && (transform_to_pcs_xyz_only || out->pcs == XYZ_SIGNATURE)) { |
struct qcms_modular_transform* lab_to_pcs; |
lab_to_pcs = qcms_modular_transform_alloc(); |
if (!lab_to_pcs) |
@@ -918,6 +919,9 @@ static struct qcms_modular_transform* qcms_modular_transform_create(qcms_profile |
lab_to_pcs->transform_module_fn = qcms_transform_module_LAB_to_XYZ; |
} |
+ if (transform_to_pcs_xyz_only) |
+ return first_transform; |
+ |
// This does not improve accuracy in practice, something is wrong here. |
//if (in->chromaticAdaption.invalid == false) { |
// struct qcms_modular_transform* chromaticAdaption; |
@@ -992,3 +996,31 @@ float* qcms_chain_transform(qcms_profile *in, qcms_profile *out, float *src, flo |
} |
return NULL; |
} |
+ |
+qcms_bool qcms_profile_white_transform(qcms_profile *profile, float XYZ[3]) |
+{ |
+ const float inverse_internal_scale = 1.999969482421875f; |
+ |
+ // Set the output profile to NULL to request a color transform to PCS XYZ only. |
+ struct qcms_modular_transform *transform_list = qcms_modular_transform_create(profile, NULL); |
+ |
+ // Now calculate how the profile transforms white input color to PCS XYZ space. |
+ if (transform_list != NULL) { |
+ XYZ[0] = XYZ[1] = XYZ[2] = 1.0f; // white input |
+ qcms_modular_transform_data(transform_list, XYZ, XYZ, 1); |
+ // qcms_modular_transform_create internally scales input by 1/1.999969482421875f |
+ // but no qcms changelog describes why / how that number was choosen. junov@ "it |
+ // might be related to the epsilon of the fixed-point type 2*(1-1/(2^16)), but |
+ // there is no explanation, which is disconcerting." Meanwhile, undo the internal |
+ // scaling so we return a normalized CIEXYZ value viz., where Y is scaled to 1.0. |
+ // A properly created color profile should produce Y=~1.0 in PCS XYZ with white |
+ // input (the D50 test). If it does not, then the profile is likely bogus. |
+ XYZ[0] *= inverse_internal_scale; |
+ XYZ[1] *= inverse_internal_scale; |
+ XYZ[2] *= inverse_internal_scale; |
+ qcms_modular_transform_release(transform_list); |
+ return true; |
+ } |
+ |
+ return false; |
+} |