feat(color): add color module

This commit is contained in:
thetek 2023-04-27 09:26:54 +02:00
parent 95473337fa
commit 69519211ad
4 changed files with 187 additions and 1 deletions

View File

@ -9,6 +9,7 @@ functions can be found in the header files (with a short description) as well
as in the source files (with a detailed description and explanation of
parameters and return values).
- `color`: Color conversion and manipulation functions
- `common`: Common utilities that are very common but did not fit in any other
module, e.g. safe memory allocation or a few math functions
- `cstr`: Functions that expand C's `<string.h>` library for `char *` strings

155
lib/color.c Normal file
View File

@ -0,0 +1,155 @@
#include "color.h"
#include <errno.h>
#include <math.h>
/**
* turn a floating point rgb struct (r, g, b, a in [0.0f .. 1.0f]) into an
* integer rgb struct (r, g, b, a in [0 .. 255]).
*
* @param rgbf: the rgbf_t struct to convert
*
* @return the corresponding rgb_t struct
*/
rgb_t
rgbf_to_rgb (rgbf_t rgbf)
{
return (rgb_t) {
.r = (u8) lroundf (rgbf.r * 255.0f),
.g = (u8) lroundf (rgbf.g * 255.0f),
.b = (u8) lroundf (rgbf.b * 255.0f),
.a = (u8) lroundf (rgbf.a * 255.0f),
};
}
/**
* turn an integer rgb struct (r, g, b, a in [0 .. 255]) into a floating point
* rgb struct (r, g, b, a in [0.0f .. 1.0f]).
*
* @param rgb: the rgb_t struct to convert
*
* @return the corresponding rgbf_t struct
*/
rgbf_t
rgb_to_rgbf (rgb_t rgb)
{
return (rgbf_t) {
.r = ((f32) rgb.r) / 255.0f,
.g = ((f32) rgb.g) / 255.0f,
.b = ((f32) rgb.b) / 255.0f,
.a = ((f32) rgb.a) / 255.0f,
};
}
/**
* get the corresponding rgb color (integer) to a given hsl color. on error,
* errno is set and a zero-initialized struct is returned.
*
* @param hsl: the hsl color
*
* @return the corresponding rgb color
*
* @errno EINVAL: invalid hsl value passed
*/
inline rgb_t
hsl_to_rgb (hsl_t hsl)
{
return rgbf_to_rgb (hsl_to_rgbf (hsl));
}
/**
* get the corresponding rgb color (floating point) to a given hsl color. on
* error, errno is set and a zero-initialized struct is returned.
*
* @param hsl: the hsl color
*
* @return the corresponding rgb color
*
* @errno EINVAL: invalid hsl value passed
*
* @see https://en.wikipedia.org/wiki/HSL_and_HSV#Color_conversion_formulae
*/
rgbf_t
hsl_to_rgbf (hsl_t hsl)
{
f32 c, h2, m, x;
rgbf_t rgbf;
if (hsl.h > 360 || hsl.s < 0.0f || hsl.s > 1.0f ||
hsl.l < 0.0f || hsl.s > 1.0f)
return errno = EINVAL, (rgbf_t) {0};
c = (1.0f - fabsf (2.0f * hsl.l - 1.0f)) * hsl.s;
h2 = ((f32) hsl.h) / 60.0f;
x = c * (1.0f - fabsf (fmodf (h2, 2.0f) - 1.0f));
m = hsl.l - (c / 2.0f);
x += m;
c += m;
if (h2 < 1.0f) { rgbf.r = c; rgbf.g = x; rgbf.b = m; }
else if (h2 < 2.0f) { rgbf.r = x; rgbf.g = c; rgbf.b = m; }
else if (h2 < 3.0f) { rgbf.r = m; rgbf.g = c; rgbf.b = x; }
else if (h2 < 4.0f) { rgbf.r = m; rgbf.g = x; rgbf.b = c; }
else if (h2 < 5.0f) { rgbf.r = x; rgbf.g = m; rgbf.b = c; }
else if (h2 <= 6.0f) { rgbf.r = c; rgbf.g = m; rgbf.b = x; }
rgbf.a = hsl.a;
return rgbf;
}
/**
* get the corresponding hsl color to a given rgb color (integer).
*
* @param rgb: the rgb color
*
* @return the corresponding hsl color
*/
inline hsl_t
rgb_to_hsl (rgb_t rgb)
{
return rgbf_to_hsl (rgb_to_rgbf (rgb));
}
/**
* get the corresponding hsl color to a given rgb color (floating point). on
* error, errno is set and a zero-initialized struct is returned.
*
* @param rgbf: the rgb color
*
* @return the corresponding hsl color
*
* @errno EINVAL: invalid rgb value passed
*
* @see https://en.wikipedia.org/wiki/HSL_and_HSV#Color_conversion_formulae
*/
hsl_t
rgbf_to_hsl (rgbf_t rgbf)
{
f32 c, xmin, xmax;
hsl_t hsl;
if (rgbf.r < 0.0f || rgbf.r > 1.0f || rgbf.g < 0.0f || rgbf.g > 1.0f ||
rgbf.b < 0.0f || rgbf.b > 1.0f)
return errno = EINVAL, (hsl_t) {0};
xmax = fmaxf (rgbf.r, fmaxf (rgbf.g, rgbf.b));
xmin = fminf (rgbf.r, fminf (rgbf.g, rgbf.b));
c = xmax - xmin;
if (c == 0.0f)
hsl.h = 0;
else if (xmax == rgbf.r)
hsl.h = (u8) lroundf (60.0f * fmodf (((rgbf.g - rgbf.b) / c), 6));
else if (xmax == rgbf.g)
hsl.h = (u8) lroundf (60.0f * (((rgbf.b - rgbf.r) / c) + 2.0f));
else if (xmax == rgbf.b)
hsl.h = (u8) lroundf (60.0f * (((rgbf.r - rgbf.g) / c) + 4.0f));
hsl.a = rgbf.a;
hsl.l = (xmax + xmin) / 2.0f;
hsl.s = (hsl.l == 0.0f || hsl.l == 1.0f)
? 0.0f
: ((xmax - hsl.l) / fminf (hsl.l, 1.0f - hsl.l));
return hsl;
}

