Created
September 4, 2020 22:18
-
-
Save cjgajard/743450e26d81d33ede98ebd291e1970e to your computer and use it in GitHub Desktop.
Conversion algorithm from LCH(ab) to RGB.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Conversion algorithm from LCH(ab) to RGB. Following the directives from w3. | |
* https://www.w3.org/TR/css-color-4/#lab-to-rgb | |
* | |
* Tags: luma,chroma,hue,lab,lch,cielab,c,windows,win10 | |
* Author: Carlos Gajardo (github.com/cjgajard). | |
* Date: 2020-09-04 | |
*/ | |
#define _USE_MATH_DEFINES | |
#include <math.h> | |
struct rgba { | |
int r, g, b, a; | |
}; | |
#define XD50 0.96422 | |
#define YD50 1.0 | |
#define ZD50 0.82521 | |
#define CRE (6.0 / 29.0) | |
#define K 903.3 | |
#define KE 8.0 | |
#define F_XZ(n) ((n) > CRE ? (n) * (n) * (n) : (116 * (n) - 16) / K) | |
static double srgbgamma (double n) | |
{ | |
return n <= 0.0031308 ? 12.92 * n : 1.055 * pow(n, 1 / 2.4) - 0.055; | |
} | |
static struct rgba lab2rgb (double L, double a, double b) | |
{ | |
/* | |
* From Lab to D50-XYZ. | |
* http://www.brucelindbloom.com/index.html?Eqn_Lab_to_XYZ.html | |
*/ | |
double y = (L + 16) / 116.0; | |
double x = y + a / 500.0; | |
double z = y - b / 200.0; | |
x = XD50 * F_XZ(x); | |
y = YD50 * (L > KE ? y * y * y : L / K); | |
z = ZD50 * F_XZ(z); | |
/* | |
* Chromatic adaptation from D50-XYZ to D65-XYZ. | |
* http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html | |
*/ | |
x = 0.9555766 * x - 0.0230393 * y + 0.0631636 * z; | |
y = -0.0282895 * x + 1.0099416 * y + 0.0210077 * z; | |
z = 0.0122982 * x - 0.0204830 * y + 1.3299098 * z; | |
/* | |
* XYZ to RGB. | |
* http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_RGB.html | |
* | |
* Linear sRGB using [M]-1 for sRGB|D65 | |
* http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html | |
*/ | |
double r_ = 3.2404542 * x - 1.5371385 * y - 0.4985314 * z; | |
double g_ = -0.9692660 * x + 1.8760108 * y + 0.0415560 * z; | |
double b_ = 0.0556434 * x - 0.2040259 * y + 1.0572252 * z; | |
/* gamma companding */ | |
r_ = srgbgamma(r_); | |
g_ = srgbgamma(g_); | |
b_ = srgbgamma(b_); | |
/* clipping */ | |
r_ = r_ > 1 ? 1 : (r_ < 0 ? 0 : r_); | |
g_ = g_ > 1 ? 1 : (g_ < 0 ? 0 : g_); | |
b_ = b_ > 1 ? 1 : (b_ < 0 ? 0 : b_); | |
/* rgb 0-255 */ | |
struct rgba color = { | |
(int)(0xff * r_), | |
(int)(0xff * g_), | |
(int)(0xff * b_), | |
0xff, | |
}; | |
return color; | |
} | |
/* | |
* Transform lch to rgb. | |
* l [0.0-1.0] Luma. | |
* c [0.0-1.0] Chroma. This argument is actually unbound. | |
* h [0-359] Hue. In degrees, 0deg is not #f00. | |
*/ | |
struct rgba lch (double l, double c, double h) | |
{ | |
double hrad = h * M_PI / 180.0; | |
double a = cos(hrad) * c * 100; | |
double b = sin(hrad) * c * 100; | |
return lab2rgb(l * 100, a, b); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment