mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-04-14 08:21:27 -04:00
79 lines
2.6 KiB
C
79 lines
2.6 KiB
C
#include "lab.h"
|
|
|
|
#include <math.h>
|
|
|
|
struct lab
|
|
lab_from_rgb(uint32_t rgb)
|
|
{
|
|
/* Extract and normalize sRGB components */
|
|
float r = ((rgb >> 16) & 0xff) / 255.0f;
|
|
float g = ((rgb >> 8) & 0xff) / 255.0f;
|
|
float b = (rgb & 0xff) / 255.0f;
|
|
|
|
/* Linearize sRGB (inverse gamma) */
|
|
r = r > 0.04045f ? powf((r + 0.055f) / 1.055f, 2.4f) : r / 12.92f;
|
|
g = g > 0.04045f ? powf((g + 0.055f) / 1.055f, 2.4f) : g / 12.92f;
|
|
b = b > 0.04045f ? powf((b + 0.055f) / 1.055f, 2.4f) : b / 12.92f;
|
|
|
|
/* Linear RGB to XYZ (sRGB matrix, D65 illuminant) */
|
|
float x = (r * 0.4124564f + g * 0.3575761f + b * 0.1804375f) / 0.95047f;
|
|
float y = r * 0.2126729f + g * 0.7151522f + b * 0.0721750f;
|
|
float z = (r * 0.0193339f + g * 0.1191920f + b * 0.9503041f) / 1.08883f;
|
|
|
|
/* XYZ to LAB */
|
|
x = x > 0.008856f ? cbrtf(x) : 7.787f * x + 16.0f / 116.0f;
|
|
y = y > 0.008856f ? cbrtf(y) : 7.787f * y + 16.0f / 116.0f;
|
|
z = z > 0.008856f ? cbrtf(z) : 7.787f * z + 16.0f / 116.0f;
|
|
|
|
return (struct lab){
|
|
.l = 116.0f * y - 16.0f,
|
|
.a = 500.0f * (x - y),
|
|
.b = 200.0f * (y - z),
|
|
};
|
|
}
|
|
|
|
uint32_t
|
|
lab_to_rgb(struct lab c)
|
|
{
|
|
/* LAB to XYZ */
|
|
float y = (c.l + 16.0f) / 116.0f;
|
|
float x = c.a / 500.0f + y;
|
|
float z = y - c.b / 200.0f;
|
|
|
|
float x3 = x * x * x;
|
|
float y3 = y * y * y;
|
|
float z3 = z * z * z;
|
|
|
|
float xf = (x3 > 0.008856f ? x3 : (x - 16.0f / 116.0f) / 7.787f) * 0.95047f;
|
|
float yf = y3 > 0.008856f ? y3 : (y - 16.0f / 116.0f) / 7.787f;
|
|
float zf = (z3 > 0.008856f ? z3 : (z - 16.0f / 116.0f) / 7.787f) * 1.08883f;
|
|
|
|
/* XYZ to linear RGB (inverse sRGB matrix) */
|
|
float r = xf * 3.2404542f - yf * 1.5371385f - zf * 0.4985314f;
|
|
float g = xf * -0.9692660f + yf * 1.8760108f + zf * 0.0415560f;
|
|
float b = xf * 0.0556434f - yf * 0.2040259f + zf * 1.0572252f;
|
|
|
|
/* Apply sRGB gamma */
|
|
r = r > 0.0031308f ? 1.055f * powf(r, 1.0f / 2.4f) - 0.055f : 12.92f * r;
|
|
g = g > 0.0031308f ? 1.055f * powf(g, 1.0f / 2.4f) - 0.055f : 12.92f * g;
|
|
b = b > 0.0031308f ? 1.055f * powf(b, 1.0f / 2.4f) - 0.055f : 12.92f * b;
|
|
|
|
/* Clamp and quantize */
|
|
if (r < 0.0f) r = 0.0f; else if (r > 1.0f) r = 1.0f;
|
|
if (g < 0.0f) g = 0.0f; else if (g > 1.0f) g = 1.0f;
|
|
if (b < 0.0f) b = 0.0f; else if (b > 1.0f) b = 1.0f;
|
|
|
|
return (uint32_t)((uint8_t)(r * 255.0f + 0.5f) << 16 |
|
|
(uint8_t)(g * 255.0f + 0.5f) << 8 |
|
|
(uint8_t)(b * 255.0f + 0.5f));
|
|
}
|
|
|
|
struct lab
|
|
lab_lerp(float t, struct lab a, struct lab b)
|
|
{
|
|
return (struct lab){
|
|
.l = a.l + t * (b.l - a.l),
|
|
.a = a.a + t * (b.a - a.a),
|
|
.b = a.b + t * (b.b - a.b),
|
|
};
|
|
}
|