mirror of
https://gitlab.freedesktop.org/wayland/weston.git
synced 2026-05-09 04:48:04 +02:00
color-lcms: recognize LCMS curves that matches transfer functions
LittleCMS curves contain curves that are parametric. They may be well-known curves, and we are not checking that. If that's the case, we should create enumerated color curves, instead of parametric. This can be helpful for renderers and/or backends that want to implement the curve, as they may have access to an API that accept enumerated curves. Signed-off-by: Leandro Ribeiro <leandro.ribeiro@collabora.com>
This commit is contained in:
parent
209882c7d4
commit
ccf6db49b7
3 changed files with 171 additions and 6 deletions
|
|
@ -442,15 +442,83 @@ merge_curvesets(cmsPipeline **lut, cmsContext context_id)
|
|||
return modified;
|
||||
}
|
||||
|
||||
static const struct weston_color_tf_info *
|
||||
lcms_curve_matches_any_tf(struct weston_compositor *compositor,
|
||||
uint32_t lcms_curve_type, bool clamped_input,
|
||||
const float lcms_curve_params[3][MAX_PARAMS_LCMS_PARAM_CURVE])
|
||||
{
|
||||
struct weston_color_curve_parametric curve = { 0 };
|
||||
unsigned int i, j;
|
||||
uint32_t n_lcms_curve_params;
|
||||
|
||||
curve.clamped_input = clamped_input;
|
||||
|
||||
switch(lcms_curve_type) {
|
||||
case 1:
|
||||
/**
|
||||
* LittleCMS type 1 is the pure power-law curve, which is a
|
||||
* special case of LINPOW. See linpow_from_type_1().
|
||||
*/
|
||||
n_lcms_curve_params = 1;
|
||||
curve.type = WESTON_COLOR_CURVE_PARAMETRIC_TYPE_LINPOW;
|
||||
break;
|
||||
case 4:
|
||||
/**
|
||||
* LittleCMS type 4 is almost exactly the same as LINPOW. See
|
||||
* linpow_from_type_4().
|
||||
*/
|
||||
n_lcms_curve_params = 5;
|
||||
curve.type = WESTON_COLOR_CURVE_PARAMETRIC_TYPE_LINPOW;
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
weston_assert_uint32_lt_or_eq(compositor,
|
||||
n_lcms_curve_params, MAX_PARAMS_LCMS_PARAM_CURVE);
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
for (j = 0; j < n_lcms_curve_params; j++)
|
||||
curve.params[i][j] = lcms_curve_params[i][j];
|
||||
|
||||
return weston_color_tf_info_from_parametric_curve(&curve);
|
||||
}
|
||||
|
||||
|
||||
static bool
|
||||
linpow_from_type_1(struct weston_compositor *compositor,
|
||||
struct weston_color_curve *curve,
|
||||
const float type_1_params[3][MAX_PARAMS_LCMS_PARAM_CURVE],
|
||||
bool clamped_input)
|
||||
{
|
||||
struct weston_color_curve_enum *enumerated = &curve->u.enumerated;
|
||||
struct weston_color_curve_parametric *parametric = &curve->u.parametric;
|
||||
const struct weston_color_tf_info *tf_info;
|
||||
unsigned int i;
|
||||
|
||||
/* Check if LittleCMS curve matches any TF (except the parametric TF's). */
|
||||
tf_info = lcms_curve_matches_any_tf(compositor, 1, clamped_input, type_1_params);
|
||||
if (tf_info) {
|
||||
curve->type = WESTON_COLOR_CURVE_TYPE_ENUM;
|
||||
enumerated->tf = tf_info;
|
||||
enumerated->tf_direction = WESTON_FORWARD_TF;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* This is a pure power-law with custom exp. If clamped_input == false,
|
||||
* this matches WESTON_TF_POWER (parametric TF that is not clamped). */
|
||||
if (!clamped_input) {
|
||||
curve->type = WESTON_COLOR_CURVE_TYPE_ENUM;
|
||||
enumerated->tf = weston_color_tf_info_from(compositor,
|
||||
WESTON_TF_POWER);
|
||||
enumerated->tf_direction = WESTON_FORWARD_TF;
|
||||
for (i = 0; i < 3; i++)
|
||||
enumerated->params[i][0] = type_1_params[i][0];
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Pure power-law with custom exp and clamped_input. We don't have any
|
||||
* TF that matches this, so let's use a parametric curve. */
|
||||
curve->type = WESTON_COLOR_CURVE_TYPE_PARAMETRIC;
|
||||
|
||||
/* LittleCMS type 1 is the pure power-law curve, which is a special case
|
||||
|
|
@ -472,7 +540,7 @@ linpow_from_type_1(struct weston_compositor *compositor,
|
|||
parametric->type = WESTON_COLOR_CURVE_PARAMETRIC_TYPE_LINPOW;
|
||||
parametric->clamped_input = clamped_input;
|
||||
|
||||
for (i = 0; i < ARRAY_LENGTH(parametric->params); i++) {
|
||||
for (i = 0; i < 3; i++) {
|
||||
parametric->params[i][0] = type_1_params[i][0]; /* g */
|
||||
parametric->params[i][1] = 1.0f; /* a */
|
||||
parametric->params[i][2] = 0.0f; /* b */
|
||||
|
|
@ -490,11 +558,44 @@ linpow_from_type_1_inverse(struct weston_compositor *compositor,
|
|||
bool clamped_input)
|
||||
{
|
||||
struct weston_color_manager_lcms *cm = to_cmlcms(compositor->color_manager);
|
||||
struct weston_color_curve_enum *enumerated = &curve->u.enumerated;
|
||||
struct weston_color_curve_parametric *parametric = &curve->u.parametric;
|
||||
const struct weston_color_tf_info *tf_info;
|
||||
float g;
|
||||
const char *err_msg;
|
||||
unsigned int i;
|
||||
|
||||
/* Check if LittleCMS curve matches any TF (except the parametric TF's). */
|
||||
tf_info = lcms_curve_matches_any_tf(compositor, 1, clamped_input, type_1_params);
|
||||
if (tf_info) {
|
||||
curve->type = WESTON_COLOR_CURVE_TYPE_ENUM;
|
||||
enumerated->tf = tf_info;
|
||||
enumerated->tf_direction = WESTON_INVERSE_TF;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* This is the inverse of a pure power-law with custom exp. If
|
||||
* clamped_input == false, this matches WESTON_TF_POWER (parametric TF
|
||||
* that is not clamped). */
|
||||
if (!clamped_input) {
|
||||
curve->type = WESTON_COLOR_CURVE_TYPE_ENUM;
|
||||
enumerated->tf = weston_color_tf_info_from(compositor,
|
||||
WESTON_TF_POWER);
|
||||
enumerated->tf_direction = WESTON_INVERSE_TF;
|
||||
for (i = 0; i < 3; i++) {
|
||||
g = type_1_params[i][0];
|
||||
if (g == 0.0f) {
|
||||
err_msg = "WARNING: xform has a LittleCMS type -1 curve " \
|
||||
"(inverse of pure power-law) with exponent 1 " \
|
||||
"divided by 0, which is invalid";
|
||||
goto err;
|
||||
}
|
||||
enumerated->params[i][0] = g;
|
||||
}
|
||||
}
|
||||
|
||||
/* Inverse of pure power-law with custom exp and clamped_input. We don't
|
||||
* have any TF that matches this, so let's use a parametric curve. */
|
||||
curve->type = WESTON_COLOR_CURVE_TYPE_PARAMETRIC;
|
||||
|
||||
/* LittleCMS type -1 (inverse of type 1) is the inverse of the pure
|
||||
|
|
@ -523,16 +624,14 @@ linpow_from_type_1_inverse(struct weston_compositor *compositor,
|
|||
parametric->type = WESTON_COLOR_CURVE_PARAMETRIC_TYPE_LINPOW;
|
||||
parametric->clamped_input = clamped_input;
|
||||
|
||||
for (i = 0; i < ARRAY_LENGTH(parametric->params); i++) {
|
||||
for (i = 0; i < 3; i++) {
|
||||
g = type_1_params[i][0];
|
||||
|
||||
if (g == 0.0f) {
|
||||
err_msg = "WARNING: xform has a LittleCMS type -1 curve " \
|
||||
"(inverse of pure power-law) with exponent 1 " \
|
||||
"divided by 0, which is invalid";
|
||||
goto err;
|
||||
}
|
||||
|
||||
parametric->params[i][0] = 1.0f / g;
|
||||
parametric->params[i][1] = 1.0f; /* a */
|
||||
parametric->params[i][2] = 0.0f; /* b */
|
||||
|
|
@ -554,11 +653,23 @@ linpow_from_type_4(struct weston_compositor *compositor,
|
|||
bool clamped_input)
|
||||
{
|
||||
struct weston_color_manager_lcms *cm = to_cmlcms(compositor->color_manager);
|
||||
struct weston_color_curve_enum *enumerated = &curve->u.enumerated;
|
||||
struct weston_color_curve_parametric *parametric = &curve->u.parametric;
|
||||
const struct weston_color_tf_info *tf_info;
|
||||
float g, a, b, c, d;
|
||||
const char *err_msg;
|
||||
unsigned int i;
|
||||
|
||||
/* Check if LittleCMS curve matches any TF (except the parametric TF's). */
|
||||
tf_info = lcms_curve_matches_any_tf(compositor, 4, clamped_input, type_4_params);
|
||||
if (tf_info) {
|
||||
curve->type = WESTON_COLOR_CURVE_TYPE_ENUM;
|
||||
enumerated->tf = tf_info;
|
||||
enumerated->tf_direction = WESTON_FORWARD_TF;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* No TF's matches this curve, so let's put it in a parametric curve. */
|
||||
curve->type = WESTON_COLOR_CURVE_TYPE_PARAMETRIC;
|
||||
|
||||
/* LittleCMS type 4 is almost exactly the same as LINPOW. So simply copy
|
||||
|
|
@ -576,7 +687,7 @@ linpow_from_type_4(struct weston_compositor *compositor,
|
|||
parametric->type = WESTON_COLOR_CURVE_PARAMETRIC_TYPE_LINPOW;
|
||||
parametric->clamped_input = clamped_input;
|
||||
|
||||
for (i = 0; i < ARRAY_LENGTH(parametric->params); i++) {
|
||||
for (i = 0; i < 3; i++) {
|
||||
g = type_4_params[i][0];
|
||||
a = type_4_params[i][1];
|
||||
b = type_4_params[i][2];
|
||||
|
|
@ -622,11 +733,23 @@ powlin_from_type_4_inverse(struct weston_compositor *compositor,
|
|||
bool clamped_input)
|
||||
{
|
||||
struct weston_color_manager_lcms *cm = to_cmlcms(compositor->color_manager);
|
||||
struct weston_color_curve_enum *enumerated = &curve->u.enumerated;
|
||||
struct weston_color_curve_parametric *parametric = &curve->u.parametric;
|
||||
const struct weston_color_tf_info *tf_info;
|
||||
float g, a, b, c, d;
|
||||
const char *err_msg;
|
||||
unsigned int i;
|
||||
|
||||
/* Check if LittleCMS curve matches any TF (except the parametric ones). */
|
||||
tf_info = lcms_curve_matches_any_tf(compositor, 4, clamped_input, type_4_params);
|
||||
if (tf_info) {
|
||||
curve->type = WESTON_COLOR_CURVE_TYPE_ENUM;
|
||||
enumerated->tf = tf_info;
|
||||
enumerated->tf_direction = WESTON_INVERSE_TF;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* No TF's matches this curve, so let's put it in a parametric curve. */
|
||||
curve->type = WESTON_COLOR_CURVE_TYPE_PARAMETRIC;
|
||||
|
||||
/* LittleCMS type -4 (inverse of type 4) fits into POWLIN. We need to
|
||||
|
|
@ -679,7 +802,7 @@ powlin_from_type_4_inverse(struct weston_compositor *compositor,
|
|||
parametric->type = WESTON_COLOR_CURVE_PARAMETRIC_TYPE_POWLIN;
|
||||
parametric->clamped_input = clamped_input;
|
||||
|
||||
for (i = 0; i < ARRAY_LENGTH(parametric->params); i++) {
|
||||
for (i = 0; i < 3; i++) {
|
||||
g = type_4_params[i][0];
|
||||
a = type_4_params[i][1];
|
||||
b = type_4_params[i][2];
|
||||
|
|
|
|||
|
|
@ -483,3 +483,42 @@ weston_color_tf_info_from_protocol(uint32_t protocol_tf)
|
|||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
WL_EXPORT const struct weston_color_tf_info *
|
||||
weston_color_tf_info_from_parametric_curve(struct weston_color_curve_parametric *curve)
|
||||
{
|
||||
const struct weston_color_tf_info *tf_info;
|
||||
float PRECISION = 1e-5;
|
||||
unsigned int i, j, k;
|
||||
bool params_match;
|
||||
|
||||
for (i = 0; i < ARRAY_LENGTH(color_tf_info_table); i++) {
|
||||
tf_info = &color_tf_info_table[i];
|
||||
|
||||
/**
|
||||
* Ignore parametric TF's; we can't compare a curve with them,
|
||||
* as they are not pre-defined, but parametric.
|
||||
*/
|
||||
if (tf_info->count_parameters > 0)
|
||||
continue;
|
||||
|
||||
if (tf_info->curve.type != curve->type)
|
||||
continue;
|
||||
|
||||
if (tf_info->curve.clamped_input != curve->clamped_input)
|
||||
continue;
|
||||
|
||||
for (j = 0, params_match = true; j < 3 && params_match == true; j++) {
|
||||
for (k = 0; k < MAX_PARAMS_PARAM_CURVE && params_match == true; k++) {
|
||||
if (fabsf(tf_info->curve.params[j][k] - curve->params[j][k]) > PRECISION)
|
||||
params_match = false;
|
||||
}
|
||||
}
|
||||
if (!params_match)
|
||||
continue;
|
||||
|
||||
return tf_info;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -149,4 +149,7 @@ weston_color_tf_info_from(struct weston_compositor *compositor,
|
|||
const struct weston_color_tf_info *
|
||||
weston_color_tf_info_from_protocol(uint32_t protocol_tf);
|
||||
|
||||
const struct weston_color_tf_info *
|
||||
weston_color_tf_info_from_parametric_curve(struct weston_color_curve_parametric *curve);
|
||||
|
||||
#endif /* WESTON_COLOR_PROPERTIES_H */
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue