color: Add gdk_color_clamp_to_gamut

This is a very primitive way to get a color into gamut: just
clamp it.

Tests included.
This commit is contained in:
Matthias Clasen 2024-08-13 22:52:00 -04:00
parent ffb3b9bdd1
commit 4b5ead5718
3 changed files with 79 additions and 0 deletions

View File

@ -298,4 +298,46 @@ gdk_color_to_string (const GdkColor *self)
return g_string_free (string, FALSE); return g_string_free (string, FALSE);
} }
gboolean
gdk_color_in_gamut (const GdkColor *self,
GdkColorState *color_state)
{
float values[4];
const float *range;
gdk_color_to_float (self, color_state, values);
range = gdk_color_state_get_range (color_state);
return range[0] <= values[0] && values[0] <= range[1] &&
range[2] <= values[1] && values[1] <= range[3] &&
range[4] <= values[2] && values[2] <= range[5] &&
range[6] <= values[3] && values[3] <= range[7];
}
void
gdk_color_clamp_to_gamut (GdkColor *self,
GdkColorState *color_state)
{
GdkColor tmp;
const float *range;
gdk_color_to_float (self, color_state, tmp.values);
range = gdk_color_state_get_range (color_state);
if (range[0] > tmp.values[0] || tmp.values[0] > range[1] ||
range[2] > tmp.values[1] || tmp.values[1] > range[3] ||
range[4] > tmp.values[2] || tmp.values[2] > range[5] ||
range[6] > tmp.values[3] || tmp.values[3] > range[7])
{
tmp.color_state = color_state;
tmp.values[0] = CLAMP (tmp.values[0], range[0], range[1]);
tmp.values[1] = CLAMP (tmp.values[1], range[2], range[3]);
tmp.values[2] = CLAMP (tmp.values[2], range[4], range[5]);
tmp.values[3] = CLAMP (tmp.values[3], range[6], range[7]);
gdk_color_to_float (&tmp, self->color_state, self->values);
}
}

View File

@ -102,6 +102,12 @@ void gdk_color_print (const GdkColor *self,
char * gdk_color_to_string (const GdkColor *self); char * gdk_color_to_string (const GdkColor *self);
gboolean gdk_color_in_gamut (const GdkColor *self,
GdkColorState *color_state);
void gdk_color_clamp_to_gamut (GdkColor *self,
GdkColorState *color_state);
#include "gdkcolorimpl.h" #include "gdkcolorimpl.h"
G_END_DECLS G_END_DECLS

View File

@ -210,6 +210,36 @@ test_color_mislabel (void)
g_assert_true (red1 != red2); g_assert_true (red1 != red2);
} }
static void
test_color_gamut (void)
{
GdkColor color = GDK_COLOR_SRGB (1, 0, 0, 1);
g_assert_true (gdk_color_in_gamut (&color, GDK_COLOR_STATE_SRGB));
g_assert_true (gdk_color_in_gamut (&color, GDK_COLOR_STATE_SRGB_LINEAR));
g_assert_true (gdk_color_in_gamut (&color, GDK_COLOR_STATE_REC2100_PQ));
g_assert_true (gdk_color_in_gamut (&color, GDK_COLOR_STATE_REC2100_LINEAR));
gdk_color_finish (&color);
gdk_color_init (&color, GDK_COLOR_STATE_REC2100_PQ, (float[]) {0.9, 0.9, 0.9, 1});
g_assert_false (gdk_color_in_gamut (&color, GDK_COLOR_STATE_SRGB));
g_assert_false (gdk_color_in_gamut (&color, GDK_COLOR_STATE_SRGB_LINEAR));
g_assert_true (gdk_color_in_gamut (&color, GDK_COLOR_STATE_REC2100_PQ));
g_assert_true (gdk_color_in_gamut (&color, GDK_COLOR_STATE_REC2100_LINEAR));
gdk_color_clamp_to_gamut (&color, GDK_COLOR_STATE_SRGB);
/* clamping an out-of-gamut gray to srgb yields media white */
g_assert_cmpfloat_with_epsilon (color.red, 0.58, 0.001);
g_assert_cmpfloat_with_epsilon (color.green, 0.58, 0.001);
g_assert_cmpfloat_with_epsilon (color.blue, 0.58, 0.001);
g_assert_cmpfloat_with_epsilon (color.alpha, 1, 0.001);
gdk_color_finish (&color);
}
int int
main (int argc, char *argv[]) main (int argc, char *argv[])
{ {
@ -242,6 +272,7 @@ main (int argc, char *argv[])
g_test_add_func ("/colorstate/matrix/srgb_to_rec2020", test_srgb_to_rec2020); g_test_add_func ("/colorstate/matrix/srgb_to_rec2020", test_srgb_to_rec2020);
g_test_add_func ("/colorstate/matrix/rec2020_to_srgb", test_rec2020_to_srgb); g_test_add_func ("/colorstate/matrix/rec2020_to_srgb", test_rec2020_to_srgb);
g_test_add_func ("/color/mislabel", test_color_mislabel); g_test_add_func ("/color/mislabel", test_color_mislabel);
g_test_add_func ("/color/gamut", test_color_gamut);
return g_test_run (); return g_test_run ();
} }