Skip to content

Commit e43d12a

Browse files
committed
Updated Oklab conversion matrices to match css-color-4, fixes #237
1 parent 4ecfbf3 commit e43d12a

File tree

8 files changed

+102
-56
lines changed

8 files changed

+102
-56
lines changed

src/oklab/convertLrgbToOklab.js

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,31 @@ const convertLrgbToOklab = ({ r, g, b, alpha }) => {
22
if (r === undefined) r = 0;
33
if (g === undefined) g = 0;
44
if (b === undefined) b = 0;
5+
56
let L = Math.cbrt(
6-
0.41222147079999993 * r + 0.5363325363 * g + 0.0514459929 * b
7+
0.412221469470763 * r + 0.5363325372617348 * g + 0.0514459932675022 * b
78
);
89
let M = Math.cbrt(
9-
0.2119034981999999 * r + 0.6806995450999999 * g + 0.1073969566 * b
10+
0.2119034958178252 * r + 0.6806995506452344 * g + 0.1073969535369406 * b
1011
);
1112
let S = Math.cbrt(
12-
0.08830246189999998 * r + 0.2817188376 * g + 0.6299787005000002 * b
13+
0.0883024591900564 * r + 0.2817188391361215 * g + 0.6299787016738222 * b
1314
);
1415

1516
let res = {
1617
mode: 'oklab',
17-
l: 0.2104542553 * L + 0.793617785 * M - 0.0040720468 * S,
18-
a: 1.9779984951 * L - 2.428592205 * M + 0.4505937099 * S,
19-
b: 0.0259040371 * L + 0.7827717662 * M - 0.808675766 * S
18+
l:
19+
0.210454268309314 * L +
20+
0.7936177747023054 * M -
21+
0.0040720430116193 * S,
22+
a:
23+
1.9779985324311684 * L -
24+
2.4285922420485799 * M +
25+
0.450593709617411 * S,
26+
b:
27+
0.0259040424655478 * L +
28+
0.7827717124575296 * M -
29+
0.8086757549230774 * S
2030
};
2131

2232
if (alpha !== undefined) {

src/oklab/convertOklabToLrgb.js

Lines changed: 13 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,39 +2,25 @@ const convertOklabToLrgb = ({ l, a, b, alpha }) => {
22
if (l === undefined) l = 0;
33
if (a === undefined) a = 0;
44
if (b === undefined) b = 0;
5-
let L = Math.pow(
6-
l * 0.99999999845051981432 +
7-
0.39633779217376785678 * a +
8-
0.21580375806075880339 * b,
9-
3
10-
);
11-
let M = Math.pow(
12-
l * 1.0000000088817607767 -
13-
0.1055613423236563494 * a -
14-
0.063854174771705903402 * b,
15-
3
16-
);
17-
let S = Math.pow(
18-
l * 1.0000000546724109177 -
19-
0.089484182094965759684 * a -
20-
1.2914855378640917399 * b,
21-
3
22-
);
5+
6+
let L = Math.pow(l + 0.3963377773761749 * a + 0.2158037573099136 * b, 3);
7+
let M = Math.pow(l - 0.1055613458156586 * a - 0.0638541728258133 * b, 3);
8+
let S = Math.pow(l - 0.0894841775298119 * a - 1.2914855480194092 * b, 3);
239

2410
let res = {
2511
mode: 'lrgb',
2612
r:
27-
+4.076741661347994 * L -
28-
3.307711590408193 * M +
29-
0.230969928729428 * S,
13+
4.0767416360759574 * L -
14+
3.3077115392580616 * M +
15+
0.2309699031821044 * S,
3016
g:
31-
-1.2684380040921763 * L +
32-
2.6097574006633715 * M -
33-
0.3413193963102197 * S,
17+
-1.2684379732850317 * L +
18+
2.6097573492876887 * M -
19+
0.3413193760026573 * S,
3420
b:
35-
-0.004196086541837188 * L -
36-
0.7034186144594493 * M +
37-
1.7076147009309444 * S
21+
-0.0041960761386756 * L -
22+
0.7034186179359362 * M +
23+
1.7076146940746117 * S
3824
};
3925

4026
if (alpha !== undefined) {

test/clamp.test.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -172,12 +172,12 @@ test('toGamut()', t => {
172172
);
173173
assert.equal(
174174
formatCss(toGamut('rgb')('color(--lch-d65 100 0 180)')),
175-
'color(srgb 0.9999999999999968 1.0000000000000016 0.9999999999999986)',
175+
'color(srgb 1 1 1)',
176176
'chroma = 0'
177177
);
178178
assert.equal(
179179
formatCss(toGamut('p3')('lch(80% 150 60)')),
180-
'color(display-p3 0.9999999999999994 0.6969234154991887 0.5084794582132421)',
180+
'color(display-p3 0.9999999999999999 0.6969234114981073 0.5084794107705369)',
181181
'api docs example'
182182
);
183183

@@ -257,9 +257,9 @@ test('missing components', t => {
257257
toGamut()('color(srgb 1.1 none none)'),
258258
{
259259
mode: 'rgb',
260-
r: 0.9999999999999994,
261-
g: 0.24780803212382269,
262-
b: 0.18935507566673854
260+
r: 0.9999999999999997,
261+
g: 0.2478080277701502,
262+
b: 0.18935505411180673
263263
},
264264
'toGamut(), rgb color'
265265
);

test/okhsl.test.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,18 @@ import { okhsl, rgb, formatHex, formatCss } from '../src/index.js';
55
test('rgb → okhsl', t => {
66
assert.equal(
77
formatCss(okhsl('red')),
8-
'color(--okhsl 29.2338851923426 1.0000000001434 0.5680846525040861)',
8+
'color(--okhsl 29.233880279627854 1.0000000007111225 0.5680846563197034)',
99
'red'
1010
);
1111
assert.equal(
1212
formatCss(okhsl('white')),
13-
'color(--okhsl none 0 0.9999999923961895)',
13+
'color(--okhsl none 0 1.0000000000000002)',
1414
'white'
1515
);
1616
assert.equal(formatCss(okhsl('black')), 'color(--okhsl none 0 0)', 'black');
1717
assert.equal(
1818
formatCss(okhsl('#3333')),
19-
'color(--okhsl none 0 0.2209950715093747 / 0.2)',
19+
'color(--okhsl none 0 0.2209950737733088 / 0.2)',
2020
'#333'
2121
);
2222
});

test/okhsv.test.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,18 @@ import { okhsv, rgb, formatHex, formatCss } from '../src/index.js';
55
test('rgb → okhsv', t => {
66
assert.equal(
77
formatCss(okhsv('red')),
8-
'color(--okhsv 29.2338851923426 0.9995219692256307 0.9999999999999997)',
8+
'color(--okhsv 29.233880279627854 0.9995219665357181 0.9999999999999998)',
99
'red'
1010
);
1111
assert.equal(
1212
formatCss(okhsv('white')),
13-
'color(--okhsv none 0 1.00000009386827)',
13+
'color(--okhsv none 0 1.0000000000000004)',
1414
'white'
1515
);
1616
assert.equal(formatCss(okhsv('black')), 'color(--okhsv none 0 0)', 'black');
1717
assert.equal(
1818
formatCss(okhsv('#3333')),
19-
'color(--okhsv none 0 0.220995101721347 / 0.2)',
19+
'color(--okhsv none 0 0.22099507377330885 / 0.2)',
2020
'#333'
2121
);
2222
});

test/oklab.test.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,14 @@ import {
1111
test('rgb → oklab', t => {
1212
assert.deepEqual(
1313
oklab('white'),
14-
{ mode: 'oklab', l: 0.999999993473546, a: 0, b: 0 },
14+
{ mode: 'oklab', l: 1.0000000000000002, a: 0, b: 0 },
1515
'white'
1616
);
1717

1818
// Tests that achromatic RGB colors get a = b = 0 in OKLab
1919
assert.deepEqual(
2020
oklab('#111'),
21-
{ mode: 'oklab', l: 0.1776377719172259, a: 0, b: 0 },
21+
{ mode: 'oklab', l: 0.17763777307657064, a: 0, b: 0 },
2222
'#111'
2323
);
2424

@@ -31,9 +31,9 @@ test('rgb → oklab', t => {
3131
oklab('red'),
3232
{
3333
mode: 'oklab',
34-
l: 0.6279553606145515,
35-
a: 0.22486306106597417,
36-
b: 0.12584629853073503
34+
l: 0.6279553639214311,
35+
a: 0.22486306842627443,
36+
b: 0.12584627733058495
3737
},
3838
'red'
3939
);

test/oklch.test.js

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,33 @@
11
import test from 'node:test';
22
import assert from 'node:assert';
3-
import { oklch, formatCss, useParser, removeParser } from '../src/index.js';
3+
import {
4+
rgb,
5+
oklch,
6+
formatCss,
7+
useParser,
8+
removeParser,
9+
displayable
10+
} from '../src/index.js';
411

512
test('oklch', t => {
613
assert.deepEqual(
714
oklch('white'),
8-
{ mode: 'oklch', l: 0.999999993473546, c: 0 },
15+
{ mode: 'oklch', l: 1.0000000000000002, c: 0 },
916
'white'
1017
);
1118
assert.deepEqual(
1219
oklch('#111'),
13-
{ mode: 'oklch', l: 0.1776377719172259, c: 0 },
20+
{ mode: 'oklch', l: 0.17763777307657064, c: 0 },
1421
'#111'
1522
);
1623
assert.deepEqual(oklch('black'), { mode: 'oklch', l: 0, c: 0 }, 'black');
1724
assert.deepEqual(
1825
oklch('red'),
1926
{
2027
mode: 'oklch',
21-
l: 0.6279553606145515,
22-
c: 0.25768330773615683,
23-
h: 29.2338851923426
28+
l: 0.6279553639214311,
29+
c: 0.2576833038053608,
30+
h: 29.233880279627854
2431
},
2532
'red'
2633
);
@@ -99,6 +106,16 @@ test('formatCss', t => {
99106
);
100107
assert.equal(
101108
formatCss(oklch('#ffffff00')),
102-
'oklch(0.999999993473546 0 none / 0)'
109+
'oklch(1.0000000000000002 0 none / 0)'
103110
);
104111
});
112+
113+
test('Issue #255', t => {
114+
assert.deepEqual(rgb(oklch('tomato')), {
115+
mode: 'rgb',
116+
r: 0.9999999999999997,
117+
g: 0.38823529411764784,
118+
b: 0.2784313725490196
119+
});
120+
assert.ok(displayable(oklch('tomato')));
121+
});

tools/math/oklab-matrices.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import numpy as np;
2+
3+
np.set_printoptions(precision=16, sign='-', floatmode='fixed');
4+
5+
# LRGBtoXYZ65 = np.array([
6+
# [ 0.4123907992659593, 0.357584339383878, 0.1804807884018343 ],
7+
# [ 0.2126390058715102, 0.715168678767756, 0.0721923153607337 ],
8+
# [ 0.0193308187155918, 0.119194779794626, 0.9505321522496607]
9+
# ]);
10+
11+
LRGBtoXYZ65 = np.array([
12+
[ 506752 / 1228815, 87881 / 245763, 12673 / 70218 ],
13+
[ 87098 / 409605, 175762 / 245763, 12673 / 175545 ],
14+
[ 7918 / 409605, 87881 / 737289, 1001167 / 1053270 ],
15+
]);
16+
17+
XYZ65toLMS = np.array([
18+
[ 0.8190224379967030, 0.3619062600528904, -0.1288737815209879 ],
19+
[ 0.0329836539323885, 0.9292868615863434, 0.0361446663506424 ],
20+
[ 0.0481771893596242, 0.2642395317527308, 0.6335478284694309 ]
21+
]);
22+
23+
LMStoOKLab = np.array([
24+
[ 0.2104542683093140, 0.7936177747023054, -0.0040720430116193 ],
25+
[ 1.9779985324311684, -2.4285922420485799, 0.4505937096174110 ],
26+
[ 0.0259040424655478, 0.7827717124575296, -0.8086757549230774 ]
27+
]);
28+
29+
C = np.matmul(XYZ65toLMS, LRGBtoXYZ65);
30+
Cinv = np.linalg.inv(C);
31+
32+
print(C);
33+
print(Cinv);

0 commit comments

Comments
 (0)