tests: move functions that create ICC profiles to lcms_util.c
We'll need to craft ICC profiles in the CM&HDR protocol implementation tests. So move it from color-icc-output-test.c to the LittleCMS helper in our test suite. This also removes some unused headers from color-icc-output-test.c, as we've moved a bunch of code to the LittleCMS helper. Signed-off-by: Leandro Ribeiro <leandro.ribeiro@collabora.com>
This commit is contained in:
parent
0de497f868
commit
ac3e416402
|
@ -26,52 +26,15 @@
|
|||
|
||||
#include "config.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <linux/limits.h>
|
||||
|
||||
#include <lcms2.h>
|
||||
|
||||
#include "weston-test-client-helper.h"
|
||||
#include "weston-test-fixture-compositor.h"
|
||||
#include "color_util.h"
|
||||
#include "image-iter.h"
|
||||
#include "lcms_util.h"
|
||||
|
||||
struct lcms_pipeline {
|
||||
/**
|
||||
* Color space name
|
||||
*/
|
||||
const char *color_space;
|
||||
/**
|
||||
* Chromaticities for output profile
|
||||
*/
|
||||
cmsCIExyYTRIPLE prim_output;
|
||||
/**
|
||||
* tone curve enum
|
||||
*/
|
||||
enum transfer_fn pre_fn;
|
||||
/**
|
||||
* Transform matrix from sRGB to target chromaticities in prim_output
|
||||
*/
|
||||
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;
|
||||
};
|
||||
|
||||
static const int WINDOW_WIDTH = 256;
|
||||
static const int WINDOW_HEIGHT = 24;
|
||||
|
||||
static cmsCIExyY wp_d65 = { 0.31271, 0.32902, 1.0 };
|
||||
|
||||
enum profile_type {
|
||||
PTYPE_MATRIX_SHAPER,
|
||||
PTYPE_CLUT,
|
||||
|
@ -182,99 +145,6 @@ static const struct setup_args my_setup_args[] = {
|
|||
{ { "sRGB->adobeRGB CLUT VCGT" }, 4, &pipeline_adobeRGB, 1.1, 17, PTYPE_CLUT, 0.0065, {1.1, 1.2, 1.3} },
|
||||
};
|
||||
|
||||
static void
|
||||
test_roundtrip(uint8_t r, uint8_t g, uint8_t b, cmsPipeline *pip,
|
||||
struct rgb_diff_stat *stat)
|
||||
{
|
||||
struct color_float in = { .rgb = { r / 255.0, g / 255.0, b / 255.0 } };
|
||||
struct color_float out = {};
|
||||
|
||||
cmsPipelineEvalFloat(in.rgb, out.rgb, pip);
|
||||
rgb_diff_stat_update(stat, &in, &out, &in);
|
||||
}
|
||||
|
||||
/*
|
||||
* Roundtrip verification tests that converting device -> PCS -> device
|
||||
* results in the original color values close enough.
|
||||
*
|
||||
* This ensures that the two pipelines are probably built correctly, and we
|
||||
* do not have problems with unexpected value clamping or with representing
|
||||
* (inverse) EOTF curves.
|
||||
*/
|
||||
static void
|
||||
roundtrip_verification(cmsPipeline *DToB, cmsPipeline *BToD, float tolerance)
|
||||
{
|
||||
unsigned r, g, b;
|
||||
struct rgb_diff_stat stat = {};
|
||||
cmsPipeline *pip;
|
||||
|
||||
pip = cmsPipelineDup(DToB);
|
||||
cmsPipelineCat(pip, BToD);
|
||||
|
||||
/*
|
||||
* Inverse-EOTF is known to have precision problems near zero, so
|
||||
* sample near zero densely, the rest can be more sparse to run faster.
|
||||
*/
|
||||
for (r = 0; r < 256; r += (r < 15) ? 1 : 8) {
|
||||
for (g = 0; g < 256; g += (g < 15) ? 1 : 8) {
|
||||
for (b = 0; b < 256; b += (b < 15) ? 1 : 8)
|
||||
test_roundtrip(r, g, b, pip, &stat);
|
||||
}
|
||||
}
|
||||
|
||||
cmsPipelineFree(pip);
|
||||
|
||||
rgb_diff_stat_print(&stat, "DToB->BToD roundtrip", 8);
|
||||
assert(stat.two_norm.max < tolerance);
|
||||
}
|
||||
|
||||
static cmsInt32Number
|
||||
sampler_matrix(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);
|
||||
|
||||
for (i = 0; i < COLOR_CHAN_NUM; i++)
|
||||
dst[i] = cf.rgb[i];
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cmsStage *
|
||||
create_cLUT_from_matrix(cmsContext context_id, const struct lcmsMAT3 *mat, int dim_size)
|
||||
{
|
||||
cmsStage *cLUT_stage;
|
||||
|
||||
assert(dim_size);
|
||||
|
||||
cLUT_stage = cmsStageAllocCLutFloat(context_id, dim_size, 3, 3, NULL);
|
||||
cmsStageSampleCLutFloat(cLUT_stage, sampler_matrix, (void *)mat, 0);
|
||||
|
||||
return cLUT_stage;
|
||||
}
|
||||
|
||||
static void
|
||||
vcgt_tag_add_to_profile(cmsContext context_id, cmsHPROFILE profile,
|
||||
const double vcgt_exponents[COLOR_CHAN_NUM])
|
||||
{
|
||||
cmsToneCurve *vcgt_tag_curves[COLOR_CHAN_NUM];
|
||||
unsigned int i;
|
||||
|
||||
if (!should_include_vcgt(vcgt_exponents))
|
||||
return;
|
||||
|
||||
for (i = 0; i < COLOR_CHAN_NUM; i++)
|
||||
vcgt_tag_curves[i] = cmsBuildGamma(context_id, vcgt_exponents[i]);
|
||||
|
||||
assert(cmsWriteTag(profile, cmsSigVcgtTag, vcgt_tag_curves));
|
||||
|
||||
cmsFreeToneCurveTriple(vcgt_tag_curves);
|
||||
}
|
||||
|
||||
/*
|
||||
* Originally the cLUT profile test attempted to use the AToB/BToA tags. Those
|
||||
* come with serious limitations though: at most uint16 representation for
|
||||
|
@ -308,116 +178,19 @@ vcgt_tag_add_to_profile(cmsContext context_id, cmsHPROFILE profile,
|
|||
* BT.2020 color space is not used in the cLUT test. AdobeRGB is enough.
|
||||
*/
|
||||
static cmsHPROFILE
|
||||
build_lcms_clut_profile_output(cmsContext context_id,
|
||||
const struct setup_args *arg)
|
||||
{
|
||||
enum transfer_fn inv_eotf_fn = arg->pipeline->post_fn;
|
||||
enum transfer_fn eotf_fn = transfer_fn_invert(inv_eotf_fn);
|
||||
cmsHPROFILE hRGB;
|
||||
cmsPipeline *DToB0, *BToD0;
|
||||
cmsStage *stage;
|
||||
cmsStage *stage_inv_eotf;
|
||||
cmsStage *stage_eotf;
|
||||
struct lcmsMAT3 mat2XYZ_inv;
|
||||
|
||||
lcmsMAT3_invert(&mat2XYZ_inv, &arg->pipeline->mat2XYZ);
|
||||
|
||||
hRGB = cmsCreateProfilePlaceholder(context_id);
|
||||
cmsSetProfileVersion(hRGB, 4.3);
|
||||
cmsSetDeviceClass(hRGB, cmsSigDisplayClass);
|
||||
cmsSetColorSpace(hRGB, cmsSigRgbData);
|
||||
cmsSetPCS(hRGB, cmsSigXYZData);
|
||||
SetTextTags(hRGB, L"cLut profile");
|
||||
|
||||
stage_eotf = build_MPE_curve_stage(context_id, eotf_fn);
|
||||
stage_inv_eotf = build_MPE_curve_stage(context_id, inv_eotf_fn);
|
||||
|
||||
/*
|
||||
* Pipeline from PCS (optical) to device (electrical)
|
||||
*/
|
||||
BToD0 = cmsPipelineAlloc(context_id, 3, 3);
|
||||
|
||||
stage = create_cLUT_from_matrix(context_id, &mat2XYZ_inv, arg->dim_size);
|
||||
cmsPipelineInsertStage(BToD0, cmsAT_END, stage);
|
||||
cmsPipelineInsertStage(BToD0, cmsAT_END, cmsStageDup(stage_inv_eotf));
|
||||
|
||||
cmsWriteTag(hRGB, cmsSigBToD0Tag, BToD0);
|
||||
cmsLinkTag(hRGB, cmsSigBToD1Tag, cmsSigBToD0Tag);
|
||||
cmsLinkTag(hRGB, cmsSigBToD2Tag, cmsSigBToD0Tag);
|
||||
cmsLinkTag(hRGB, cmsSigBToD3Tag, cmsSigBToD0Tag);
|
||||
|
||||
/*
|
||||
* Pipeline from device (electrical) to PCS (optical)
|
||||
*/
|
||||
DToB0 = cmsPipelineAlloc(context_id, 3, 3);
|
||||
|
||||
cmsPipelineInsertStage(DToB0, cmsAT_END, cmsStageDup(stage_eotf));
|
||||
stage = create_cLUT_from_matrix(context_id, &arg->pipeline->mat2XYZ, arg->dim_size);
|
||||
cmsPipelineInsertStage(DToB0, cmsAT_END, stage);
|
||||
|
||||
cmsWriteTag(hRGB, cmsSigDToB0Tag, DToB0);
|
||||
cmsLinkTag(hRGB, cmsSigDToB1Tag, cmsSigDToB0Tag);
|
||||
cmsLinkTag(hRGB, cmsSigDToB2Tag, cmsSigDToB0Tag);
|
||||
cmsLinkTag(hRGB, cmsSigDToB3Tag, cmsSigDToB0Tag);
|
||||
|
||||
vcgt_tag_add_to_profile(context_id, hRGB, arg->vcgt_exponents);
|
||||
|
||||
roundtrip_verification(DToB0, BToD0, arg->clut_roundtrip_tolerance);
|
||||
|
||||
cmsPipelineFree(BToD0);
|
||||
cmsPipelineFree(DToB0);
|
||||
cmsStageFree(stage_eotf);
|
||||
cmsStageFree(stage_inv_eotf);
|
||||
|
||||
return hRGB;
|
||||
}
|
||||
|
||||
static cmsHPROFILE
|
||||
build_lcms_matrix_shaper_profile_output(cmsContext context_id,
|
||||
const struct setup_args *arg)
|
||||
{
|
||||
cmsToneCurve *arr_curves[3];
|
||||
cmsHPROFILE hRGB;
|
||||
int type_inverse_tone_curve;
|
||||
double inverse_tone_curve_param[5];
|
||||
|
||||
assert(find_tone_curve_type(arg->pipeline->post_fn, &type_inverse_tone_curve,
|
||||
inverse_tone_curve_param));
|
||||
|
||||
/*
|
||||
* We are creating output profile and therefore we can use the following:
|
||||
* calling semantics:
|
||||
* cmsBuildParametricToneCurve(type_inverse_tone_curve, inverse_tone_curve_param)
|
||||
* The function find_tone_curve_type sets the type of curve positive if it
|
||||
* is tone curve and negative if it is inverse. When we create an ICC
|
||||
* profile we should use a tone curve, the inversion is done by LCMS
|
||||
* when the profile is used for output.
|
||||
*/
|
||||
|
||||
arr_curves[0] = arr_curves[1] = arr_curves[2] =
|
||||
cmsBuildParametricToneCurve(context_id,
|
||||
(-1) * type_inverse_tone_curve,
|
||||
inverse_tone_curve_param);
|
||||
|
||||
assert(arr_curves[0]);
|
||||
hRGB = cmsCreateRGBProfileTHR(context_id, &wp_d65,
|
||||
&arg->pipeline->prim_output, arr_curves);
|
||||
assert(hRGB);
|
||||
|
||||
vcgt_tag_add_to_profile(context_id, hRGB, arg->vcgt_exponents);
|
||||
|
||||
cmsFreeToneCurve(arr_curves[0]);
|
||||
return hRGB;
|
||||
}
|
||||
|
||||
static cmsHPROFILE
|
||||
build_lcms_profile_output(cmsContext context_id, const struct setup_args *arg)
|
||||
build_lcms_profile_output(const struct setup_args *arg)
|
||||
{
|
||||
switch (arg->type) {
|
||||
case PTYPE_MATRIX_SHAPER:
|
||||
return build_lcms_matrix_shaper_profile_output(context_id, arg);
|
||||
return build_lcms_matrix_shaper_profile_output(NULL,
|
||||
arg->pipeline,
|
||||
arg->vcgt_exponents);
|
||||
case PTYPE_CLUT:
|
||||
return build_lcms_clut_profile_output(context_id, arg);
|
||||
return build_lcms_clut_profile_output(NULL,
|
||||
arg->pipeline,
|
||||
arg->vcgt_exponents,
|
||||
arg->dim_size,
|
||||
arg->clut_roundtrip_tolerance);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
@ -442,7 +215,7 @@ build_output_icc_profile(const struct setup_args *arg)
|
|||
arg->pipeline->color_space);
|
||||
assert(ret > 0);
|
||||
|
||||
profile = build_lcms_profile_output(NULL, arg);
|
||||
profile = build_lcms_profile_output(arg);
|
||||
assert(profile);
|
||||
|
||||
saved = cmsSaveProfileToFile(profile, profile_name);
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
/*
|
||||
* Copyright 2021 Advanced Micro Devices, Inc.
|
||||
* Copyright 2022 Collabora, Ltd.
|
||||
* Copyright (c) 1998-2022 Marti Maria Saguer
|
||||
*
|
||||
|
@ -29,11 +30,14 @@
|
|||
#include <math.h>
|
||||
#include <lcms2.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "shared/helpers.h"
|
||||
#include "color_util.h"
|
||||
#include "lcms_util.h"
|
||||
|
||||
static cmsCIExyY wp_d65 = { 0.31271, 0.32902, 1.0 };
|
||||
|
||||
/*
|
||||
* MPE tone curves can only use LittleCMS parametric curve types 6-8 and not
|
||||
* inverses.
|
||||
|
@ -229,3 +233,203 @@ Error:
|
|||
cmsMLUfree(CopyrightMLU);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void
|
||||
test_roundtrip(uint8_t r, uint8_t g, uint8_t b, cmsPipeline *pip,
|
||||
struct rgb_diff_stat *stat)
|
||||
{
|
||||
struct color_float in = { .rgb = { r / 255.0, g / 255.0, b / 255.0 } };
|
||||
struct color_float out = {};
|
||||
|
||||
cmsPipelineEvalFloat(in.rgb, out.rgb, pip);
|
||||
rgb_diff_stat_update(stat, &in, &out, &in);
|
||||
}
|
||||
|
||||
/*
|
||||
* Roundtrip verification tests that converting device -> PCS -> device
|
||||
* results in the original color values close enough.
|
||||
*
|
||||
* This ensures that the two pipelines are probably built correctly, and we
|
||||
* do not have problems with unexpected value clamping or with representing
|
||||
* (inverse) EOTF curves.
|
||||
*/
|
||||
static void
|
||||
roundtrip_verification(cmsPipeline *DToB, cmsPipeline *BToD, float tolerance)
|
||||
{
|
||||
unsigned r, g, b;
|
||||
struct rgb_diff_stat stat = {};
|
||||
cmsPipeline *pip;
|
||||
|
||||
pip = cmsPipelineDup(DToB);
|
||||
cmsPipelineCat(pip, BToD);
|
||||
|
||||
/*
|
||||
* Inverse-EOTF is known to have precision problems near zero, so
|
||||
* sample near zero densely, the rest can be more sparse to run faster.
|
||||
*/
|
||||
for (r = 0; r < 256; r += (r < 15) ? 1 : 8) {
|
||||
for (g = 0; g < 256; g += (g < 15) ? 1 : 8) {
|
||||
for (b = 0; b < 256; b += (b < 15) ? 1 : 8)
|
||||
test_roundtrip(r, g, b, pip, &stat);
|
||||
}
|
||||
}
|
||||
|
||||
cmsPipelineFree(pip);
|
||||
|
||||
rgb_diff_stat_print(&stat, "DToB->BToD roundtrip", 8);
|
||||
assert(stat.two_norm.max < tolerance);
|
||||
}
|
||||
|
||||
static cmsInt32Number
|
||||
sampler_matrix(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);
|
||||
|
||||
for (i = 0; i < COLOR_CHAN_NUM; i++)
|
||||
dst[i] = cf.rgb[i];
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cmsStage *
|
||||
create_cLUT_from_matrix(cmsContext context_id, const struct lcmsMAT3 *mat,
|
||||
int dim_size)
|
||||
{
|
||||
cmsStage *cLUT_stage;
|
||||
|
||||
assert(dim_size);
|
||||
|
||||
cLUT_stage = cmsStageAllocCLutFloat(context_id, dim_size, 3, 3, NULL);
|
||||
cmsStageSampleCLutFloat(cLUT_stage, sampler_matrix, (void *)mat, 0);
|
||||
|
||||
return cLUT_stage;
|
||||
}
|
||||
|
||||
static void
|
||||
vcgt_tag_add_to_profile(cmsContext context_id, cmsHPROFILE profile,
|
||||
const double vcgt_exponents[COLOR_CHAN_NUM])
|
||||
{
|
||||
cmsToneCurve *vcgt_tag_curves[COLOR_CHAN_NUM];
|
||||
unsigned int i;
|
||||
|
||||
if (!should_include_vcgt(vcgt_exponents))
|
||||
return;
|
||||
|
||||
for (i = 0; i < COLOR_CHAN_NUM; i++)
|
||||
vcgt_tag_curves[i] = cmsBuildGamma(context_id, vcgt_exponents[i]);
|
||||
|
||||
assert(cmsWriteTag(profile, cmsSigVcgtTag, vcgt_tag_curves));
|
||||
|
||||
cmsFreeToneCurveTriple(vcgt_tag_curves);
|
||||
}
|
||||
|
||||
cmsHPROFILE
|
||||
build_lcms_clut_profile_output(cmsContext context_id,
|
||||
const struct lcms_pipeline *pipeline,
|
||||
const double vcgt_exponents[COLOR_CHAN_NUM],
|
||||
int clut_dim_size, float clut_roundtrip_tolerance)
|
||||
{
|
||||
enum transfer_fn inv_eotf_fn = pipeline->post_fn;
|
||||
enum transfer_fn eotf_fn = transfer_fn_invert(inv_eotf_fn);
|
||||
cmsHPROFILE hRGB;
|
||||
cmsPipeline *DToB0, *BToD0;
|
||||
cmsStage *stage;
|
||||
cmsStage *stage_inv_eotf;
|
||||
cmsStage *stage_eotf;
|
||||
struct lcmsMAT3 mat2XYZ_inv;
|
||||
|
||||
lcmsMAT3_invert(&mat2XYZ_inv, &pipeline->mat2XYZ);
|
||||
|
||||
hRGB = cmsCreateProfilePlaceholder(context_id);
|
||||
cmsSetProfileVersion(hRGB, 4.3);
|
||||
cmsSetDeviceClass(hRGB, cmsSigDisplayClass);
|
||||
cmsSetColorSpace(hRGB, cmsSigRgbData);
|
||||
cmsSetPCS(hRGB, cmsSigXYZData);
|
||||
SetTextTags(hRGB, L"cLut profile");
|
||||
|
||||
stage_eotf = build_MPE_curve_stage(context_id, eotf_fn);
|
||||
stage_inv_eotf = build_MPE_curve_stage(context_id, inv_eotf_fn);
|
||||
|
||||
/*
|
||||
* Pipeline from PCS (optical) to device (electrical)
|
||||
*/
|
||||
BToD0 = cmsPipelineAlloc(context_id, 3, 3);
|
||||
|
||||
stage = create_cLUT_from_matrix(context_id, &mat2XYZ_inv, clut_dim_size);
|
||||
cmsPipelineInsertStage(BToD0, cmsAT_END, stage);
|
||||
cmsPipelineInsertStage(BToD0, cmsAT_END, cmsStageDup(stage_inv_eotf));
|
||||
|
||||
cmsWriteTag(hRGB, cmsSigBToD0Tag, BToD0);
|
||||
cmsLinkTag(hRGB, cmsSigBToD1Tag, cmsSigBToD0Tag);
|
||||
cmsLinkTag(hRGB, cmsSigBToD2Tag, cmsSigBToD0Tag);
|
||||
cmsLinkTag(hRGB, cmsSigBToD3Tag, cmsSigBToD0Tag);
|
||||
|
||||
/*
|
||||
* Pipeline from device (electrical) to PCS (optical)
|
||||
*/
|
||||
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);
|
||||
cmsPipelineInsertStage(DToB0, cmsAT_END, stage);
|
||||
|
||||
cmsWriteTag(hRGB, cmsSigDToB0Tag, DToB0);
|
||||
cmsLinkTag(hRGB, cmsSigDToB1Tag, cmsSigDToB0Tag);
|
||||
cmsLinkTag(hRGB, cmsSigDToB2Tag, cmsSigDToB0Tag);
|
||||
cmsLinkTag(hRGB, cmsSigDToB3Tag, cmsSigDToB0Tag);
|
||||
|
||||
vcgt_tag_add_to_profile(context_id, hRGB, vcgt_exponents);
|
||||
|
||||
roundtrip_verification(DToB0, BToD0, clut_roundtrip_tolerance);
|
||||
|
||||
cmsPipelineFree(BToD0);
|
||||
cmsPipelineFree(DToB0);
|
||||
cmsStageFree(stage_eotf);
|
||||
cmsStageFree(stage_inv_eotf);
|
||||
|
||||
return hRGB;
|
||||
}
|
||||
|
||||
cmsHPROFILE
|
||||
build_lcms_matrix_shaper_profile_output(cmsContext context_id,
|
||||
const struct lcms_pipeline *pipeline,
|
||||
const double vcgt_exponents[COLOR_CHAN_NUM])
|
||||
{
|
||||
cmsToneCurve *arr_curves[3];
|
||||
cmsHPROFILE hRGB;
|
||||
int type_inverse_tone_curve;
|
||||
double inverse_tone_curve_param[5];
|
||||
|
||||
assert(find_tone_curve_type(pipeline->post_fn, &type_inverse_tone_curve,
|
||||
inverse_tone_curve_param));
|
||||
|
||||
/*
|
||||
* We are creating output profile and therefore we can use the following:
|
||||
* calling semantics:
|
||||
* cmsBuildParametricToneCurve(type_inverse_tone_curve, inverse_tone_curve_param)
|
||||
* The function find_tone_curve_type sets the type of curve positive if it
|
||||
* is tone curve and negative if it is inverse. When we create an ICC
|
||||
* profile we should use a tone curve, the inversion is done by LCMS
|
||||
* when the profile is used for output.
|
||||
*/
|
||||
|
||||
arr_curves[0] = arr_curves[1] = arr_curves[2] =
|
||||
cmsBuildParametricToneCurve(context_id,
|
||||
(-1) * type_inverse_tone_curve,
|
||||
inverse_tone_curve_param);
|
||||
|
||||
assert(arr_curves[0]);
|
||||
hRGB = cmsCreateRGBProfileTHR(context_id, &wp_d65,
|
||||
&pipeline->prim_output, arr_curves);
|
||||
assert(hRGB);
|
||||
|
||||
vcgt_tag_add_to_profile(context_id, hRGB, vcgt_exponents);
|
||||
|
||||
cmsFreeToneCurve(arr_curves[0]);
|
||||
return hRGB;
|
||||
}
|
||||
|
|
|
@ -29,6 +29,34 @@
|
|||
|
||||
#include "color_util.h"
|
||||
|
||||
struct lcms_pipeline {
|
||||
/**
|
||||
* Color space name
|
||||
*/
|
||||
const char *color_space;
|
||||
/**
|
||||
* Chromaticities for output profile
|
||||
*/
|
||||
cmsCIExyYTRIPLE prim_output;
|
||||
/**
|
||||
* tone curve enum
|
||||
*/
|
||||
enum transfer_fn pre_fn;
|
||||
/**
|
||||
* Transform matrix from sRGB to target chromaticities in prim_output
|
||||
*/
|
||||
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;
|
||||
};
|
||||
|
||||
cmsToneCurve *
|
||||
build_MPE_curve(cmsContext ctx, enum transfer_fn fn);
|
||||
|
||||
|
@ -37,3 +65,14 @@ build_MPE_curve_stage(cmsContext context_id, enum transfer_fn fn);
|
|||
|
||||
cmsBool
|
||||
SetTextTags(cmsHPROFILE hProfile, const wchar_t* Description);
|
||||
|
||||
cmsHPROFILE
|
||||
build_lcms_matrix_shaper_profile_output(cmsContext context_id,
|
||||
const struct lcms_pipeline *pipeline,
|
||||
const double vcgt_exponents[COLOR_CHAN_NUM]);
|
||||
|
||||
cmsHPROFILE
|
||||
build_lcms_clut_profile_output(cmsContext context_id,
|
||||
const struct lcms_pipeline *pipeline,
|
||||
const double vcgt_exponents[COLOR_CHAN_NUM],
|
||||
int clut_dim_size, float clut_roundtrip_tolerance);
|
||||
|
|
Loading…
Reference in New Issue