Compare commits
8 Commits
rendering-
...
matthiasc/
Author | SHA1 | Date | |
---|---|---|---|
|
ebead0b629 | ||
|
acce932e8d | ||
|
ad9887457f | ||
|
740e9c6857 | ||
|
01ff202094 | ||
|
497585db37 | ||
|
24a55b0ac1 | ||
|
1382cf916b |
@@ -103,6 +103,71 @@ gdk_color_state_get_srgb_linear (void)
|
||||
return GDK_COLOR_STATE_SRGB_LINEAR;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_color_state_get_xyz:
|
||||
*
|
||||
* Returns the color state object representing the XYZ color space.
|
||||
*
|
||||
* Since: 4.16
|
||||
*/
|
||||
GdkColorState *
|
||||
gdk_color_state_get_xyz (void)
|
||||
{
|
||||
return GDK_COLOR_STATE_XYZ;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_color_state_get_oklab:
|
||||
*
|
||||
* Returns the color state object representing the OKLAB color space.
|
||||
*
|
||||
* Since: 4.16
|
||||
*/
|
||||
GdkColorState *
|
||||
gdk_color_state_get_oklab (void)
|
||||
{
|
||||
return GDK_COLOR_STATE_OKLAB;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_color_state_get_oklch:
|
||||
*
|
||||
* Returns the color state object representing the OKLCH color space.
|
||||
*
|
||||
* Since: 4.16
|
||||
*/
|
||||
GdkColorState *
|
||||
gdk_color_state_get_oklch (void)
|
||||
{
|
||||
return GDK_COLOR_STATE_OKLCH;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_color_state_get_rec2020:
|
||||
*
|
||||
* Returns the color state object representing the rec2020 color space.
|
||||
*
|
||||
* Since: 4.16
|
||||
*/
|
||||
GdkColorState *
|
||||
gdk_color_state_get_rec2020 (void)
|
||||
{
|
||||
return GDK_COLOR_STATE_REC2020;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_color_state_get_rec2020_linear:
|
||||
*
|
||||
* Returns the color state object representing the linear rec2020 color space.
|
||||
*
|
||||
* Since: 4.16
|
||||
*/
|
||||
GdkColorState *
|
||||
gdk_color_state_get_rec2020_linear (void)
|
||||
{
|
||||
return GDK_COLOR_STATE_REC2020_LINEAR;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_color_state_equal:
|
||||
* @self: a `GdkColorState`
|
||||
@@ -127,7 +192,7 @@ gboolean
|
||||
|
||||
/* }}} */
|
||||
/* {{{ Default implementation */
|
||||
|
||||
/* {{{ Vfuncs */
|
||||
static gboolean
|
||||
gdk_default_color_state_equal (GdkColorState *self,
|
||||
GdkColorState *other)
|
||||
@@ -151,6 +216,35 @@ gdk_default_color_state_get_no_srgb_tf (GdkColorState *color_state)
|
||||
return self->no_srgb;
|
||||
}
|
||||
|
||||
static GdkFloatColorConvert
|
||||
gdk_default_color_state_get_convert_to (GdkColorState *color_state,
|
||||
GdkColorState *target)
|
||||
{
|
||||
GdkDefaultColorState *self = (GdkDefaultColorState *) color_state;
|
||||
|
||||
if (!GDK_IS_DEFAULT_COLOR_STATE (target))
|
||||
return NULL;
|
||||
|
||||
return self->convert_to[GDK_DEFAULT_COLOR_STATE_ID (target)];
|
||||
}
|
||||
|
||||
/* }}} */
|
||||
/* {{{ Conversion functions */
|
||||
|
||||
#define COORDINATE_TRANSFORM(name, tf) \
|
||||
static void \
|
||||
name(GdkColorState *self, \
|
||||
float (*values)[4], \
|
||||
gsize n_values) \
|
||||
{ \
|
||||
for (gsize i = 0; i < n_values; i++) \
|
||||
{ \
|
||||
values[i][0] = tf (values[i][0]); \
|
||||
values[i][1] = tf (values[i][1]); \
|
||||
values[i][2] = tf (values[i][2]); \
|
||||
} \
|
||||
}
|
||||
|
||||
static inline float
|
||||
srgb_oetf (float v)
|
||||
{
|
||||
@@ -169,48 +263,283 @@ srgb_eotf (float v)
|
||||
return v / 12.92f;
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_default_srgb_to_linear_srgb (GdkColorState *self,
|
||||
float (*values)[4],
|
||||
gsize n_values)
|
||||
{
|
||||
gsize i;
|
||||
COORDINATE_TRANSFORM(gdk_default_srgb_to_srgb_linear, srgb_eotf)
|
||||
COORDINATE_TRANSFORM(gdk_default_srgb_linear_to_srgb, srgb_oetf)
|
||||
|
||||
for (i = 0; i < n_values; i++)
|
||||
static inline void
|
||||
vec3_multiply (const float matrix[3][3],
|
||||
const float vec[3],
|
||||
float res[3])
|
||||
{
|
||||
res[0] = matrix[0][0] * vec[0] + matrix[0][1] * vec[1] + matrix[0][2] * vec[2];
|
||||
res[1] = matrix[1][0] * vec[0] + matrix[1][1] * vec[1] + matrix[1][2] * vec[2];
|
||||
res[2] = matrix[2][0] * vec[0] + matrix[2][1] * vec[1] + matrix[2][2] * vec[2];
|
||||
}
|
||||
|
||||
#define LINEAR_TRANSFORM(name, matrix) \
|
||||
static void \
|
||||
name (GdkColorState *self, \
|
||||
float (*values)[4], \
|
||||
gsize n_values) \
|
||||
{ \
|
||||
for (gsize i = 0; i < n_values; i++) \
|
||||
{ \
|
||||
float res[3]; \
|
||||
\
|
||||
vec3_multiply (matrix, values[i], res); \
|
||||
\
|
||||
values[i][0] = res[0]; \
|
||||
values[i][1] = res[1]; \
|
||||
values[i][2] = res[2]; \
|
||||
} \
|
||||
}
|
||||
|
||||
static const float srgb_linear_to_xyz[3][3] = {
|
||||
{ (506752.0 / 1228815.0), (87881.0 / 245763.0), (12673.0 / 70218.0) },
|
||||
{ (87098.0 / 409605.0), (175762.0 / 245763.0), (12673.0 / 175545.0) },
|
||||
{ ( 7918.0 / 409605.0), (87881.0 / 737289.0), (1001167.0 / 1053270.0) },
|
||||
};
|
||||
|
||||
static const float xyz_to_srgb_linear[3][3] = {
|
||||
{ (12831.0 / 3959.0), - (329.0 / 214.0), - (1974.0 / 3959.0) },
|
||||
{ - (851781.0 / 878810.0), (1648619.0 / 878810.0), (36519.0 / 878810.0) },
|
||||
{ (705.0 / 12673.0), - (2585.0 / 12673.0), (705.0 / 667.0) },
|
||||
};
|
||||
|
||||
LINEAR_TRANSFORM(gdk_default_xyz_to_srgb_linear, xyz_to_srgb_linear)
|
||||
LINEAR_TRANSFORM(gdk_default_srgb_linear_to_xyz, srgb_linear_to_xyz)
|
||||
|
||||
#define DEG_TO_RAD(x) ((x) * G_PI / 180)
|
||||
#define RAD_TO_DEG(x) ((x) * 180 / G_PI)
|
||||
|
||||
static inline void
|
||||
_sincosf (float angle,
|
||||
float *out_s,
|
||||
float *out_c)
|
||||
{
|
||||
#ifdef HAVE_SINCOSF
|
||||
sincosf (angle, out_s, out_c);
|
||||
#else
|
||||
*out_s = sinf (angle);
|
||||
*out_c = cosf (angle);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_default_oklab_to_oklch (GdkColorState *self,
|
||||
float (*values)[4],
|
||||
gsize n_values)
|
||||
{
|
||||
for (gsize i = 0; i < n_values; i++)
|
||||
{
|
||||
values[i][0] = srgb_eotf (values[i][0]);
|
||||
values[i][1] = srgb_eotf (values[i][1]);
|
||||
values[i][2] = srgb_eotf (values[i][2]);
|
||||
float a = values[i][1];
|
||||
float b = values[i][2];
|
||||
float C, H;
|
||||
|
||||
C = hypotf (a, b);
|
||||
H = RAD_TO_DEG (atan2 (b, a));
|
||||
H = fmod (H, 360);
|
||||
if (H < 0)
|
||||
H += 360;
|
||||
|
||||
values[i][1] = C;
|
||||
values[i][2] = H;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_default_srgb_linear_to_srgb (GdkColorState *self,
|
||||
float (*values)[4],
|
||||
gsize n_values)
|
||||
gdk_default_oklch_to_oklab (GdkColorState *self,
|
||||
float (*values)[4],
|
||||
gsize n_values)
|
||||
{
|
||||
gsize i;
|
||||
|
||||
for (i = 0; i < n_values; i++)
|
||||
for (gsize i = 0; i < n_values; i++)
|
||||
{
|
||||
values[i][0] = srgb_oetf (values[i][0]);
|
||||
values[i][1] = srgb_oetf (values[i][1]);
|
||||
values[i][2] = srgb_oetf (values[i][2]);
|
||||
float C = values[i][1];
|
||||
float H = values[i][2];
|
||||
float a, b;
|
||||
|
||||
_sincosf (DEG_TO_RAD (H), &b, &a);
|
||||
a *= C;
|
||||
b *= C;
|
||||
|
||||
values[i][1] = a;
|
||||
values[i][2] = b;
|
||||
}
|
||||
}
|
||||
|
||||
static GdkFloatColorConvert
|
||||
gdk_default_color_state_get_convert_to (GdkColorState *color_state,
|
||||
GdkColorState *target)
|
||||
static const float oklab_to_lms[3][3] = {
|
||||
{ 1, 0.3963377774, 0.2158037573 },
|
||||
{ 1, - 0.1055613458, - 0.0638541728 },
|
||||
{ 1, - 0.0894841775, - 1.2914855480 },
|
||||
};
|
||||
|
||||
static const float lms_to_srgb_linear[3][3] = {
|
||||
{ 4.0767416621, - 3.3077115913, 0.2309699292 },
|
||||
{ - 1.2684380046, 2.6097574011, - 0.3413193965 },
|
||||
{ - 0.0041960863, - 0.7034186147, 1.7076147010 },
|
||||
};
|
||||
|
||||
#define SUM(a, b, i, j) ((a)[i][0] * (b)[0][j] + (a)[i][1] * (b)[1][j] + (a)[i][2] * (b)[2][j])
|
||||
#define MATMUL(name, a, b) \
|
||||
static const float name[3][3] = { \
|
||||
{ SUM((a),(b),0,0), SUM((a),(b),0,1), SUM((a),(b),0,2) }, \
|
||||
{ SUM((a),(b),1,0), SUM((a),(b),1,1), SUM((a),(b),1,2) }, \
|
||||
{ SUM((a),(b),2,0), SUM((a),(b),2,1), SUM((a),(b),2,2) }, \
|
||||
};
|
||||
|
||||
MATMUL(lms_to_xyz, lms_to_srgb_linear, srgb_linear_to_xyz)
|
||||
|
||||
static void
|
||||
gdk_default_oklab_to_xyz (GdkColorState *self,
|
||||
float (*values)[4],
|
||||
gsize n_values)
|
||||
{
|
||||
GdkDefaultColorState *self = (GdkDefaultColorState *) color_state;
|
||||
for (gsize i = 0; i < n_values; i++)
|
||||
{
|
||||
float lms[3];
|
||||
|
||||
if (!GDK_IS_DEFAULT_COLOR_STATE (target))
|
||||
return NULL;
|
||||
vec3_multiply (oklab_to_lms, values[i], lms);
|
||||
|
||||
return self->convert_to[GDK_DEFAULT_COLOR_STATE_ID (target)];
|
||||
lms[0] = powf (lms[0], 3);
|
||||
lms[1] = powf (lms[1], 3);
|
||||
lms[2] = powf (lms[2], 3);
|
||||
|
||||
vec3_multiply (lms_to_xyz, lms, values[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static const float srgb_linear_to_lms[3][3] = {
|
||||
{ 0.4122214708, 0.5363325363, 0.0514459929 },
|
||||
{ 0.2119034982, 0.6806995451, 0.1073969566 },
|
||||
{ 0.0883024619, 0.2817188376, 0.6299787005 },
|
||||
};
|
||||
|
||||
static const float lms_to_oklab[3][3] = {
|
||||
{ 0.2104542553, 0.7936177850, - 0.0040720468 },
|
||||
{ 1.9779984951, - 2.4285922050, 0.4505937099 },
|
||||
{ 0.0259040371, 0.7827717662, - 0.8086757660 },
|
||||
};
|
||||
|
||||
MATMUL(xyz_to_lms, xyz_to_srgb_linear, srgb_linear_to_lms)
|
||||
|
||||
static void
|
||||
gdk_default_xyz_to_oklab (GdkColorState *self,
|
||||
float (*values)[4],
|
||||
gsize n_values)
|
||||
{
|
||||
for (gsize i = 0; i < n_values; i++)
|
||||
{
|
||||
float lms[3];
|
||||
|
||||
vec3_multiply (xyz_to_lms, values[i], lms);
|
||||
|
||||
lms[0] = cbrtf (lms[0]);
|
||||
lms[1] = cbrtf (lms[1]);
|
||||
lms[2] = cbrtf (lms[2]);
|
||||
|
||||
vec3_multiply (lms_to_oklab, lms, values[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static inline float
|
||||
rec2020_eotf (float v)
|
||||
{
|
||||
float alpha = 1.09929682680944;
|
||||
float beta = 0.018053968510807;
|
||||
|
||||
int sign = v < 0 ? -1 : 1;
|
||||
float abs = fabsf (v);
|
||||
|
||||
if (abs < beta * 4.5 )
|
||||
return v/ 4.5;
|
||||
else
|
||||
return sign * powf ((abs + alpha - 1) / alpha, 1.0 / 0.45);
|
||||
}
|
||||
|
||||
static inline float
|
||||
rec2020_oetf (float v)
|
||||
{
|
||||
float alpha = 1.09929682680944;
|
||||
float beta = 0.018053968510807;
|
||||
int sign = v < 0 ? -1 : 1;
|
||||
float abs = fabsf (v);
|
||||
|
||||
if (abs > beta)
|
||||
return sign * (alpha * powf (abs, 0.45) - (alpha - 1));
|
||||
else
|
||||
return 4.5 * v;
|
||||
}
|
||||
|
||||
COORDINATE_TRANSFORM(gdk_default_rec2020_to_rec2020_linear, rec2020_eotf)
|
||||
COORDINATE_TRANSFORM(gdk_default_rec2020_linear_to_rec2020, rec2020_oetf)
|
||||
|
||||
static const float rec2020_linear_to_xyz[3][3] = {
|
||||
{ (63426534.0 / 99577255.0), (20160776.0 / 139408157.0), (47086771.0 / 278816314.0) },
|
||||
{ (26158966.0 / 99577255.0), (472592308.0 / 697040785.0), (8267143.0 / 139408157.0) },
|
||||
{ ( 0 / 1), (19567812.0 / 697040785.0), (295819943.0 / 278816314.0) },
|
||||
};
|
||||
|
||||
static const float xyz_to_rec2020_linear[3][3] = {
|
||||
{ (30757411.0 / 17917100.0), - (6372589.0 / 17917100.0), - (4539589.0 / 17917100.0) },
|
||||
{ - (19765991.0 / 29648200.0), (47925759.0 / 29648200.0), (467509.0 / 29648200.0) },
|
||||
{ (792561.0 / 44930125.0), - (1921689.0 / 44930125.0), (42328811.0 / 44930125.0) },
|
||||
};
|
||||
|
||||
LINEAR_TRANSFORM(gdk_default_rec2020_linear_to_xyz, rec2020_linear_to_xyz)
|
||||
LINEAR_TRANSFORM(gdk_default_xyz_to_rec2020_linear, xyz_to_rec2020_linear)
|
||||
|
||||
static inline float
|
||||
rec2100_pq_eotf (float v)
|
||||
{
|
||||
float ninv = (1 << 14) / 2610.0;
|
||||
float minv = (1 << 5) / 2523.0;
|
||||
float c1 = 3424.0 / (1 << 12);
|
||||
float c2 = 2413.0 / (1 << 7);
|
||||
float c3 = 2392.0 / (1 << 7);
|
||||
|
||||
float x = powf (MAX ((powf (v, minv) - c1), 0) / (c2 - (c3 * (powf (v, minv)))), ninv);
|
||||
|
||||
return x * 10000 / 203.0;
|
||||
}
|
||||
|
||||
static inline float
|
||||
rec2100_pq_oetf (float v)
|
||||
{
|
||||
float x = v * 203.0 / 10000.0;
|
||||
float n = 2610.0 / (1 << 14);
|
||||
float m = 2523.0 / (1 << 5);
|
||||
float c1 = 3424.0 / (1 << 12);
|
||||
float c2 = 2413.0 / (1 << 7);
|
||||
float c3 = 2392.0 / (1 << 7);
|
||||
|
||||
return powf (((c1 + (c2 * powf (x, n))) / (1 + (c3 * powf (x, n)))), m);
|
||||
}
|
||||
|
||||
COORDINATE_TRANSFORM(gdk_default_rec2100_pq_to_rec2100_linear, rec2100_pq_eotf)
|
||||
COORDINATE_TRANSFORM(gdk_default_rec2100_linear_to_rec2100_pq, rec2100_pq_oetf)
|
||||
|
||||
|
||||
#define CONCAT(name, f1, f2) \
|
||||
static void \
|
||||
name (GdkColorState *self, \
|
||||
float (*values)[4], \
|
||||
gsize n_values) \
|
||||
{ \
|
||||
f1 (self, values, n_values); \
|
||||
f2 (self, values, n_values); \
|
||||
}
|
||||
|
||||
CONCAT(gdk_default_xyz_to_srgb, gdk_default_xyz_to_srgb_linear, gdk_default_srgb_linear_to_srgb);
|
||||
CONCAT(gdk_default_srgb_to_xyz, gdk_default_srgb_to_srgb_linear, gdk_default_srgb_linear_to_xyz);
|
||||
CONCAT(gdk_default_oklch_to_xyz, gdk_default_oklch_to_oklab, gdk_default_oklab_to_xyz);
|
||||
CONCAT(gdk_default_xyz_to_oklch, gdk_default_xyz_to_oklab, gdk_default_oklab_to_oklch);
|
||||
CONCAT(gdk_default_rec2020_to_xyz, gdk_default_rec2020_to_rec2020_linear, gdk_default_rec2020_linear_to_xyz);
|
||||
CONCAT(gdk_default_xyz_to_rec2020, gdk_default_xyz_to_rec2020_linear, gdk_default_rec2020_linear_to_rec2020);
|
||||
CONCAT(gdk_default_rec2100_pq_to_xyz, gdk_default_rec2100_pq_to_rec2100_linear, gdk_default_rec2020_linear_to_xyz);
|
||||
CONCAT(gdk_default_xyz_to_rec2100_pq, gdk_default_xyz_to_rec2020_linear, gdk_default_rec2100_linear_to_rec2100_pq);
|
||||
|
||||
/* }}} */
|
||||
|
||||
static const
|
||||
GdkColorStateClass GDK_DEFAULT_COLOR_STATE_CLASS = {
|
||||
.free = NULL, /* crash here if this ever happens */
|
||||
@@ -231,7 +560,8 @@ GdkDefaultColorState gdk_default_color_states[] = {
|
||||
.name = "srgb",
|
||||
.no_srgb = GDK_COLOR_STATE_SRGB_LINEAR,
|
||||
.convert_to = {
|
||||
[GDK_COLOR_STATE_ID_SRGB_LINEAR] = gdk_default_srgb_to_linear_srgb,
|
||||
[GDK_COLOR_STATE_ID_SRGB_LINEAR] = gdk_default_srgb_to_srgb_linear,
|
||||
[GDK_COLOR_STATE_ID_XYZ] = gdk_default_srgb_to_xyz,
|
||||
},
|
||||
},
|
||||
[GDK_COLOR_STATE_ID_SRGB_LINEAR] = {
|
||||
@@ -245,6 +575,105 @@ GdkDefaultColorState gdk_default_color_states[] = {
|
||||
.no_srgb = NULL,
|
||||
.convert_to = {
|
||||
[GDK_COLOR_STATE_ID_SRGB] = gdk_default_srgb_linear_to_srgb,
|
||||
[GDK_COLOR_STATE_ID_XYZ] = gdk_default_srgb_linear_to_xyz,
|
||||
},
|
||||
},
|
||||
[GDK_COLOR_STATE_ID_XYZ] = {
|
||||
.parent = {
|
||||
.klass = &GDK_DEFAULT_COLOR_STATE_CLASS,
|
||||
.ref_count = 0,
|
||||
.depth = GDK_MEMORY_FLOAT16,
|
||||
.rendering_color_state = GDK_COLOR_STATE_XYZ,
|
||||
},
|
||||
.name = "xyz",
|
||||
.no_srgb = NULL,
|
||||
.convert_to = {
|
||||
[GDK_COLOR_STATE_ID_SRGB] = gdk_default_xyz_to_srgb,
|
||||
[GDK_COLOR_STATE_ID_SRGB_LINEAR] = gdk_default_xyz_to_srgb_linear,
|
||||
[GDK_COLOR_STATE_ID_OKLAB] = gdk_default_xyz_to_oklab,
|
||||
[GDK_COLOR_STATE_ID_OKLCH] = gdk_default_xyz_to_oklch,
|
||||
[GDK_COLOR_STATE_ID_REC2020] = gdk_default_xyz_to_rec2020,
|
||||
[GDK_COLOR_STATE_ID_REC2020_LINEAR] = gdk_default_xyz_to_rec2020_linear,
|
||||
[GDK_COLOR_STATE_ID_REC2100_PQ] = gdk_default_xyz_to_rec2100_pq,
|
||||
[GDK_COLOR_STATE_ID_REC2100_LINEAR] = gdk_default_xyz_to_rec2020_linear,
|
||||
},
|
||||
},
|
||||
[GDK_COLOR_STATE_ID_OKLAB] = {
|
||||
.parent = {
|
||||
.klass = &GDK_DEFAULT_COLOR_STATE_CLASS,
|
||||
.ref_count = 0,
|
||||
.depth = GDK_MEMORY_FLOAT16,
|
||||
.rendering_color_state = GDK_COLOR_STATE_SRGB_LINEAR,
|
||||
},
|
||||
.name = "oklab",
|
||||
.no_srgb = NULL,
|
||||
.convert_to = {
|
||||
[GDK_COLOR_STATE_ID_XYZ] = gdk_default_oklab_to_xyz,
|
||||
},
|
||||
},
|
||||
[GDK_COLOR_STATE_ID_OKLCH] = {
|
||||
.parent = {
|
||||
.klass = &GDK_DEFAULT_COLOR_STATE_CLASS,
|
||||
.ref_count = 0,
|
||||
.depth = GDK_MEMORY_FLOAT16,
|
||||
.rendering_color_state = GDK_COLOR_STATE_SRGB_LINEAR,
|
||||
},
|
||||
.name = "oklch",
|
||||
.no_srgb = NULL,
|
||||
.convert_to = {
|
||||
[GDK_COLOR_STATE_ID_XYZ] = gdk_default_oklch_to_xyz,
|
||||
},
|
||||
},
|
||||
[GDK_COLOR_STATE_ID_REC2020] = {
|
||||
.parent = {
|
||||
.klass = &GDK_DEFAULT_COLOR_STATE_CLASS,
|
||||
.ref_count = 0,
|
||||
.depth = GDK_MEMORY_FLOAT16,
|
||||
.rendering_color_state = GDK_COLOR_STATE_REC2020_LINEAR,
|
||||
},
|
||||
.name = "rec2020",
|
||||
.no_srgb = NULL,
|
||||
.convert_to = {
|
||||
[GDK_COLOR_STATE_ID_XYZ] = gdk_default_rec2020_to_xyz,
|
||||
},
|
||||
},
|
||||
[GDK_COLOR_STATE_ID_REC2020_LINEAR] = {
|
||||
.parent = {
|
||||
.klass = &GDK_DEFAULT_COLOR_STATE_CLASS,
|
||||
.ref_count = 0,
|
||||
.depth = GDK_MEMORY_FLOAT16,
|
||||
.rendering_color_state = GDK_COLOR_STATE_REC2020_LINEAR,
|
||||
},
|
||||
.name = "rec2020-linear",
|
||||
.no_srgb = NULL,
|
||||
.convert_to = {
|
||||
[GDK_COLOR_STATE_ID_XYZ] = gdk_default_rec2020_linear_to_xyz,
|
||||
},
|
||||
},
|
||||
[GDK_COLOR_STATE_ID_REC2100_PQ] = {
|
||||
.parent = {
|
||||
.klass = &GDK_DEFAULT_COLOR_STATE_CLASS,
|
||||
.ref_count = 0,
|
||||
.depth = GDK_MEMORY_FLOAT16,
|
||||
.rendering_color_state = GDK_COLOR_STATE_REC2100_LINEAR,
|
||||
},
|
||||
.name = "rec2100-pq",
|
||||
.no_srgb = NULL,
|
||||
.convert_to = {
|
||||
[GDK_COLOR_STATE_ID_XYZ] = gdk_default_rec2100_pq_to_xyz,
|
||||
},
|
||||
},
|
||||
[GDK_COLOR_STATE_ID_REC2100_LINEAR] = {
|
||||
.parent = {
|
||||
.klass = &GDK_DEFAULT_COLOR_STATE_CLASS,
|
||||
.ref_count = 0,
|
||||
.depth = GDK_MEMORY_FLOAT16,
|
||||
.rendering_color_state = GDK_COLOR_STATE_REC2100_LINEAR,
|
||||
},
|
||||
.name = "rec2100-linear",
|
||||
.no_srgb = NULL,
|
||||
.convert_to = {
|
||||
[GDK_COLOR_STATE_ID_XYZ] = gdk_default_rec2020_linear_to_xyz,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
@@ -43,6 +43,27 @@ GdkColorState * gdk_color_state_get_srgb (void);
|
||||
GDK_AVAILABLE_IN_4_16
|
||||
GdkColorState * gdk_color_state_get_srgb_linear (void);
|
||||
|
||||
GDK_AVAILABLE_IN_4_16
|
||||
GdkColorState * gdk_color_state_get_xyz (void);
|
||||
|
||||
GDK_AVAILABLE_IN_4_16
|
||||
GdkColorState * gdk_color_state_get_oklab (void);
|
||||
|
||||
GDK_AVAILABLE_IN_4_16
|
||||
GdkColorState * gdk_color_state_get_oklch (void);
|
||||
|
||||
GDK_AVAILABLE_IN_4_16
|
||||
GdkColorState * gdk_color_state_get_rec2020 (void);
|
||||
|
||||
GDK_AVAILABLE_IN_4_16
|
||||
GdkColorState * gdk_color_state_get_rec2020_linear (void);
|
||||
|
||||
GDK_AVAILABLE_IN_4_16
|
||||
GdkColorState * gdk_color_state_get_rec2100_pq (void);
|
||||
|
||||
GDK_AVAILABLE_IN_4_16
|
||||
GdkColorState * gdk_color_state_get_rec2100_linear (void);
|
||||
|
||||
GDK_AVAILABLE_IN_4_16
|
||||
gboolean gdk_color_state_equal (GdkColorState *self,
|
||||
GdkColorState *other);
|
||||
|
@@ -10,6 +10,13 @@ typedef enum
|
||||
{
|
||||
GDK_COLOR_STATE_ID_SRGB,
|
||||
GDK_COLOR_STATE_ID_SRGB_LINEAR,
|
||||
GDK_COLOR_STATE_ID_XYZ,
|
||||
GDK_COLOR_STATE_ID_OKLAB,
|
||||
GDK_COLOR_STATE_ID_OKLCH,
|
||||
GDK_COLOR_STATE_ID_REC2020,
|
||||
GDK_COLOR_STATE_ID_REC2020_LINEAR,
|
||||
GDK_COLOR_STATE_ID_REC2100_PQ,
|
||||
GDK_COLOR_STATE_ID_REC2100_LINEAR,
|
||||
|
||||
GDK_COLOR_STATE_N_IDS
|
||||
} GdkColorStateId;
|
||||
@@ -53,8 +60,15 @@ struct _GdkDefaultColorState
|
||||
|
||||
extern GdkDefaultColorState gdk_default_color_states[GDK_COLOR_STATE_N_IDS];
|
||||
|
||||
#define GDK_COLOR_STATE_SRGB ((GdkColorState *) &gdk_default_color_states[GDK_COLOR_STATE_ID_SRGB])
|
||||
#define GDK_COLOR_STATE_SRGB_LINEAR ((GdkColorState *) &gdk_default_color_states[GDK_COLOR_STATE_ID_SRGB_LINEAR])
|
||||
#define GDK_COLOR_STATE_SRGB ((GdkColorState *) &gdk_default_color_states[GDK_COLOR_STATE_ID_SRGB])
|
||||
#define GDK_COLOR_STATE_SRGB_LINEAR ((GdkColorState *) &gdk_default_color_states[GDK_COLOR_STATE_ID_SRGB_LINEAR])
|
||||
#define GDK_COLOR_STATE_XYZ ((GdkColorState *) &gdk_default_color_states[GDK_COLOR_STATE_ID_XYZ])
|
||||
#define GDK_COLOR_STATE_OKLAB ((GdkColorState *) &gdk_default_color_states[GDK_COLOR_STATE_ID_OKLAB])
|
||||
#define GDK_COLOR_STATE_OKLCH ((GdkColorState *) &gdk_default_color_states[GDK_COLOR_STATE_ID_OKLCH])
|
||||
#define GDK_COLOR_STATE_REC2020 ((GdkColorState *) &gdk_default_color_states[GDK_COLOR_STATE_ID_REC2020])
|
||||
#define GDK_COLOR_STATE_REC2020_LINEAR ((GdkColorState *) &gdk_default_color_states[GDK_COLOR_STATE_ID_REC2020_LINEAR])
|
||||
#define GDK_COLOR_STATE_REC2100_PQ ((GdkColorState *) &gdk_default_color_states[GDK_COLOR_STATE_ID_REC2100_PQ])
|
||||
#define GDK_COLOR_STATE_REC2100_LINEAR ((GdkColorState *) &gdk_default_color_states[GDK_COLOR_STATE_ID_REC2100_LINEAR])
|
||||
|
||||
#define GDK_IS_DEFAULT_COLOR_STATE(c) ((GdkDefaultColorState *) (c) >= &gdk_default_color_states[0] && \
|
||||
(GdkDefaultColorState *) (c) < &gdk_default_color_states[GDK_COLOR_STATE_N_IDS])
|
||||
|
@@ -2105,6 +2105,7 @@ gdk_memory_convert_color_state (guchar *data,
|
||||
{
|
||||
const GdkMemoryFormatDescription *desc = &memory_formats[format];
|
||||
GdkFloatColorConvert convert_func;
|
||||
GdkFloatColorConvert convert_func2 = NULL;
|
||||
float (*tmp)[4];
|
||||
|
||||
if (gdk_color_state_equal (src_cs, dest_cs))
|
||||
@@ -2126,8 +2127,14 @@ gdk_memory_convert_color_state (guchar *data,
|
||||
}
|
||||
|
||||
convert_func = gdk_color_state_get_convert_to (src_cs, dest_cs);
|
||||
/* FIXME: add fallback that goes via generic colorstate */
|
||||
g_assert (convert_func);
|
||||
|
||||
if (!convert_func)
|
||||
{
|
||||
convert_func = gdk_color_state_get_convert_to (src_cs, GDK_COLOR_STATE_XYZ);
|
||||
convert_func2 = gdk_color_state_get_convert_to (GDK_COLOR_STATE_XYZ, dest_cs);
|
||||
|
||||
g_assert (convert_func && convert_func2);
|
||||
}
|
||||
|
||||
tmp = g_malloc (sizeof (*tmp) * width);
|
||||
|
||||
@@ -2139,6 +2146,8 @@ gdk_memory_convert_color_state (guchar *data,
|
||||
unpremultiply (tmp, width);
|
||||
|
||||
convert_func (src_cs, tmp, width);
|
||||
if (convert_func2)
|
||||
convert_func2 (GDK_COLOR_STATE_XYZ, tmp, width);
|
||||
|
||||
if (desc->alpha == GDK_MEMORY_ALPHA_PREMULTIPLIED)
|
||||
premultiply (tmp, width);
|
||||
|
@@ -54,6 +54,13 @@
|
||||
|
||||
#define GDK_COLOR_STATE_ID_SRGB 0u
|
||||
#define GDK_COLOR_STATE_ID_SRGB_LINEAR 1u
|
||||
#define GDK_COLOR_STATE_ID_XYZ 2u
|
||||
#define GDK_COLOR_STATE_ID_OKLAB 3u
|
||||
#define GDK_COLOR_STATE_ID_OKLCH 4u
|
||||
#define GDK_COLOR_STATE_ID_REC2020 5u
|
||||
#define GDK_COLOR_STATE_ID_REC2020_LINEAR 6u
|
||||
#define GDK_COLOR_STATE_ID_REC2100_PQ 7u
|
||||
#define GDK_COLOR_STATE_ID_REC2100_LINEAR 8u
|
||||
|
||||
#define TOP 0u
|
||||
#define RIGHT 1u
|
||||
|
@@ -5,6 +5,368 @@
|
||||
|
||||
#define HAS_VARIATION(var) ((GSK_VARIATION & var) == var)
|
||||
|
||||
#define SOURCE_COLOR_STATE ((GSK_VARIATION >> VARIATION_SOURCE_SHIFT) & VARIATION_COLOR_STATE_MASK)
|
||||
#define TARGET_COLOR_STATE ((GSK_VARIATION >> VARIATION_TARGET_SHIFT) & VARIATION_COLOR_STATE_MASK)
|
||||
|
||||
float
|
||||
srgb_eotf (float v)
|
||||
{
|
||||
if (v >= 0.04045)
|
||||
return pow (((v + 0.055) / (1.0 + 0.055)), 2.4);
|
||||
else
|
||||
return v / 12.92;
|
||||
}
|
||||
|
||||
float
|
||||
srgb_oetf (float v)
|
||||
{
|
||||
if (v > 0.0031308)
|
||||
return 1.055 * pow (v, 1.0 / 2.4) - 0.055;
|
||||
else
|
||||
return 12.92 * v;
|
||||
}
|
||||
|
||||
vec4
|
||||
srgb_to_srgb_linear (vec4 color)
|
||||
{
|
||||
return vec4 (srgb_eotf (color.r),
|
||||
srgb_eotf (color.g),
|
||||
srgb_eotf (color.b),
|
||||
color.a);
|
||||
}
|
||||
|
||||
vec4
|
||||
srgb_linear_to_srgb (vec4 color)
|
||||
{
|
||||
return vec4 (srgb_oetf (color.r),
|
||||
srgb_oetf (color.g),
|
||||
srgb_oetf (color.b),
|
||||
color.a);
|
||||
}
|
||||
|
||||
vec4
|
||||
srgb_linear_to_xyz (vec4 color)
|
||||
{
|
||||
mat3 m = mat3 (506752.0 / 1228815.0, 87881.0 / 245763.0, 12673.0 / 70218.0,
|
||||
87098.0 / 409605.0, 175762.0 / 245763.0, 12673.0 / 175545.0,
|
||||
7918.0 / 409605.0, 87881.0 / 737289.0, 1001167.0 / 1053270.0);
|
||||
|
||||
return vec4 (color.rgb * m, color.a);
|
||||
}
|
||||
|
||||
vec4
|
||||
xyz_to_srgb_linear (vec4 color)
|
||||
{
|
||||
mat3 m = mat3 ( 12831.0 / 3959.0, -329.0 / 214.0, -1974.0 / 3959.0,
|
||||
-851781.0 / 878810.0, 1648619.0 / 878810.0, 36519.0 / 878810.0,
|
||||
705.0 / 12673.0, -2585.0 / 12673.0, 705.0 / 667.0);
|
||||
|
||||
return vec4 (color.xyz * m, color.a);
|
||||
}
|
||||
|
||||
#define M_PI 3.1415926535897932384626433832795
|
||||
#define RAD_TO_DEG(x) ((x)*180.0/M_PI)
|
||||
#define DEG_TO_RAD(x) ((x)*M_PI/180.0)
|
||||
|
||||
vec4
|
||||
oklab_to_oklch (vec4 color)
|
||||
{
|
||||
return vec4 (color.x,
|
||||
length (color.yz),
|
||||
RAD_TO_DEG (atan (color.z, color.y)),
|
||||
color.a);
|
||||
}
|
||||
|
||||
float
|
||||
normalize_hue (float h)
|
||||
{
|
||||
while (h < 0.0)
|
||||
h += 360.0;
|
||||
while (h > 360.0)
|
||||
h -= 360.0;
|
||||
return h;
|
||||
}
|
||||
|
||||
vec4
|
||||
oklch_to_oklab (vec4 color)
|
||||
{
|
||||
color.z = normalize_hue (color.z);
|
||||
|
||||
return vec4 (color.x,
|
||||
color.y * cos (DEG_TO_RAD (color.z)),
|
||||
color.y * sin (DEG_TO_RAD(color.z)),
|
||||
color.a);
|
||||
}
|
||||
|
||||
vec4
|
||||
oklab_to_xyz (vec4 color)
|
||||
{
|
||||
mat3 m1 = mat3 (1.0, 0.3963377774, 0.2158037573,
|
||||
1.0, -0.1055613458, -0.0638541728,
|
||||
1.0, -0.0894841775, -1.2914855480);
|
||||
|
||||
vec3 lms = color.rgb * m1;
|
||||
|
||||
lms = vec3 (pow (lms.x, 3.0),
|
||||
pow (lms.y, 3.0),
|
||||
pow (lms.z, 3.0));
|
||||
|
||||
mat3 m2 = mat3 ( 4.0767416621, -3.3077115913, 0.2309699292,
|
||||
-1.2684380046, 2.6097574011, -0.3413193965,
|
||||
-0.0041960863, -0.7034186147, 1.7076147010);
|
||||
mat3 m3 = mat3 (506752.0 / 1228815.0, 87881.0 / 245763.0, 12673.0 / 70218.0,
|
||||
87098.0 / 409605.0, 175762.0 / 245763.0, 12673.0 / 175545.0,
|
||||
7918.0 / 409605.0, 87881.0 / 737289.0, 1001167.0 / 1053270.0);
|
||||
|
||||
mat3 m4 = m2 * m3;
|
||||
|
||||
vec3 rgb = lms * m4;
|
||||
|
||||
return vec4 (rgb, color.a);
|
||||
}
|
||||
|
||||
vec4
|
||||
xyz_to_oklab (vec4 color)
|
||||
{
|
||||
mat3 m1 = mat3 ( 12831.0 / 3959.0, -329.0 / 214.0, -1974.0 / 3959.0,
|
||||
-851781.0 / 878810.0, 1648619.0 / 878810.0, 36519.0 / 878810.0,
|
||||
705.0 / 12673.0, -2585.0 / 12673.0, 705.0 / 667.0);
|
||||
|
||||
mat3 m2 = mat3 (0.4122214708, 0.5363325363, 0.0514459929,
|
||||
0.2119034982, 0.6806995451, 0.1073969566,
|
||||
0.0883024619, 0.2817188376, 0.6299787005);
|
||||
|
||||
mat3 m3 = m1 * m2;
|
||||
|
||||
vec3 lms = color.rgb * m3;
|
||||
|
||||
lms = vec3 (pow (lms.x, 1.0/3.0),
|
||||
pow (lms.y, 1.0/3.0),
|
||||
pow (lms.z, 1.0/3.0));
|
||||
|
||||
mat3 m4 = mat3 (0.2104542553, 0.7936177850, -0.0040720468,
|
||||
1.9779984951, -2.4285922050, 0.4505937099,
|
||||
0.0259040371, 0.7827717662, -0.8086757660);
|
||||
|
||||
vec3 lab = lms * m4;
|
||||
|
||||
return vec4 (lab, color.a);
|
||||
}
|
||||
|
||||
float
|
||||
rec2020_eotf (float v)
|
||||
{
|
||||
float alpha = 1.09929682680944;
|
||||
float beta = 0.018053968510807;
|
||||
|
||||
float sign = v < 0.0 ? -1.0 : 1.0;
|
||||
float vabs = abs (v);
|
||||
|
||||
if (vabs < beta * 4.5)
|
||||
return v / 4.5;
|
||||
else
|
||||
return sign * pow ((vabs + alpha - 1.0) / alpha, 1.0 / 0.45);
|
||||
}
|
||||
|
||||
float
|
||||
rec2020_oetf (float v)
|
||||
{
|
||||
float alpha = 1.09929682680944;
|
||||
float beta = 0.018053968510807;
|
||||
float sign = v < 0.0 ? -1.0 : 1.0;
|
||||
float vabs = abs (v);
|
||||
|
||||
if (vabs > beta)
|
||||
return sign * (alpha * pow (vabs, 0.45) - (alpha - 1.0));
|
||||
else
|
||||
return 4.5 * v;
|
||||
}
|
||||
|
||||
vec4
|
||||
rec2020_to_rec2020_linear (vec4 color)
|
||||
{
|
||||
return vec4 (rec2020_eotf (color.r),
|
||||
rec2020_eotf (color.g),
|
||||
rec2020_eotf (color.b),
|
||||
color.a);
|
||||
}
|
||||
|
||||
vec4
|
||||
rec2020_linear_to_rec2020 (vec4 color)
|
||||
{
|
||||
return vec4 (rec2020_oetf (color.r),
|
||||
rec2020_oetf (color.g),
|
||||
rec2020_oetf (color.b),
|
||||
color.a);
|
||||
}
|
||||
|
||||
vec4
|
||||
rec2020_linear_to_xyz (vec4 color)
|
||||
{
|
||||
mat3 m = mat3 (63426534.0 / 99577255.0, 20160776.0 / 139408157.0, 47086771.0 / 278816314.0,
|
||||
26158966.0 / 99577255.0, 472592308.0 / 697040785.0, 8267143.0 / 139408157.0,
|
||||
0.0, 19567812.0 / 697040785.0, 295819943.0 / 278816314.0);
|
||||
|
||||
return vec4 (color.rgb * m, color.a);
|
||||
}
|
||||
|
||||
vec4
|
||||
xyz_to_rec2020_linear (vec4 color)
|
||||
{
|
||||
mat3 m = mat3 ( 30757411.0 / 17917100.0, -6372589.0 / 17917100.0, -4539589.0 / 17917100.0,
|
||||
-19765991.0 / 29648200.0, 47925759.0 / 29648200.0, 467509.0 / 29648200.0,
|
||||
792561.0 / 44930125.0, -1921689.0 / 44930125.0, 42328811.0 / 44930125.0);
|
||||
|
||||
return vec4 (color.xyz * m, color.z);
|
||||
}
|
||||
|
||||
float
|
||||
rec2100_pq_eotf (float v)
|
||||
{
|
||||
float ninv = 16384.0 / 2610.0;
|
||||
float minv = 32.0 / 2523.0;
|
||||
float c1 = 3424.0 / 4096.0;
|
||||
float c2 = 2413.0 / 128.0;
|
||||
float c3 = 2392.0 / 128.0;
|
||||
|
||||
float x = pow (max ((pow (v, minv) - c1), 0.0) / (c2 - (c3 * (pow (v, minv)))), ninv);
|
||||
|
||||
return x * 10000.0 / 203.0;
|
||||
}
|
||||
|
||||
float
|
||||
rec2100_pq_oetf (float v)
|
||||
{
|
||||
float x = v * 203.0 / 10000.0;
|
||||
float n = 2610.0 / 16384.0;
|
||||
float m = 2523.0 / 32.0;
|
||||
float c1 = 3424.0 / 4096.0;
|
||||
float c2 = 2413.0 / 128.0;
|
||||
float c3 = 2392.0 / 128.0;
|
||||
|
||||
return pow (((c1 + (c2 * pow (x, n))) / (1.0 + (c3 * pow (x, n)))), m);
|
||||
}
|
||||
|
||||
vec4
|
||||
rec2100_pq_to_rec2100_linear (vec4 color)
|
||||
{
|
||||
return vec4 (rec2100_pq_eotf (color.r),
|
||||
rec2100_pq_eotf (color.g),
|
||||
rec2100_pq_eotf (color.b),
|
||||
color.a);
|
||||
}
|
||||
|
||||
vec4
|
||||
rec2100_linear_to_rec2100_pq (vec4 color)
|
||||
{
|
||||
return vec4 (rec2100_pq_oetf (color.r),
|
||||
rec2100_pq_oetf (color.g),
|
||||
rec2100_pq_oetf (color.b),
|
||||
color.a);
|
||||
}
|
||||
|
||||
#define CONCAT(f, f1, f2) vec4 f(vec4 color) { return f2(f1(color)); }
|
||||
|
||||
CONCAT(srgb_to_xyz, srgb_to_srgb_linear, srgb_linear_to_xyz)
|
||||
CONCAT(xyz_to_srgb, xyz_to_srgb_linear, srgb_linear_to_srgb)
|
||||
CONCAT(oklch_to_xyz, oklch_to_oklab, oklab_to_xyz)
|
||||
CONCAT(xyz_to_oklch, xyz_to_oklab, oklab_to_oklch)
|
||||
CONCAT(rec2020_to_xyz, rec2020_to_rec2020_linear, rec2020_linear_to_xyz)
|
||||
CONCAT(xyz_to_rec2020, xyz_to_rec2020_linear, rec2020_linear_to_rec2020)
|
||||
CONCAT(rec2100_pq_to_xyz, rec2100_pq_to_rec2100_linear, rec2020_linear_to_xyz)
|
||||
CONCAT(xyz_to_rec2100_pq, xyz_to_rec2020_linear, rec2100_linear_to_rec2100_pq)
|
||||
|
||||
#define PAIR(_from_cs, _to_cs) ((_from_cs) << 16 | (_to_cs))
|
||||
|
||||
bool
|
||||
do_conversion (vec4 color,
|
||||
uint from_cs,
|
||||
uint to_cs,
|
||||
out vec4 result)
|
||||
{
|
||||
switch (PAIR (from_cs, to_cs))
|
||||
{
|
||||
case PAIR (GDK_COLOR_STATE_ID_SRGB, GDK_COLOR_STATE_ID_SRGB_LINEAR):
|
||||
result = srgb_to_srgb_linear (color);
|
||||
break;
|
||||
case PAIR (GDK_COLOR_STATE_ID_SRGB_LINEAR, GDK_COLOR_STATE_ID_SRGB):
|
||||
result = srgb_linear_to_srgb (color);
|
||||
break;
|
||||
|
||||
case PAIR (GDK_COLOR_STATE_ID_SRGB_LINEAR, GDK_COLOR_STATE_ID_XYZ):
|
||||
result = srgb_linear_to_xyz (color);
|
||||
break;
|
||||
case PAIR (GDK_COLOR_STATE_ID_SRGB, GDK_COLOR_STATE_ID_XYZ):
|
||||
result = srgb_to_xyz (color);
|
||||
break;
|
||||
case PAIR (GDK_COLOR_STATE_ID_OKLAB, GDK_COLOR_STATE_ID_XYZ):
|
||||
result = oklab_to_xyz (color);
|
||||
break;
|
||||
case PAIR (GDK_COLOR_STATE_ID_OKLCH, GDK_COLOR_STATE_ID_XYZ):
|
||||
result = oklch_to_xyz (color);
|
||||
break;
|
||||
case PAIR (GDK_COLOR_STATE_ID_REC2020, GDK_COLOR_STATE_ID_XYZ):
|
||||
result = rec2020_to_xyz (color);
|
||||
break;
|
||||
case PAIR (GDK_COLOR_STATE_ID_REC2020_LINEAR, GDK_COLOR_STATE_ID_XYZ):
|
||||
result = rec2020_linear_to_xyz (color);
|
||||
break;
|
||||
case PAIR (GDK_COLOR_STATE_ID_REC2100_PQ, GDK_COLOR_STATE_ID_XYZ):
|
||||
result = rec2100_pq_to_xyz (color);
|
||||
break;
|
||||
case PAIR (GDK_COLOR_STATE_ID_REC2100_LINEAR, GDK_COLOR_STATE_ID_XYZ):
|
||||
result = rec2020_linear_to_xyz (color);
|
||||
break;
|
||||
|
||||
case PAIR (GDK_COLOR_STATE_ID_XYZ, GDK_COLOR_STATE_ID_SRGB_LINEAR):
|
||||
result = xyz_to_srgb_linear (color);
|
||||
break;
|
||||
case PAIR (GDK_COLOR_STATE_ID_XYZ, GDK_COLOR_STATE_ID_SRGB):
|
||||
result = xyz_to_srgb (color);
|
||||
break;
|
||||
case PAIR (GDK_COLOR_STATE_ID_XYZ, GDK_COLOR_STATE_ID_OKLAB):
|
||||
result = xyz_to_oklab (color);
|
||||
break;
|
||||
case PAIR (GDK_COLOR_STATE_ID_XYZ, GDK_COLOR_STATE_ID_OKLCH):
|
||||
result = xyz_to_oklch (color);
|
||||
break;
|
||||
case PAIR (GDK_COLOR_STATE_ID_XYZ, GDK_COLOR_STATE_ID_REC2020):
|
||||
result = xyz_to_rec2020 (color);
|
||||
break;
|
||||
case PAIR (GDK_COLOR_STATE_ID_XYZ, GDK_COLOR_STATE_ID_REC2020_LINEAR):
|
||||
result = xyz_to_rec2020_linear (color);
|
||||
break;
|
||||
case PAIR (GDK_COLOR_STATE_ID_XYZ, GDK_COLOR_STATE_ID_REC2100_PQ):
|
||||
result = xyz_to_rec2100_pq (color);
|
||||
break;
|
||||
case PAIR (GDK_COLOR_STATE_ID_XYZ, GDK_COLOR_STATE_ID_REC2100_LINEAR):
|
||||
result = xyz_to_rec2020_linear (color);
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
vec4
|
||||
color_convert (vec4 color)
|
||||
{
|
||||
vec4 result;
|
||||
|
||||
if (SOURCE_COLOR_STATE == TARGET_COLOR_STATE)
|
||||
return color;
|
||||
|
||||
if (!do_conversion (color, SOURCE_COLOR_STATE, TARGET_COLOR_STATE, result))
|
||||
{
|
||||
do_conversion (color, SOURCE_COLOR_STATE, GDK_COLOR_STATE_ID_XYZ, result);
|
||||
do_conversion (result, GDK_COLOR_STATE_ID_XYZ, TARGET_COLOR_STATE, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
PASS(0) vec2 _pos;
|
||||
PASS_FLAT(1) Rect _rect;
|
||||
PASS(2) vec2 _tex_coord;
|
||||
|
@@ -1,4 +1,7 @@
|
||||
#include <gdk/gdk.h>
|
||||
#include <gdk/gdkcolorstateprivate.h>
|
||||
#include <gdk/gdkmemoryformatprivate.h>
|
||||
#include <math.h>
|
||||
|
||||
static void
|
||||
test_srgb (void)
|
||||
@@ -14,12 +17,105 @@ test_srgb (void)
|
||||
g_assert_false (gdk_color_state_equal (srgb, srgb_linear));
|
||||
}
|
||||
|
||||
static float
|
||||
image_distance (const guchar *data,
|
||||
const guchar *data2,
|
||||
gsize width,
|
||||
gsize height,
|
||||
gsize stride)
|
||||
{
|
||||
float dist = 0;
|
||||
|
||||
for (gsize i = 0; i < height; i++)
|
||||
{
|
||||
const float *p = (const float *) (data + i * stride);
|
||||
const float *p2 = (const float *) (data2 + i * stride);
|
||||
|
||||
for (gsize j = 0; j < width; j++)
|
||||
{
|
||||
float dr, dg, db, da;
|
||||
|
||||
dr = p[4 * j + 0] - p2[4 * j + 0];
|
||||
dg = p[4 * j + 1] - p2[4 * j + 1];
|
||||
db = p[4 * j + 2] - p2[4 * j + 2];
|
||||
da = p[4 * j + 3] - p2[4 * j + 3];
|
||||
|
||||
dist = MAX (dist, dr * dr + dg * dg + db * db + da * da);
|
||||
}
|
||||
}
|
||||
|
||||
return sqrt (dist);
|
||||
}
|
||||
|
||||
static void
|
||||
test_convert (gconstpointer testdata)
|
||||
{
|
||||
GdkColorState *cs = (GdkColorState *) testdata;
|
||||
char *path;
|
||||
GdkTexture *texture;
|
||||
GdkTextureDownloader *downloader;
|
||||
GError *error = NULL;
|
||||
GBytes *bytes;
|
||||
const guchar *data;
|
||||
guchar *data2;
|
||||
gsize width, height;
|
||||
gsize size;
|
||||
gsize stride;
|
||||
|
||||
path = g_test_build_filename (G_TEST_DIST, "image-data", "image.png", NULL);
|
||||
|
||||
texture = gdk_texture_new_from_filename (path, &error);
|
||||
g_assert_no_error (error);
|
||||
|
||||
width = gdk_texture_get_width (texture);
|
||||
height = gdk_texture_get_height (texture);
|
||||
|
||||
downloader = gdk_texture_downloader_new (texture);
|
||||
gdk_texture_downloader_set_format (downloader, GDK_MEMORY_R32G32B32A32_FLOAT);
|
||||
|
||||
bytes = gdk_texture_downloader_download_bytes (downloader, &stride);
|
||||
data = g_bytes_get_data (bytes, &size);
|
||||
data2 = g_memdup2 (data, size);
|
||||
|
||||
gdk_memory_convert_color_state (data2,
|
||||
stride,
|
||||
GDK_MEMORY_R32G32B32A32_FLOAT,
|
||||
gdk_texture_get_color_state (texture),
|
||||
cs,
|
||||
width,
|
||||
height);
|
||||
|
||||
gdk_memory_convert_color_state (data2,
|
||||
stride,
|
||||
GDK_MEMORY_R32G32B32A32_FLOAT,
|
||||
cs,
|
||||
gdk_texture_get_color_state (texture),
|
||||
width,
|
||||
height);
|
||||
|
||||
g_assert_true (image_distance (data, data2, width, height, stride) < 0.001);
|
||||
|
||||
g_free (data2);
|
||||
g_bytes_unref (bytes);
|
||||
gdk_texture_downloader_free (downloader);
|
||||
g_object_unref (texture);
|
||||
g_free (path);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
(g_test_init) (&argc, &argv, NULL);
|
||||
|
||||
g_test_add_func ("/colorstate/srgb", test_srgb);
|
||||
g_test_add_data_func ("/colorstate/convert/srgb<->srgb-linear", GDK_COLOR_STATE_SRGB_LINEAR, test_convert);
|
||||
g_test_add_data_func ("/colorstate/convert/srgb<->xyz", GDK_COLOR_STATE_XYZ, test_convert);
|
||||
g_test_add_data_func ("/colorstate/convert/srgb<->oklab", GDK_COLOR_STATE_OKLAB, test_convert);
|
||||
g_test_add_data_func ("/colorstate/convert/srgb<->oklch", GDK_COLOR_STATE_OKLCH, test_convert);
|
||||
g_test_add_data_func ("/colorstate/convert/srgb<->rec2020", GDK_COLOR_STATE_REC2020, test_convert);
|
||||
g_test_add_data_func ("/colorstate/convert/srgb<->rec2020-linear", GDK_COLOR_STATE_REC2020_LINEAR, test_convert);
|
||||
g_test_add_data_func ("/colorstate/convert/srgb<->rec2100-pq", GDK_COLOR_STATE_REC2100_PQ, test_convert);
|
||||
g_test_add_data_func ("/colorstate/convert/srgb<->rec2100-linear", GDK_COLOR_STATE_REC2100_LINEAR, test_convert);
|
||||
|
||||
return g_test_run ();
|
||||
}
|
||||
|
Reference in New Issue
Block a user