Skip to content

Instantly share code, notes, and snippets.

@zazaulola
Last active July 30, 2024 03:21
Show Gist options
  • Save zazaulola/24dba8090bf1a706905e5c0a99bf2410 to your computer and use it in GitHub Desktop.
Save zazaulola/24dba8090bf1a706905e5c0a99bf2410 to your computer and use it in GitHub Desktop.
True color difference formula is calculated using OKLab color space
const color_distance = ([ L1, a1, b1 ], [ L2, a2, b2 ] ) => Math.hypot( L1 - L2, a1 - a2, b1 - b2 );
const linear = x => x >= 0.04045 ? ((x + 0.055) / (1 + 0.055)) ** 2.4 : x / 12.92;
const gamma = x => x >= 0.0031308 ? 1.055 * x ** (1 / 2.4) - 0.055 : 12.92 * x;
const clamp = x => Math.min ( 255, Math.max ( 0, x ) );
const multiply = (a, b) =>
[...a].map((_, r) =>
[...b[0]].map((_, c) =>
a[r].reduce((s,_,i) =>
s + a[r][i] * b[i][c], 0)));
const rgb_to_oklab = (r, g, b) =>
multiply([
[ +0.2104542553, +0.7936177850, -0.0040720468],
[ +1.9779984951, -2.4285922050, +0.4505937099],
[ +0.0259040371, +0.7827717662, -0.8086757660]
],
multiply([
[ 0.4121656120, 0.5362752080, 0.0514575653 ],
[ 0.2118591070, 0.6807189584, 0.1074065790 ],
[ 0.0883097947, 0.2818474174, 0.6302613616 ]
],
[r, g, b] .map(x => x / 255)
.map(linear)
.map(x => [x])
) .map(([x]) => [ x ** (1/3) ])
) .flat();
const oklab_to_rgb = (L, a, b) =>
multiply( [
[ +4.0767245293, -3.3072168827, +0.2307590544 ],
[ -1.2681437731, +2.6093323231, -0.3411344290 ],
[ -0.0041119885, -0.7034763098, +1.7068625689 ]
],
multiply( [
[ +1, +0.3963377774, +0.2158037573 ],
[ +1, -0.1055613458, -0.0638541728 ],
[ +1, -0.0894841775, -1.2914855480 ]
],
[ [ L ],
[ a ],
[ b ] ]
) .map( ([x]) => [ x ** 3 ])
) .flat()
.map(gamma)
.map(x => x * 255)
.map(clamp)
.map(Math.round);
const oklch = (L, C, h) => {
const H = 2 * Math.PI * (h / 360);
const a = C * Math.cos(H)
const b = C * Math.sin(H)
return oklab_to_rgb(L, a, b)
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment