commit b69e5e904d1499a13d7062b481d311b808592fed
parent 5ed8b2fdb20b211c8a238e6d596c065399f79fea
Author: Pollux <pollux@pollux.codes>
Date: Fri, 18 Jul 2025 17:46:58 -0500
feat: Add color space conversions
Signed-off-by: Pollux <pollux@pollux.codes>
Diffstat:
M | morph.c | | | 96 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- |
1 file changed, 94 insertions(+), 2 deletions(-)
diff --git a/morph.c b/morph.c
@@ -1,5 +1,97 @@
+
+/* See LICENSE file for copyright and license details. */
+
+#include <math.h>
#include <stdio.h>
-int main(int argc, char **argv) {
- printf("Hello, world!\n");
+#include <Imlib2.h>
+
+/// Type to represent a color in the srgb color space. Use the functions
+/// rgb_to_lab and lab_to_rgb to convert between different color spaces.
+typedef struct {
+ float r;
+ float g;
+ float b;
+} col_rgb_t;
+
+/// Type to represent a color in the OkLab color space. Use the functions
+/// rgb_to_lab and lab_to_rgb to convert between different color spaces.
+typedef struct {
+ float l;
+ float a;
+ float b;
+} col_lab_t;
+
+/// Convert a color in the srgb color space, used for color IO, to the OkLab
+/// perceptual color space.
+col_lab_t
+rgb_to_lab(col_rgb_t rgb) {
+
+ col_lab_t lab;
+ float lin_r, lin_g, lin_b;
+ float l, m, s;
+
+ lin_r = rgb.r >= 0.04045 ? powf((rgb.r + 0.055) / 1.055,
+ 2.4) : rgb.r / 12.92;
+ lin_g = rgb.g >= 0.04045 ? powf((rgb.g + 0.055) / 1.055,
+ 2.4) : rgb.g / 12.92;
+ lin_b = rgb.b >= 0.04045 ? powf((rgb.b + 0.055) / 1.055,
+ 2.4) : rgb.b / 12.92;
+
+ l = cbrtf(0.4122214708 * lin_r + 0.5363325363 * lin_g +
+ 0.0514459929 * lin_b);
+ m = cbrtf(0.2119034982 * lin_r + 0.6806995451 * lin_g +
+ 0.1073969566 * lin_b);
+ s = cbrtf(0.0883024619 * lin_r + 0.2817188376 * lin_g +
+ 0.6299787005 * lin_b);
+
+ lab.l = 0.2104542553 * l + 0.7936177850 * m - 0.0040720468 * s;
+ lab.a = 1.9779984951 * l - 2.4285922050 * m + 0.4505937099 * s;
+ lab.b = 0.0259040371 * l + 0.7827717662 * m - 0.8086757660 * s;
+
+ return lab;
+}
+
+/// Convert a color in the OkLab perceptual color space to the srgb color space
+/// for IO.
+col_rgb_t
+lab_to_rgb(col_lab_t lab) {
+
+ col_rgb_t rgb;
+ float l, m, s;
+ float lin_r, lin_g, lin_b;
+
+ l = lab.l + 0.3963377774 * lab.a + 0.2158037573 * lab.b;
+ m = lab.l - 0.1055613458 * lab.a - 0.0638541728 * lab.b;
+ s = lab.l - 0.0894841775 * lab.a - 1.2914855480 * lab.b;
+
+ l = l * l * l;
+ m = m * m * m;
+ s = s * s * s;
+
+ lin_r = 4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s;
+ lin_g = -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s;
+ lin_b = -0.0041960863 * l - 0.7034186147 * m + 1.7076147010 * s;
+
+ rgb.r = lin_r >= 0.0031308 ? 1.055 * powf(lin_r,
+ 1 / 2.4) -
+ 0.055 : 12.92 * lin_r;
+ rgb.g = lin_g >= 0.0031308 ? 1.055 * powf(lin_g,
+ 1 / 2.4) -
+ 0.055 : 12.92 * lin_g;
+ rgb.b = lin_b >= 0.0031308 ? 1.055 * powf(lin_b,
+ 1 / 2.4) -
+ 0.055 : 12.92 * lin_b;
+
+ return rgb;
+}
+
+int
+main(int argc, char **argv) {
+ col_rgb_t test_color = {.r = 1.0f,.g = 1.0f,.b = 1.0f };
+ col_lab_t lab_color = rgb_to_lab(test_color);
+ col_rgb_t out_color = lab_to_rgb(lab_color);
+
+ printf("Output color: R=%f, G=%f, B=%f\n", out_color.r, out_color.g,
+ out_color.b);
}