home | blog | art | now | git gpg | email | rss

morph

Generate xresources colors from an image.
git clone https://pollux.codes/git/morph.git
Log | Files | Refs | README | LICENSE
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:
Mmorph.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); }