29
lib/inc/color.h Normal file
View File

@ -0,0 +1,29 @@
#ifndef COLOR_H_
#define COLOR_H_
#include "common.h"
/* integer rgb struct, fields accept [0 .. 255] */
typedef struct {
u8 r, g, b, a;
} rgb_t;
/* floating point rgb struct, fields accept [0.0f .. 1.0f] */
typedef struct {
f32 r, g, b, a;
} rgbf_t;
/* hsl struct, h accepts [0 .. 360]; s, l, a accept [0.0f .. 1.0f] */
typedef struct {
u16 h;
f32 s, l, a;
} hsl_t;
rgb_t rgbf_to_rgb (rgbf_t rgbf); /* turn a floating point rgb struct into an integer rbg struct */
rgbf_t rgb_to_rgbf (rgb_t rgb); /* turn an integer rgb struct into a floating point rbg struct */
rgb_t hsl_to_rgb (hsl_t hsl); /* get the corresponding rgb color (integer) to a given hsl color */
rgbf_t hsl_to_rgbf (hsl_t hsl); /* get the corresponding rgb color (floating point) to a given hsl color */
hsl_t rgb_to_hsl (rgb_t rgb); /* get the corresponding hsl color to a given rgb color (integer) */
hsl_t rgbf_to_hsl (rgbf_t rgbf); /* get the corresponding hsl color to a given rgb color (floating point) */
#endif // COLOR_H_

View File

@ -1,5 +1,6 @@
CC := gcc
CFLAGS := -Wall -Wextra -Werror=implicit -pedantic -Og -g -Ilib/inc
CLIBS := -lm
SRCFILES := $(wildcard lib/*.c)
SRCFILES += $(wildcard test/*.c)
@ -21,7 +22,7 @@ test: $(TARGET)
$(TARGET): mkdir $(OBJFILES)
$(CC) $(CFLAGS) $(OBJFILES) -o $(TARGET)
$(CC) $(CFLAGS) $(CLIBS) $(OBJFILES) -o $(TARGET)
obj/%.o: %.c
@$(CC) $(CFLAGS) $(DEPFLAGS) $<