From: Lennart Poettering Date: Wed, 20 Dec 2023 11:08:32 +0000 (+0100) Subject: color-util: add helper to convert RGB → HSV X-Git-Tag: v256-rc1~1428^2~4 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=447bcbfc903d56615809d7b578ddbec53704ccc5;p=thirdparty%2Fsystemd.git color-util: add helper to convert RGB → HSV We already have HSV → RGB, add the opposite operation. --- diff --git a/src/shared/color-util.c b/src/shared/color-util.c index c02b4b62eb4..776445ecfc5 100644 --- a/src/shared/color-util.c +++ b/src/shared/color-util.c @@ -5,6 +5,43 @@ #include "color-util.h" #include "macro.h" +void rgb_to_hsv(double r, double g, double b, + double *ret_h, double *ret_s, double *ret_v) { + + assert(r >= 0 && r <= 1); + assert(g >= 0 && g <= 1); + assert(b >= 0 && b <= 1); + assert(ret_h); + assert(ret_s); + assert(ret_v); + + double max_color = fmax(r, fmax(g, b)); + double min_color = fmin(r, fmin(g, b)); + double delta = max_color - min_color; + + *ret_v = max_color * 100.0; + + if (max_color > 0) + *ret_s = delta / max_color * 100.0; + else { + *ret_s = 0; + *ret_h = NAN; + return; + } + + if (delta > 0) { + if (r >= max_color) + *ret_h = 60 * fmod((g - b) / delta, 6); + else if (g >= max_color) + *ret_h = 60 * (((b - r) / delta) + 2); + else if (b >= max_color) + *ret_h = 60 * (((r - g) / delta) + 4); + + *ret_h = fmod(*ret_h, 360); + } else + *ret_h = NAN; +} + void hsv_to_rgb(double h, double s, double v, uint8_t* ret_r, uint8_t *ret_g, uint8_t *ret_b) { diff --git a/src/shared/color-util.h b/src/shared/color-util.h index d527794d09d..a4ae9eba09f 100644 --- a/src/shared/color-util.h +++ b/src/shared/color-util.h @@ -3,6 +3,9 @@ #include +void rgb_to_hsv(double r, double g, double b, + double *ret_h, double *ret_s, double *ret_v); + void hsv_to_rgb( double h, double s, double v, uint8_t* ret_r, uint8_t *ret_g, uint8_t *ret_b); diff --git a/src/test/meson.build b/src/test/meson.build index b0a92bb43b9..aec125d483a 100644 --- a/src/test/meson.build +++ b/src/test/meson.build @@ -57,6 +57,7 @@ simple_tests += files( 'test-cgroup.c', 'test-chase.c', 'test-clock.c', + 'test-color-util.c', 'test-compare-operator.c', 'test-condition.c', 'test-conf-files.c', diff --git a/src/test/test-color-util.c b/src/test/test-color-util.c new file mode 100644 index 00000000000..3d00d8719d8 --- /dev/null +++ b/src/test/test-color-util.c @@ -0,0 +1,63 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "color-util.h" +#include "tests.h" + +TEST(hsv_to_rgb) { + uint8_t r, g, b; + + hsv_to_rgb(0, 0, 0, &r, &g, &b); + assert(r == 0 && g == 0 && b == 0); + + hsv_to_rgb(60, 0, 0, &r, &g, &b); + assert(r == 0 && g == 0 && b == 0); + + hsv_to_rgb(0, 0, 100, &r, &g, &b); + assert(r == 255 && g == 255 && b == 255); + + hsv_to_rgb(0, 100, 100, &r, &g, &b); + assert(r == 255 && g == 0 && b == 0); + + hsv_to_rgb(120, 100, 100, &r, &g, &b); + assert(r == 0 && g == 255 && b == 0); + + hsv_to_rgb(240, 100, 100, &r, &g, &b); + assert(r == 0 && g == 0 && b == 255); + + hsv_to_rgb(311, 52, 62, &r, &g, &b); + assert(r == 158 && g == 75 && b == 143); +} + +TEST(rgb_to_hsv) { + + double h, s, v; + rgb_to_hsv(0, 0, 0, &h, &s, &v); + assert(s <= 0); + assert(v <= 0); + + rgb_to_hsv(1, 1, 1, &h, &s, &v); + assert(s <= 0); + assert(v >= 100); + + rgb_to_hsv(1, 0, 0, &h, &s, &v); + assert(h >= 359 || h <= 1); + assert(s >= 100); + assert(v >= 100); + + rgb_to_hsv(0, 1, 0, &h, &s, &v); + assert(h >= 119 && h <= 121); + assert(s >= 100); + assert(v >= 100); + + rgb_to_hsv(0, 0, 1, &h, &s, &v); + assert(h >= 239 && h <= 241); + assert(s >= 100); + assert(v >= 100); + + rgb_to_hsv(0.5, 0.6, 0.7, &h, &s, &v); + assert(h >= 209 && h <= 211); + assert(s >= 28 && s <= 31); + assert(v >= 69 && v <= 71); +} + +DEFINE_TEST_MAIN(LOG_DEBUG);