Skip to content

Instantly share code, notes, and snippets.

@cjgajard
Created September 4, 2020 22:18
Show Gist options
  • Save cjgajard/743450e26d81d33ede98ebd291e1970e to your computer and use it in GitHub Desktop.
Save cjgajard/743450e26d81d33ede98ebd291e1970e to your computer and use it in GitHub Desktop.
Conversion algorithm from LCH(ab) to RGB.
/*
* 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