color-util: add helper to convert RGB → HSV

We already have HSV → RGB, add the opposite operation.
This commit is contained in:
Lennart Poettering
2023-12-20 12:08:32 +01:00
parent eee799fa86
commit 447bcbfc90
4 changed files with 104 additions and 0 deletions

View File

@@ -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) {

View File

@@ -3,6 +3,9 @@
#include <inttypes.h>
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);

View File

@@ -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',

View File

@@ -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);