mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2025-01-15 23:00:08 +00:00
colorstate: Add cicp support
This adds machinery to create colorstate objects from cicp tuples, as well as a function to return a cicp tuple for a colorstate. Still missing: a conversion shader for non-default colorstates.
This commit is contained in:
parent
4255230e36
commit
d907c0a42e
84
gdk/gdkcicpparamsprivate.h
Normal file
84
gdk/gdkcicpparamsprivate.h
Normal file
@ -0,0 +1,84 @@
|
||||
#pragma once
|
||||
|
||||
typedef struct _GdkCicp GdkCicp;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
GDK_CICP_RANGE_NARROW,
|
||||
GDK_CICP_RANGE_FULL,
|
||||
} GdkCicpRange;
|
||||
|
||||
struct _GdkCicp
|
||||
{
|
||||
guint color_primaries;
|
||||
guint transfer_function;
|
||||
guint matrix_coefficients;
|
||||
GdkCicpRange range;
|
||||
};
|
||||
|
||||
/*< private >
|
||||
* gdk_cicp_equal:
|
||||
* @p1: a `GdkCicp`
|
||||
* @p2: another `GdkCicp`
|
||||
*
|
||||
* Compare two cicp tuples for equality.
|
||||
*
|
||||
* Note that several cicp values are 'functionally equivalent'.
|
||||
* If you are interested in that notion, use gdk_cicp_equivalent().
|
||||
*
|
||||
* Returns: whether @p1 and @p2 are equal
|
||||
*/
|
||||
static inline gboolean
|
||||
gdk_cicp_equal (const GdkCicp *p1,
|
||||
const GdkCicp *p2)
|
||||
{
|
||||
return p1->color_primaries == p2->color_primaries &&
|
||||
p1->transfer_function == p2->transfer_function &&
|
||||
p1->matrix_coefficients == p2->matrix_coefficients &&
|
||||
p1->range == p2->range;
|
||||
}
|
||||
|
||||
static inline void
|
||||
gdk_cicp_normalize (const GdkCicp *orig,
|
||||
GdkCicp *out)
|
||||
{
|
||||
memcpy (out, orig, sizeof (GdkCicp));
|
||||
|
||||
/* ntsc */
|
||||
if (out->color_primaries == 6)
|
||||
out->color_primaries = 5;
|
||||
|
||||
/* bt709 */
|
||||
if (out->transfer_function == 6 ||
|
||||
out->transfer_function == 14 ||
|
||||
out->transfer_function == 15)
|
||||
out->transfer_function = 1;
|
||||
|
||||
/* bt601 */
|
||||
if (out->matrix_coefficients == 6)
|
||||
out->matrix_coefficients = 5;
|
||||
}
|
||||
|
||||
/*< private >
|
||||
* gdk_cicp_equivalent:
|
||||
* @p1: a `GdkCicp`
|
||||
* @p2: another `GdkCicp`
|
||||
*
|
||||
* Determine whether two cicp tuples are functionally equivalent.
|
||||
*
|
||||
* Returns: whether @p1 and @p2 are functionally equivalent
|
||||
*/
|
||||
static inline gboolean
|
||||
gdk_cicp_equivalent (const GdkCicp *p1,
|
||||
const GdkCicp *p2)
|
||||
{
|
||||
GdkCicp n1, n2;
|
||||
|
||||
if (gdk_cicp_equal (p1, p2))
|
||||
return TRUE;
|
||||
|
||||
gdk_cicp_normalize (p1, &n1);
|
||||
gdk_cicp_normalize (p2, &n2);
|
||||
|
||||
return gdk_cicp_equal (&n1, &n2);
|
||||
}
|
@ -22,6 +22,8 @@
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include <glib/gi18n-lib.h>
|
||||
|
||||
/**
|
||||
* GdkColorState:
|
||||
*
|
||||
@ -193,6 +195,12 @@ gboolean
|
||||
/* }}} */
|
||||
/* {{{ Conversion functions */
|
||||
|
||||
typedef float (* GdkTransferFunc) (float v);
|
||||
typedef const float GdkColorMatrix[3][3];
|
||||
|
||||
#define IDENTITY ((float**)0)
|
||||
#define NONE ((GdkTransferFunc)0)
|
||||
|
||||
#define TRANSFORM(name, eotf, matrix, oetf) \
|
||||
static void \
|
||||
name (GdkColorState *self, \
|
||||
@ -201,9 +209,12 @@ name (GdkColorState *self, \
|
||||
{ \
|
||||
for (gsize i = 0; i < n_values; i++) \
|
||||
{ \
|
||||
values[i][0] = eotf (values[i][0]); \
|
||||
values[i][1] = eotf (values[i][1]); \
|
||||
values[i][2] = eotf (values[i][2]); \
|
||||
if (eotf != NONE) \
|
||||
{ \
|
||||
values[i][0] = eotf (values[i][0]); \
|
||||
values[i][1] = eotf (values[i][1]); \
|
||||
values[i][2] = eotf (values[i][2]); \
|
||||
} \
|
||||
if ((float **)matrix != IDENTITY) \
|
||||
{ \
|
||||
float res[3]; \
|
||||
@ -214,9 +225,12 @@ name (GdkColorState *self, \
|
||||
values[i][1] = res[1]; \
|
||||
values[i][2] = res[2]; \
|
||||
} \
|
||||
values[i][0] = oetf (values[i][0]); \
|
||||
values[i][1] = oetf (values[i][1]); \
|
||||
values[i][2] = oetf (values[i][2]); \
|
||||
if (oetf != NONE) \
|
||||
{ \
|
||||
values[i][0] = oetf (values[i][0]); \
|
||||
values[i][1] = oetf (values[i][1]); \
|
||||
values[i][2] = oetf (values[i][2]); \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
@ -265,29 +279,116 @@ pq_oetf (float v)
|
||||
return powf (((c1 + (c2 * powf (x, n))) / (1 + (c3 * powf (x, n)))), m);
|
||||
}
|
||||
|
||||
/* These matrices are derived by combining the standard abc_to_xyz onces:
|
||||
*
|
||||
* rec2020_to_srgb = srgb_to_xyz⁻¹ * rec2020_to_xyz
|
||||
* srgb_to_rec2020 = rec2020_to_xyz⁻¹ * srgb_to_xyz
|
||||
*
|
||||
* These values were used here:
|
||||
*
|
||||
* static const float srgb_to_xyz[3][3] = {
|
||||
* { 0.4125288, 0.3581642, 0.1774037 },
|
||||
* { 0.2127102, 0.7163284, 0.0709615 },
|
||||
* { 0.0193373, 0.1193881, 0.9343260 },
|
||||
* }
|
||||
*
|
||||
* static const float rec2020_to_xyz[3][3] = {
|
||||
* { 0.6369615, 0.1448079, 0.1663273 },
|
||||
* { 0.2627016, 0.6788934, 0.0584050 },
|
||||
* { 0.0000000, 0.0281098, 1.0449416 },
|
||||
* };
|
||||
*
|
||||
* See http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
|
||||
static inline float
|
||||
bt709_eotf (float v)
|
||||
{
|
||||
if (v < 0.081)
|
||||
return v / 4.5;
|
||||
else
|
||||
return powf ((v + 0.099) / 1.099, 1/0.45);
|
||||
}
|
||||
|
||||
static inline float
|
||||
bt709_oetf (float v)
|
||||
{
|
||||
if (v < 0.081)
|
||||
return v * 4.5;
|
||||
else
|
||||
return 1.099 * powf (v, 0.45) - 0.099;
|
||||
}
|
||||
|
||||
static inline float
|
||||
hlg_eotf (float v)
|
||||
{
|
||||
const float a = 0.17883277;
|
||||
const float b = 0.28466892;
|
||||
const float c = 0.55991073;
|
||||
|
||||
if (v <= 0.5)
|
||||
return (v * v) / 3;
|
||||
else
|
||||
return expf (((v - c) / a) + b) / 12.0;
|
||||
}
|
||||
|
||||
static inline float
|
||||
hlg_oetf (float v)
|
||||
{
|
||||
const float a = 0.17883277;
|
||||
const float b = 0.28466892;
|
||||
const float c = 0.55991073;
|
||||
|
||||
if (v <= 1/12.0)
|
||||
return sqrtf (3 * v);
|
||||
else
|
||||
return a * logf (12 * v - b) + c;
|
||||
}
|
||||
|
||||
/* See http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
|
||||
* for how to derive the abc_to_xyz matrices from chromaticity coordinates.
|
||||
*/
|
||||
|
||||
static const float srgb_to_xyz[3][3] = {
|
||||
{ 0.4125288, 0.3581642, 0.1774037 },
|
||||
{ 0.2127102, 0.7163284, 0.0709615 },
|
||||
{ 0.0193373, 0.1193881, 0.9343260 },
|
||||
};
|
||||
|
||||
static const float xyz_to_srgb[3][3] = {
|
||||
{ 3.2409699, -1.5373832, -0.4986108 },
|
||||
{ -0.9692436, 1.8759675, 0.0415551 },
|
||||
{ 0.0556301, -0.2039770, 1.0569715 },
|
||||
};
|
||||
|
||||
static const float rec2020_to_xyz[3][3] = {
|
||||
{ 0.6369615, 0.1448079, 0.1663273 },
|
||||
{ 0.2627016, 0.6788934, 0.0584050 },
|
||||
{ 0.0000000, 0.0281098, 1.0449416 },
|
||||
};
|
||||
|
||||
static const float xyz_to_rec2020[3][3] = {
|
||||
{ 1.7166512, -0.3556708, -0.2533663 },
|
||||
{ -0.6666844, 1.6164812, 0.0157685 },
|
||||
{ 0.0176399, -0.0427706, 0.9421031 },
|
||||
};
|
||||
|
||||
static const float pal_to_xyz[3][3] = {
|
||||
{ 0.4305538, 0.3415498, 0.1783523 },
|
||||
{ 0.2220043, 0.7066548, 0.0713409 },
|
||||
{ 0.0201822, 0.1295534, 0.9393222 },
|
||||
};
|
||||
|
||||
static const float xyz_to_pal[3][3] = {
|
||||
{ 3.0633611, -1.3933902, -0.4758237 },
|
||||
{ -0.9692436, 1.8759675, 0.0415551 },
|
||||
{ 0.0678610, -0.2287993, 1.0690896 },
|
||||
};
|
||||
|
||||
static const float ntsc_to_xyz[3][3] = {
|
||||
{ 0.3935209, 0.3652581, 0.1916769 },
|
||||
{ 0.2123764, 0.7010599, 0.0865638 },
|
||||
{ 0.0187391, 0.1119339, 0.9583847 },
|
||||
};
|
||||
|
||||
static const float xyz_to_ntsc[3][3] = {
|
||||
{ 3.5060033, -1.7397907, -0.5440583 },
|
||||
{ -1.0690476, 1.9777789, 0.0351714 },
|
||||
{ 0.0563066, -0.1969757, 1.0499523 },
|
||||
};
|
||||
|
||||
static const float p3_to_xyz[3][3] = {
|
||||
{ 0.4865709, 0.2656677, 0.1982173 },
|
||||
{ 0.2289746, 0.6917385, 0.0792869 },
|
||||
{ 0.0000000, 0.0451134, 1.0439444 },
|
||||
};
|
||||
|
||||
static const float xyz_to_p3[3][3] = {
|
||||
{ 2.4934969, -0.9313836, -0.4027108 },
|
||||
{ -0.8294890, 1.7626641, 0.0236247 },
|
||||
{ 0.0358458, -0.0761724, 0.9568845 },
|
||||
};
|
||||
|
||||
/* premultiplied matrices for default conversions */
|
||||
|
||||
static const float rec2020_to_srgb[3][3] = {
|
||||
{ 1.659944, -0.588220, -0.071724 },
|
||||
{ -0.124350, 1.132559, -0.008210 },
|
||||
@ -300,9 +401,6 @@ static const float srgb_to_rec2020[3][3] = {
|
||||
{ 0.016649, 0.089510, 0.893842 },
|
||||
};
|
||||
|
||||
#define IDENTITY ((float**)0)
|
||||
#define NONE(x) x
|
||||
|
||||
TRANSFORM(gdk_default_srgb_to_srgb_linear, srgb_eotf, IDENTITY, NONE);
|
||||
TRANSFORM(gdk_default_srgb_linear_to_srgb, NONE, IDENTITY, srgb_oetf)
|
||||
TRANSFORM(gdk_default_rec2100_pq_to_rec2100_linear, pq_eotf, IDENTITY, NONE)
|
||||
@ -316,9 +414,6 @@ TRANSFORM(gdk_default_rec2100_linear_to_srgb, NONE, rec2020_to_srgb,
|
||||
TRANSFORM(gdk_default_srgb_to_rec2100_pq, srgb_eotf, srgb_to_rec2020, pq_oetf)
|
||||
TRANSFORM(gdk_default_rec2100_pq_to_srgb, pq_eotf, rec2020_to_srgb, srgb_oetf)
|
||||
|
||||
#undef IDENTITY
|
||||
#undef NONE
|
||||
|
||||
/* }}} */
|
||||
/* {{{ Default implementation */
|
||||
/* {{{ Vfuncs */
|
||||
@ -352,22 +447,28 @@ gdk_default_color_state_get_convert_to (GdkColorState *color_state,
|
||||
{
|
||||
GdkDefaultColorState *self = (GdkDefaultColorState *) color_state;
|
||||
|
||||
if (!GDK_IS_DEFAULT_COLOR_STATE (target))
|
||||
return NULL;
|
||||
if (GDK_IS_DEFAULT_COLOR_STATE (target))
|
||||
return self->convert_to[GDK_DEFAULT_COLOR_STATE_ID (target)];
|
||||
|
||||
return self->convert_to[GDK_DEFAULT_COLOR_STATE_ID (target)];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static GdkFloatColorConvert
|
||||
gdk_default_color_state_get_convert_from (GdkColorState *color_state,
|
||||
GdkColorState *source)
|
||||
{
|
||||
GdkDefaultColorState *self = (GdkDefaultColorState *) source;
|
||||
/* This is ok because the default-to-default conversion functions
|
||||
* don't use the passed colorstate at all.
|
||||
*/
|
||||
return gdk_default_color_state_get_convert_to (source, color_state);
|
||||
}
|
||||
|
||||
if (!GDK_IS_DEFAULT_COLOR_STATE (color_state))
|
||||
return NULL;
|
||||
static const GdkCicp *
|
||||
gdk_default_color_state_get_cicp (GdkColorState *color_state)
|
||||
{
|
||||
GdkDefaultColorState *self = (GdkDefaultColorState *) color_state;
|
||||
|
||||
return self->convert_to[GDK_DEFAULT_COLOR_STATE_ID (color_state)];
|
||||
return &self->cicp;
|
||||
}
|
||||
|
||||
/* }}} */
|
||||
@ -379,6 +480,8 @@ GdkColorStateClass GDK_DEFAULT_COLOR_STATE_CLASS = {
|
||||
.get_name = gdk_default_color_state_get_name,
|
||||
.get_no_srgb_tf = gdk_default_color_state_get_no_srgb_tf,
|
||||
.get_convert_to = gdk_default_color_state_get_convert_to,
|
||||
.get_convert_from = gdk_default_color_state_get_convert_from,
|
||||
.get_cicp = gdk_default_color_state_get_cicp,
|
||||
};
|
||||
|
||||
GdkDefaultColorState gdk_default_color_states[] = {
|
||||
@ -396,6 +499,7 @@ GdkDefaultColorState gdk_default_color_states[] = {
|
||||
[GDK_COLOR_STATE_ID_REC2100_PQ] = gdk_default_srgb_to_rec2100_pq,
|
||||
[GDK_COLOR_STATE_ID_REC2100_LINEAR] = gdk_default_srgb_to_rec2100_linear,
|
||||
},
|
||||
.cicp = { 1, 13, 0, 1 },
|
||||
},
|
||||
[GDK_COLOR_STATE_ID_SRGB_LINEAR] = {
|
||||
.parent = {
|
||||
@ -411,6 +515,7 @@ GdkDefaultColorState gdk_default_color_states[] = {
|
||||
[GDK_COLOR_STATE_ID_REC2100_PQ] = gdk_default_srgb_linear_to_rec2100_pq,
|
||||
[GDK_COLOR_STATE_ID_REC2100_LINEAR] = gdk_default_srgb_linear_to_rec2100_linear,
|
||||
},
|
||||
.cicp = { 1, 8, 0, 1 },
|
||||
},
|
||||
[GDK_COLOR_STATE_ID_REC2100_PQ] = {
|
||||
.parent = {
|
||||
@ -426,6 +531,7 @@ GdkDefaultColorState gdk_default_color_states[] = {
|
||||
[GDK_COLOR_STATE_ID_SRGB_LINEAR] = gdk_default_rec2100_pq_to_srgb_linear,
|
||||
[GDK_COLOR_STATE_ID_REC2100_LINEAR] = gdk_default_rec2100_pq_to_rec2100_linear,
|
||||
},
|
||||
.cicp = { 9, 16, 0, 1 },
|
||||
},
|
||||
[GDK_COLOR_STATE_ID_REC2100_LINEAR] = {
|
||||
.parent = {
|
||||
@ -441,9 +547,316 @@ GdkDefaultColorState gdk_default_color_states[] = {
|
||||
[GDK_COLOR_STATE_ID_SRGB_LINEAR] = gdk_default_rec2100_linear_to_srgb_linear,
|
||||
[GDK_COLOR_STATE_ID_REC2100_PQ] = gdk_default_rec2100_linear_to_rec2100_pq,
|
||||
},
|
||||
.cicp = { 9, 8, 0, 1 },
|
||||
},
|
||||
};
|
||||
|
||||
/* }}} */
|
||||
/* {{{ Cicp implementation */
|
||||
|
||||
typedef struct _GdkCicpColorState GdkCicpColorState;
|
||||
struct _GdkCicpColorState
|
||||
{
|
||||
GdkColorState parent;
|
||||
|
||||
GdkColorState *no_srgb;
|
||||
|
||||
const char *name;
|
||||
|
||||
GdkTransferFunc eotf;
|
||||
GdkTransferFunc oetf;
|
||||
|
||||
float to_srgb[3][3];
|
||||
float to_rec2020[3][3];
|
||||
float from_srgb[3][3];
|
||||
float from_rec2020[3][3];
|
||||
|
||||
GdkCicp cicp;
|
||||
};
|
||||
|
||||
/* {{{ Conversion functions */
|
||||
|
||||
#define cicp ((GdkCicpColorState *)self)
|
||||
|
||||
TRANSFORM(gdk_cicp_to_srgb, cicp->eotf, cicp->to_srgb, srgb_oetf)
|
||||
TRANSFORM(gdk_cicp_to_srgb_linear, cicp->eotf, cicp->to_srgb, NONE)
|
||||
TRANSFORM(gdk_cicp_to_rec2100_pq, cicp->eotf, cicp->to_rec2020, pq_oetf)
|
||||
TRANSFORM(gdk_cicp_to_rec2100_linear, cicp->eotf, cicp->to_rec2020, NONE)
|
||||
TRANSFORM(gdk_cicp_from_srgb, srgb_eotf, cicp->from_srgb, cicp->oetf)
|
||||
TRANSFORM(gdk_cicp_from_srgb_linear, NONE, cicp->from_srgb, cicp->oetf)
|
||||
TRANSFORM(gdk_cicp_from_rec2100_pq, pq_eotf, cicp->from_rec2020, cicp->oetf)
|
||||
TRANSFORM(gdk_cicp_from_rec2100_linear, NONE, cicp->from_rec2020, cicp->oetf)
|
||||
|
||||
#undef cicp
|
||||
|
||||
/* }}} */
|
||||
/* {{{ Vfuncs */
|
||||
|
||||
static void
|
||||
gdk_cicp_color_state_free (GdkColorState *cs)
|
||||
{
|
||||
GdkCicpColorState *self = (GdkCicpColorState *) cs;
|
||||
|
||||
if (self->no_srgb)
|
||||
gdk_color_state_unref (self->no_srgb);
|
||||
|
||||
g_free (self);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gdk_cicp_color_state_equal (GdkColorState *self,
|
||||
GdkColorState *other)
|
||||
{
|
||||
GdkCicpColorState *cs1 = (GdkCicpColorState *) self;
|
||||
GdkCicpColorState *cs2 = (GdkCicpColorState *) other;
|
||||
|
||||
return gdk_cicp_equal (&cs1->cicp, &cs2->cicp);
|
||||
}
|
||||
|
||||
static const char *
|
||||
gdk_cicp_color_state_get_name (GdkColorState *self)
|
||||
{
|
||||
GdkCicpColorState *cs = (GdkCicpColorState *) self;
|
||||
|
||||
return cs->name;
|
||||
}
|
||||
|
||||
static GdkColorState *
|
||||
gdk_cicp_color_state_get_no_srgb_tf (GdkColorState *self)
|
||||
{
|
||||
GdkCicpColorState *cs = (GdkCicpColorState *) self;
|
||||
|
||||
return cs->no_srgb;
|
||||
}
|
||||
|
||||
static GdkFloatColorConvert
|
||||
gdk_cicp_color_state_get_convert_to (GdkColorState *self,
|
||||
GdkColorState *target)
|
||||
{
|
||||
if (!GDK_IS_DEFAULT_COLOR_STATE (target))
|
||||
return NULL;
|
||||
|
||||
switch (GDK_DEFAULT_COLOR_STATE_ID (target))
|
||||
{
|
||||
case GDK_COLOR_STATE_ID_SRGB:
|
||||
return gdk_cicp_to_srgb;
|
||||
case GDK_COLOR_STATE_ID_SRGB_LINEAR:
|
||||
return gdk_cicp_to_srgb_linear;
|
||||
case GDK_COLOR_STATE_ID_REC2100_PQ:
|
||||
return gdk_cicp_to_rec2100_pq;
|
||||
case GDK_COLOR_STATE_ID_REC2100_LINEAR:
|
||||
return gdk_cicp_to_rec2100_linear;
|
||||
|
||||
case GDK_COLOR_STATE_N_IDS:
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static GdkFloatColorConvert
|
||||
gdk_cicp_color_state_get_convert_from (GdkColorState *self,
|
||||
GdkColorState *source)
|
||||
{
|
||||
if (!GDK_IS_DEFAULT_COLOR_STATE (source))
|
||||
return NULL;
|
||||
|
||||
switch (GDK_DEFAULT_COLOR_STATE_ID (source))
|
||||
{
|
||||
case GDK_COLOR_STATE_ID_SRGB:
|
||||
return gdk_cicp_from_srgb;
|
||||
case GDK_COLOR_STATE_ID_SRGB_LINEAR:
|
||||
return gdk_cicp_from_srgb_linear;
|
||||
case GDK_COLOR_STATE_ID_REC2100_PQ:
|
||||
return gdk_cicp_from_rec2100_pq;
|
||||
case GDK_COLOR_STATE_ID_REC2100_LINEAR:
|
||||
return gdk_cicp_from_rec2100_linear;
|
||||
|
||||
case GDK_COLOR_STATE_N_IDS:
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const GdkCicp *
|
||||
gdk_cicp_color_state_get_cicp (GdkColorState *color_state)
|
||||
{
|
||||
GdkCicpColorState *self = (GdkCicpColorState *) color_state;
|
||||
|
||||
return &self->cicp;
|
||||
}
|
||||
|
||||
/* }}} */
|
||||
|
||||
static const
|
||||
GdkColorStateClass GDK_CICP_COLOR_STATE_CLASS = {
|
||||
.free = gdk_cicp_color_state_free,
|
||||
.equal = gdk_cicp_color_state_equal,
|
||||
.get_name = gdk_cicp_color_state_get_name,
|
||||
.get_no_srgb_tf = gdk_cicp_color_state_get_no_srgb_tf,
|
||||
.get_convert_to = gdk_cicp_color_state_get_convert_to,
|
||||
.get_convert_from = gdk_cicp_color_state_get_convert_from,
|
||||
.get_cicp = gdk_cicp_color_state_get_cicp,
|
||||
};
|
||||
|
||||
static inline void
|
||||
multiply (float res[3][3],
|
||||
const float m1[3][3],
|
||||
const float m2[3][3])
|
||||
{
|
||||
if ((float **) m1 == IDENTITY)
|
||||
memcpy (res, m2, sizeof (float) * 3 * 3);
|
||||
else if ((float **) m2 == IDENTITY)
|
||||
memcpy (res, m1, sizeof (float) * 3 * 3);
|
||||
else
|
||||
for (int i = 0; i < 3; i++)
|
||||
for (int j = 0; j < 3; j++)
|
||||
res[i][j] = m1[i][0] * m2[0][j] + m1[i][1] * m2[1][j] + m1[i][2] * m2[2][j];
|
||||
}
|
||||
|
||||
GdkColorState *
|
||||
gdk_color_state_new_for_cicp (const GdkCicp *cicp,
|
||||
GError **error)
|
||||
{
|
||||
GdkCicpColorState *self;
|
||||
GdkTransferFunc eotf;
|
||||
GdkTransferFunc oetf;
|
||||
gconstpointer to_xyz;
|
||||
gconstpointer from_xyz;
|
||||
|
||||
if (cicp->range == GDK_CICP_RANGE_NARROW || cicp->matrix_coefficients != 0)
|
||||
{
|
||||
g_set_error (error,
|
||||
G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
_("cicp: Narrow range or YUV not supported"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (cicp->color_primaries == 2 ||
|
||||
cicp->transfer_function == 2 ||
|
||||
cicp->matrix_coefficients == 2)
|
||||
{
|
||||
g_set_error (error,
|
||||
G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
_("cicp: Unspecified parameters not supported"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (guint i = 0; i < GDK_COLOR_STATE_N_IDS; i++)
|
||||
{
|
||||
if (gdk_cicp_equivalent (cicp, &gdk_default_color_states[i].cicp))
|
||||
return (GdkColorState *) &gdk_default_color_states[i];
|
||||
}
|
||||
|
||||
switch (cicp->transfer_function)
|
||||
{
|
||||
case 1:
|
||||
case 6:
|
||||
case 14:
|
||||
case 15:
|
||||
eotf = bt709_eotf;
|
||||
oetf = bt709_oetf;
|
||||
break;
|
||||
case 8:
|
||||
eotf = NONE;
|
||||
oetf = NONE;
|
||||
break;
|
||||
case 13:
|
||||
eotf = srgb_eotf;
|
||||
oetf = srgb_oetf;
|
||||
break;
|
||||
case 16:
|
||||
eotf = pq_eotf;
|
||||
oetf = pq_oetf;
|
||||
break;
|
||||
case 18:
|
||||
eotf = hlg_eotf;
|
||||
oetf = hlg_oetf;
|
||||
break;
|
||||
default:
|
||||
g_set_error (error,
|
||||
G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
_("cicp: Transfer function %u not supported"),
|
||||
cicp->transfer_function);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch (cicp->color_primaries)
|
||||
{
|
||||
case 1:
|
||||
to_xyz = srgb_to_xyz;
|
||||
from_xyz = xyz_to_srgb;
|
||||
break;
|
||||
case 5:
|
||||
to_xyz = pal_to_xyz;
|
||||
from_xyz = xyz_to_pal;
|
||||
break;
|
||||
case 6:
|
||||
to_xyz = ntsc_to_xyz;
|
||||
from_xyz = xyz_to_ntsc;
|
||||
break;
|
||||
case 9:
|
||||
to_xyz = rec2020_to_xyz;
|
||||
from_xyz = xyz_to_rec2020;
|
||||
break;
|
||||
case 10:
|
||||
to_xyz = IDENTITY;
|
||||
from_xyz = IDENTITY;
|
||||
break;
|
||||
case 12:
|
||||
to_xyz = p3_to_xyz;
|
||||
from_xyz = xyz_to_p3;
|
||||
break;
|
||||
default:
|
||||
g_set_error (error,
|
||||
G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
_("cicp: Color primaries %u not supported"),
|
||||
cicp->color_primaries);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
self = g_new0 (GdkCicpColorState, 1);
|
||||
|
||||
self->parent.klass = &GDK_CICP_COLOR_STATE_CLASS;
|
||||
self->parent.ref_count = 1;
|
||||
|
||||
/* sRGB is special-cased by being a default colorstate */
|
||||
self->parent.rendering_color_state = GDK_COLOR_STATE_REC2100_LINEAR;
|
||||
|
||||
self->parent.depth = GDK_MEMORY_FLOAT16;
|
||||
|
||||
memcpy (&self->cicp, cicp, sizeof (GdkCicp));
|
||||
|
||||
self->eotf = eotf;
|
||||
self->oetf = oetf;
|
||||
|
||||
multiply (self->to_srgb, xyz_to_srgb, to_xyz);
|
||||
multiply (self->to_rec2020, xyz_to_rec2020, to_xyz);
|
||||
multiply (self->from_srgb, from_xyz, srgb_to_xyz);
|
||||
multiply (self->from_rec2020, from_xyz, rec2020_to_xyz);
|
||||
|
||||
self->name = g_strdup_printf ("cicp-%u/%u/%u/%u",
|
||||
cicp->color_primaries,
|
||||
cicp->transfer_function,
|
||||
cicp->matrix_coefficients,
|
||||
cicp->range);
|
||||
|
||||
if (cicp->transfer_function == 13)
|
||||
{
|
||||
GdkCicp no_srgb;
|
||||
|
||||
memcpy (&no_srgb, cicp, sizeof (GdkCicp));
|
||||
no_srgb.transfer_function = 8;
|
||||
|
||||
self->no_srgb = gdk_color_state_new_for_cicp (&no_srgb, NULL);
|
||||
}
|
||||
|
||||
return (GdkColorState *) self;
|
||||
}
|
||||
|
||||
/* }}} */
|
||||
/* {{{ Private API */
|
||||
|
||||
|
@ -6,6 +6,8 @@
|
||||
#include "gdkmemoryformatprivate.h"
|
||||
#include "gdkrgba.h"
|
||||
|
||||
#include "gdkcicpparamsprivate.h"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
GDK_COLOR_STATE_ID_SRGB,
|
||||
@ -27,6 +29,7 @@ struct _GdkColorState
|
||||
GdkColorState *rendering_color_state;
|
||||
};
|
||||
|
||||
/* Note: self may be the source or the target colorstate */
|
||||
typedef void (* GdkFloatColorConvert)(GdkColorState *self,
|
||||
float (*values)[4],
|
||||
gsize n_values);
|
||||
@ -42,6 +45,7 @@ struct _GdkColorStateClass
|
||||
GdkColorState *target);
|
||||
GdkFloatColorConvert (* get_convert_from) (GdkColorState *self,
|
||||
GdkColorState *source);
|
||||
const GdkCicp * (* get_cicp) (GdkColorState *self);
|
||||
};
|
||||
|
||||
typedef struct _GdkDefaultColorState GdkDefaultColorState;
|
||||
@ -53,6 +57,8 @@ struct _GdkDefaultColorState
|
||||
const char *name;
|
||||
GdkColorState *no_srgb;
|
||||
GdkFloatColorConvert convert_to[GDK_COLOR_STATE_N_IDS];
|
||||
|
||||
GdkCicp cicp;
|
||||
};
|
||||
|
||||
extern GdkDefaultColorState gdk_default_color_states[GDK_COLOR_STATE_N_IDS];
|
||||
@ -133,6 +139,9 @@ _gdk_color_state_equal (GdkColorState *self,
|
||||
return self->klass->equal (self, other);
|
||||
}
|
||||
|
||||
/* Note: the functions returned from this expect the source
|
||||
* color state to be passed as self
|
||||
*/
|
||||
static inline GdkFloatColorConvert
|
||||
gdk_color_state_get_convert_to (GdkColorState *self,
|
||||
GdkColorState *target)
|
||||
@ -140,6 +149,9 @@ gdk_color_state_get_convert_to (GdkColorState *self,
|
||||
return self->klass->get_convert_to (self, target);
|
||||
}
|
||||
|
||||
/* Note: the functions returned from this expect the target
|
||||
* color state to be passed as self
|
||||
*/
|
||||
static inline GdkFloatColorConvert
|
||||
gdk_color_state_get_convert_from (GdkColorState *self,
|
||||
GdkColorState *source)
|
||||
@ -165,3 +177,12 @@ gdk_color_state_from_rgba (GdkColorState *self,
|
||||
convert = gdk_color_state_get_convert_to (GDK_COLOR_STATE_SRGB, self);
|
||||
convert (GDK_COLOR_STATE_SRGB, (float(*)[4]) out_color, 1);
|
||||
}
|
||||
|
||||
static inline const GdkCicp *
|
||||
gdk_color_state_get_cicp (GdkColorState *self)
|
||||
{
|
||||
return self->klass->get_cicp (self);
|
||||
}
|
||||
|
||||
GdkColorState * gdk_color_state_new_for_cicp (const GdkCicp *cicp,
|
||||
GError **error);
|
||||
|
Loading…
Reference in New Issue
Block a user