From 4b5ead5718816207778a3250b48695580eb25284 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Tue, 13 Aug 2024 22:52:00 -0400 Subject: [PATCH] color: Add gdk_color_clamp_to_gamut This is a very primitive way to get a color into gamut: just clamp it. Tests included. --- gdk/gdkcolor.c | 42 +++++++++++++++++++++++++++++ gdk/gdkcolorprivate.h | 6 +++++ testsuite/gdk/colorstate-internal.c | 31 +++++++++++++++++++++ 3 files changed, 79 insertions(+) diff --git a/gdk/gdkcolor.c b/gdk/gdkcolor.c index a7dc080346..7fa72884d8 100644 --- a/gdk/gdkcolor.c +++ b/gdk/gdkcolor.c @@ -298,4 +298,46 @@ gdk_color_to_string (const GdkColor *self) 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); + } +} diff --git a/gdk/gdkcolorprivate.h b/gdk/gdkcolorprivate.h index 93369100a9..95d6ba083e 100644 --- a/gdk/gdkcolorprivate.h +++ b/gdk/gdkcolorprivate.h @@ -102,6 +102,12 @@ void gdk_color_print (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" G_END_DECLS diff --git a/testsuite/gdk/colorstate-internal.c b/testsuite/gdk/colorstate-internal.c index 41213c7c6b..a847a4d5a6 100644 --- a/testsuite/gdk/colorstate-internal.c +++ b/testsuite/gdk/colorstate-internal.c @@ -210,6 +210,36 @@ test_color_mislabel (void) 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 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/rec2020_to_srgb", test_rec2020_to_srgb); g_test_add_func ("/color/mislabel", test_color_mislabel); + g_test_add_func ("/color/gamut", test_color_gamut); return g_test_run (); }