Skip to content

Instantly share code, notes, and snippets.

@eldh
Last active April 7, 2019 12:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save eldh/40f5b1dca4345d368097b6847ffcc4f6 to your computer and use it in GitHub Desktop.
Save eldh/40f5b1dca4345d368097b6847ffcc4f6 to your computer and use it in GitHub Desktop.
LAB <-> RGB in Reason
exception InvalidValue(string);
let toInt = f => (f +. 0.5)->int_of_float;
module Constants = {
let kn = 18;
let xn = 0.950470;
let yn = 1.;
let zn = 1.088830;
let t0 = 0.137931034; // 4 / 29
let t1 = 0.206896552; // 6 / 29
let t2 = 0.12841855; // 3 * t1 * t1
let t3 = 0.008856452; // t1 * t1 * t1
};
let xyz_rgb = r => {
255. *. (r <= 0.00304 ? 12.92 *. r : 1.055 *. r ** (1. /. 2.4) -. 0.055);
};
let lab_xyz = t => {
t > Constants.t1 ? t *. t *. t : Constants.t2 *. (t -. Constants.t0);
};
let toRGB = lab => {
let (l, a, b, alpha) = lab;
let y0 = (l +. 16.) /. 116.;
let x0 = y0 +. a /. 500.;
let z0 = y0 -. b /. 200.;
let y = Constants.yn *. lab_xyz(y0);
let x = Constants.xn *. lab_xyz(x0);
let z = Constants.zn *. lab_xyz(z0);
let r = xyz_rgb(3.2404542 *. x -. 1.5371385 *. y -. 0.4985314 *. z); // D65 -> sRGB
let g = xyz_rgb((-0.9692660) *. x +. 1.8760108 *. y +. 0.0415560 *. z);
let b_ = xyz_rgb(0.0556434 *. x -. 0.2040259 *. y +. 1.0572252 *. z);
(r->toInt, g->toInt, b_->toInt, alpha);
};
let toCssRGB = t => {
let (r, g, b, a) = toRGB(t);
Css.rgba(r, g, b, a);
};
let rgb_xyz = r => {
let r2 = r /. 255.;
if (r2 <= 0.04045) {
r2 /. 12.92;
} else {
((r2 +. 0.055) /. 1.055) ** 2.4;
};
};
let xyz_lab = t =>
if (t > Constants.t3) {
t ** (1. /. 3.);
} else {
t /. Constants.t2 +. Constants.t0;
};
let rgb2xyz = (r_, g_, b_) => {
let r = rgb_xyz(r_->float_of_int);
let g = rgb_xyz(g_->float_of_int);
let b = rgb_xyz(b_->float_of_int);
let x =
xyz_lab(
(0.4124564 *. r +. 0.3575761 *. g +. 0.1804375 *. b) /. Constants.xn,
);
let y =
xyz_lab(
(0.2126729 *. r +. 0.7151522 *. g +. 0.0721750 *. b) /. Constants.yn,
);
let z =
xyz_lab(
(0.0193339 *. r +. 0.1191920 *. g +. 0.9503041 *. b) /. Constants.zn,
);
(x, y, z);
};
let fromRGB = ((r, g, b, alpha)) => {
let (x, y, z) = rgb2xyz(r, g, b);
let l = 116. *. y -. 16.;
(l < 0. ? 0. : l, 500. *. (x -. y), 200. *. (y -. z), alpha);
};
let fromCssRGB = rgb => {
switch (rgb) {
| `rgb(r, g, b) => fromRGB((r, g, b, 1.))
| `rgba(r, g, b, a) => fromRGB((r, g, b, a))
| _ => raise(InvalidValue("Not an rgb value"))
};
};
@leostera
Copy link

leostera commented Apr 7, 2019

Do you need the catch all here? The signature should be automatically constrained to the two poly variants you are switching on.

@eldh
Copy link
Author

eldh commented Apr 7, 2019

If it's coming from bs-css it might have a different type, I think.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment