diff options
author | Pekka Paalanen <pekka.paalanen@collabora.com> | 2024-04-10 14:19:45 +0300 |
---|---|---|
committer | Pekka Paalanen <pq@iki.fi> | 2024-04-19 12:19:36 +0000 |
commit | 94ccce4e3866c42e62ea68c66698b4b678bbb066 (patch) | |
tree | aa3898108667b35b64574181ba3aef560fd42bc7 | |
parent | 7d38e044dd086fad7c81c790de0b9050c224f0e5 (diff) |
tests: replace mat2XYZ
The primaries and the white point are the fundamental definition of the
color spaces in these tests. Instead of hard-coding mat2XYZ, use
LittleCMS to derive the result from the fundamental definition.
This removes derived hard-coded constants, which is a benefit in itself.
How these constants were originally produced was not mentioned in
0c5860fafb079b8edba66e4e805d26b563c8e529 but I was able to reproduce
them with python3:
import colour
import numpy as np
x = colour.RGB_COLOURSPACES['sRGB']
w_d50 = np.array([0.34567, 0.35850])
print(x.chromatically_adapt(w_d50, 'D50', 'Bradford'))
It's identical to 3-4 decimals of the hardcoded values, and also for
Adobe RGB. I printed the LittleCMS generated values as well, and they
are the same as with python up to roughly 4 decimals.
Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
-rw-r--r-- | tests/color-icc-output-test.c | 6 | ||||
-rw-r--r-- | tests/color-management-test.c | 3 | ||||
-rw-r--r-- | tests/lcms_util.c | 73 | ||||
-rw-r--r-- | tests/lcms_util.h | 6 |
4 files changed, 57 insertions, 31 deletions
diff --git a/tests/color-icc-output-test.c b/tests/color-icc-output-test.c index 9c71a239..5cd10afb 100644 --- a/tests/color-icc-output-test.c +++ b/tests/color-icc-output-test.c @@ -59,9 +59,6 @@ const struct lcms_pipeline pipeline_sRGB = { .mat = LCMSMAT3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0), - .mat2XYZ = LCMSMAT3(0.436037, 0.385124, 0.143039, - 0.222482, 0.716913, 0.060605, - 0.013922, 0.097078, 0.713899), .post_fn = TRANSFER_FN_SRGB_EOTF_INVERSE }; @@ -76,9 +73,6 @@ const struct lcms_pipeline pipeline_adobeRGB = { .mat = LCMSMAT3( 0.715127, 0.284868, 0.000005, 0.000001, 0.999995, 0.000004, -0.000003, 0.041155, 0.958848), - .mat2XYZ = LCMSMAT3(0.609740, 0.205279, 0.149181, - 0.311111, 0.625681, 0.063208, - 0.019469, 0.060879, 0.744552), .post_fn = TRANSFER_FN_ADOBE_RGB_EOTF_INVERSE }; diff --git a/tests/color-management-test.c b/tests/color-management-test.c index 5db56153..ec748667 100644 --- a/tests/color-management-test.c +++ b/tests/color-management-test.c @@ -61,9 +61,6 @@ const struct lcms_pipeline pipeline_sRGB = { .mat = LCMSMAT3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0), - .mat2XYZ = LCMSMAT3(0.436037, 0.385124, 0.143039, - 0.222482, 0.716913, 0.060605, - 0.013922, 0.097078, 0.713899), .post_fn = TRANSFER_FN_SRGB_EOTF_INVERSE }; diff --git a/tests/lcms_util.c b/tests/lcms_util.c index 7478a967..3fcd5712 100644 --- a/tests/lcms_util.c +++ b/tests/lcms_util.c @@ -32,11 +32,12 @@ #include <assert.h> #include <stdlib.h> +#include <libweston/matrix.h> #include "shared/helpers.h" #include "color_util.h" #include "lcms_util.h" -static cmsCIExyY wp_d65 = { 0.31271, 0.32902, 1.0 }; +static const cmsCIExyY wp_d65 = { 0.31271, 0.32902, 1.0 }; /* * MPE tone curves can only use LittleCMS parametric curve types 6-8 and not @@ -280,32 +281,33 @@ roundtrip_verification(cmsPipeline *DToB, cmsPipeline *BToD, float tolerance) assert(stat.two_norm.max < tolerance); } +struct transform_sampler_context { + cmsHTRANSFORM t; +}; + static cmsInt32Number -sampler_matrix(const float src[], float dst[], void *cargo) +transform_sampler(const float src[], float dst[], void *cargo) { - const struct lcmsMAT3 *mat = cargo; - struct color_float in = { .r = src[0], .g = src[1], .b = src[2] }; - struct color_float cf; - unsigned i; - - cf = color_float_apply_matrix(mat, in); + const struct transform_sampler_context *tsc = cargo; - for (i = 0; i < COLOR_CHAN_NUM; i++) - dst[i] = cf.rgb[i]; + cmsDoTransform(tsc->t, src, dst, 1); return 1; } static cmsStage * -create_cLUT_from_matrix(cmsContext context_id, const struct lcmsMAT3 *mat, - int dim_size) +create_cLUT_from_transform(cmsContext context_id, const cmsHTRANSFORM t, + int dim_size) { + struct transform_sampler_context tsc; cmsStage *cLUT_stage; assert(dim_size); + tsc.t = t; + cLUT_stage = cmsStageAllocCLutFloat(context_id, dim_size, 3, 3, NULL); - cmsStageSampleCLutFloat(cLUT_stage, sampler_matrix, (void *)mat, 0); + cmsStageSampleCLutFloat(cLUT_stage, transform_sampler, &tsc, 0); return cLUT_stage; } @@ -341,9 +343,41 @@ build_lcms_clut_profile_output(cmsContext context_id, cmsStage *stage; cmsStage *stage_inv_eotf; cmsStage *stage_eotf; - struct lcmsMAT3 mat2XYZ_inv; + cmsToneCurve *identity_curves[3]; + cmsHPROFILE linear_device; + cmsHPROFILE pcs; + cmsHTRANSFORM linear_device_to_pcs; + cmsHTRANSFORM pcs_to_linear_device; + + identity_curves[0] = identity_curves[1] = identity_curves[2] = + cmsBuildGamma(context_id, 1.0); - lcmsMAT3_invert(&mat2XYZ_inv, &pipeline->mat2XYZ); + linear_device = cmsCreateRGBProfileTHR(context_id, &wp_d65, + &pipeline->prim_output, + identity_curves); + assert(cmsIsMatrixShaper(linear_device)); + cmsFreeToneCurve(identity_curves[0]); + + pcs = cmsCreateXYZProfileTHR(context_id); + + /* + * Since linear_device is a matrix-shaper profile, all rendering intents + * share the same device<->PCS transformations. We only need to pick + * an arbitrary rendering intent that allows to turn BPC both on and off. + */ + linear_device_to_pcs = cmsCreateTransformTHR(context_id, + linear_device, TYPE_RGB_FLT, + pcs, TYPE_XYZ_FLT, + INTENT_RELATIVE_COLORIMETRIC, + cmsFLAGS_NOOPTIMIZE); + pcs_to_linear_device = cmsCreateTransformTHR(context_id, + pcs, TYPE_XYZ_FLT, + linear_device, TYPE_RGB_FLT, + INTENT_RELATIVE_COLORIMETRIC, + cmsFLAGS_NOOPTIMIZE); + + cmsCloseProfile(linear_device); + cmsCloseProfile(pcs); hRGB = cmsCreateProfilePlaceholder(context_id); cmsSetProfileVersion(hRGB, 4.3); @@ -360,7 +394,8 @@ build_lcms_clut_profile_output(cmsContext context_id, */ BToD0 = cmsPipelineAlloc(context_id, 3, 3); - stage = create_cLUT_from_matrix(context_id, &mat2XYZ_inv, clut_dim_size); + stage = create_cLUT_from_transform(context_id, pcs_to_linear_device, + clut_dim_size); cmsPipelineInsertStage(BToD0, cmsAT_END, stage); cmsPipelineInsertStage(BToD0, cmsAT_END, cmsStageDup(stage_inv_eotf)); @@ -375,7 +410,8 @@ build_lcms_clut_profile_output(cmsContext context_id, DToB0 = cmsPipelineAlloc(context_id, 3, 3); cmsPipelineInsertStage(DToB0, cmsAT_END, cmsStageDup(stage_eotf)); - stage = create_cLUT_from_matrix(context_id, &pipeline->mat2XYZ, clut_dim_size); + stage = create_cLUT_from_transform(context_id, linear_device_to_pcs, + clut_dim_size); cmsPipelineInsertStage(DToB0, cmsAT_END, stage); cmsWriteTag(hRGB, cmsSigDToB0Tag, DToB0); @@ -392,6 +428,9 @@ build_lcms_clut_profile_output(cmsContext context_id, cmsStageFree(stage_eotf); cmsStageFree(stage_inv_eotf); + cmsDeleteTransform(linear_device_to_pcs); + cmsDeleteTransform(pcs_to_linear_device); + return hRGB; } diff --git a/tests/lcms_util.h b/tests/lcms_util.h index 5afe671c..78feefa6 100644 --- a/tests/lcms_util.h +++ b/tests/lcms_util.h @@ -36,6 +36,7 @@ struct lcms_pipeline { const char *color_space; /** * Chromaticities for output profile + * White point is assumed to be D65. */ cmsCIExyYTRIPLE prim_output; /** @@ -47,11 +48,6 @@ struct lcms_pipeline { */ struct lcmsMAT3 mat; /** - * matrix from prim_output to XYZ, for example matrix conversion - * sRGB->XYZ, adobeRGB->XYZ, bt2020->XYZ - */ - struct lcmsMAT3 mat2XYZ; - /** * tone curve enum */ enum transfer_fn post_fn; |