@texel/color 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +21 -0
- package/README.md +376 -0
- package/package.json +65 -0
- package/src/conversion_matrices.js +268 -0
- package/src/core.js +186 -0
- package/src/gamut.js +336 -0
- package/src/index.js +6 -0
- package/src/okhsl.js +345 -0
- package/src/spaces/a98-rgb.js +50 -0
- package/src/spaces/display-p3.js +28 -0
- package/src/spaces/oklab.js +70 -0
- package/src/spaces/prophoto-rgb.js +72 -0
- package/src/spaces/rec2020.js +47 -0
- package/src/spaces/srgb.js +29 -0
- package/src/spaces/util.js +44 -0
- package/src/spaces/xyz.js +44 -0
- package/src/spaces.js +44 -0
- package/src/util.js +119 -0
- package/test/almost-equal.js +15 -0
- package/test/banner.png +0 -0
- package/test/bench-colorjs.js +138 -0
- package/test/bench-node.js +51 -0
- package/test/bench-size.js +3 -0
- package/test/canvas-graph.js +210 -0
- package/test/logo.js +112 -0
- package/test/logo.png +0 -0
- package/test/profiles/DisplayP3.icc +0 -0
- package/test/test-colorjs.js +87 -0
- package/test/test.js +321 -0
- package/tools/__pycache__/calc_oklab_matrices.cpython-311.pyc +0 -0
- package/tools/calc_oklab_matrices.py +233 -0
- package/tools/print_matrices.py +509 -0
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
/** This file is auto-generated by tools/print_matrices.py */
|
|
2
|
+
|
|
3
|
+
// OKLab to LMS matrices
|
|
4
|
+
|
|
5
|
+
export const OKLab_to_LMS_M = [
|
|
6
|
+
[1.0, 0.3963377773761749, 0.2158037573099136],
|
|
7
|
+
[1.0, -0.1055613458156586, -0.0638541728258133],
|
|
8
|
+
[1.0, -0.0894841775298119, -1.2914855480194092],
|
|
9
|
+
];
|
|
10
|
+
|
|
11
|
+
export const LMS_to_OKLab_M = [
|
|
12
|
+
[0.210454268309314, 0.7936177747023054, -0.0040720430116193],
|
|
13
|
+
[1.9779985324311684, -2.42859224204858, 0.450593709617411],
|
|
14
|
+
[0.0259040424655478, 0.7827717124575296, -0.8086757549230774],
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
export const XYZ_to_LMS_M = [
|
|
18
|
+
[0.819022437996703, 0.3619062600528904, -0.1288737815209879],
|
|
19
|
+
[0.0329836539323885, 0.9292868615863434, 0.0361446663506424],
|
|
20
|
+
[0.0481771893596242, 0.2642395317527308, 0.6335478284694309],
|
|
21
|
+
];
|
|
22
|
+
|
|
23
|
+
export const LMS_to_XYZ_M = [
|
|
24
|
+
[1.2268798758459243, -0.5578149944602171, 0.2813910456659647],
|
|
25
|
+
[-0.0405757452148008, 1.112286803280317, -0.0717110580655164],
|
|
26
|
+
[-0.0763729366746601, -0.4214933324022432, 1.5869240198367816],
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
// linear_sRGB space
|
|
30
|
+
|
|
31
|
+
// linear_sRGB to XYZ (D65) matrices
|
|
32
|
+
|
|
33
|
+
export const linear_sRGB_to_XYZ_M = [
|
|
34
|
+
[0.4123907992659595, 0.35758433938387796, 0.1804807884018343],
|
|
35
|
+
[0.21263900587151036, 0.7151686787677559, 0.07219231536073371],
|
|
36
|
+
[0.01933081871559185, 0.11919477979462599, 0.9505321522496606],
|
|
37
|
+
];
|
|
38
|
+
|
|
39
|
+
export const XYZ_to_linear_sRGB_M = [
|
|
40
|
+
[3.2409699419045213, -1.5373831775700935, -0.4986107602930033],
|
|
41
|
+
[-0.9692436362808798, 1.8759675015077206, 0.04155505740717561],
|
|
42
|
+
[0.05563007969699361, -0.20397695888897657, 1.0569715142428786],
|
|
43
|
+
];
|
|
44
|
+
|
|
45
|
+
// linear_sRGB to LMS matrices
|
|
46
|
+
|
|
47
|
+
export const linear_sRGB_to_LMS_M = [
|
|
48
|
+
[0.4122214694707629, 0.5363325372617349, 0.051445993267502196],
|
|
49
|
+
[0.2119034958178251, 0.6806995506452345, 0.10739695353694051],
|
|
50
|
+
[0.08830245919005637, 0.2817188391361215, 0.6299787016738223],
|
|
51
|
+
];
|
|
52
|
+
|
|
53
|
+
export const LMS_to_linear_sRGB_M = [
|
|
54
|
+
[4.076741636075959, -3.307711539258062, 0.2309699031821041],
|
|
55
|
+
[-1.2684379732850313, 2.6097573492876878, -0.3413193760026569],
|
|
56
|
+
[-0.004196076138675526, -0.703418617935936, 1.7076146940746113],
|
|
57
|
+
];
|
|
58
|
+
|
|
59
|
+
// linear_sRGB coefficients for OKLab gamut approximation
|
|
60
|
+
|
|
61
|
+
export const OKLab_to_linear_sRGB_coefficients = [
|
|
62
|
+
[
|
|
63
|
+
[-1.8817030993265873, -0.8093650129914302],
|
|
64
|
+
[1.19086277, 1.76576728, 0.59662641, 0.75515197, 0.56771245],
|
|
65
|
+
],
|
|
66
|
+
[
|
|
67
|
+
[1.8144407988010998, -1.194452667805235],
|
|
68
|
+
[0.73956515, -0.45954404, 0.08285427, 0.12541073, -0.14503204],
|
|
69
|
+
],
|
|
70
|
+
[
|
|
71
|
+
[0.13110757611180954, 1.813339709266608],
|
|
72
|
+
[1.35733652, -0.00915799, -1.1513021, -0.50559606, 0.00692167],
|
|
73
|
+
],
|
|
74
|
+
];
|
|
75
|
+
|
|
76
|
+
// linear_DisplayP3 space
|
|
77
|
+
|
|
78
|
+
// linear_DisplayP3 to XYZ (D65) matrices
|
|
79
|
+
|
|
80
|
+
export const linear_DisplayP3_to_XYZ_M = [
|
|
81
|
+
[0.48657094864821626, 0.26566769316909294, 0.1982172852343625],
|
|
82
|
+
[0.22897456406974884, 0.6917385218365062, 0.079286914093745],
|
|
83
|
+
[0.0, 0.045113381858902575, 1.0439443689009757],
|
|
84
|
+
];
|
|
85
|
+
|
|
86
|
+
export const XYZ_to_linear_DisplayP3_M = [
|
|
87
|
+
[2.4934969119414245, -0.9313836179191236, -0.40271078445071684],
|
|
88
|
+
[-0.829488969561575, 1.7626640603183468, 0.02362468584194359],
|
|
89
|
+
[0.035845830243784335, -0.07617238926804171, 0.9568845240076873],
|
|
90
|
+
];
|
|
91
|
+
|
|
92
|
+
// linear_DisplayP3 to LMS matrices
|
|
93
|
+
|
|
94
|
+
export const linear_DisplayP3_to_LMS_M = [
|
|
95
|
+
[0.48137985274995443, 0.4621183710113181, 0.05650177623872757],
|
|
96
|
+
[0.22883194181124475, 0.6532168193835676, 0.11795123880518778],
|
|
97
|
+
[0.08394575232299319, 0.22416527097756642, 0.6918889766994405],
|
|
98
|
+
];
|
|
99
|
+
|
|
100
|
+
export const LMS_to_linear_DisplayP3_M = [
|
|
101
|
+
[3.1277689713618737, -2.2571357625916395, 0.1293667912297651],
|
|
102
|
+
[-1.091009018437798, 2.413331710306923, -0.3223226918691248],
|
|
103
|
+
[-0.02601080193857041, -0.5080413317041669, 1.5340521336427373],
|
|
104
|
+
];
|
|
105
|
+
|
|
106
|
+
// linear_DisplayP3 coefficients for OKLab gamut approximation
|
|
107
|
+
|
|
108
|
+
export const OKLab_to_linear_DisplayP3_coefficients = [
|
|
109
|
+
[
|
|
110
|
+
[-1.772343927512981, -0.8207587433674072],
|
|
111
|
+
[
|
|
112
|
+
1.1941401817282744, 1.7629811997119493, 0.5958599382477117,
|
|
113
|
+
0.7575999740542505, 0.5681684967813678,
|
|
114
|
+
],
|
|
115
|
+
],
|
|
116
|
+
[
|
|
117
|
+
[1.8031987175305495, -1.1932813966558915],
|
|
118
|
+
[
|
|
119
|
+
0.7395668192259771, -0.45954279991477065, 0.08285308768965816,
|
|
120
|
+
0.1254116495192955, -0.14503290744357106,
|
|
121
|
+
],
|
|
122
|
+
],
|
|
123
|
+
[
|
|
124
|
+
[0.08970487824467532, 1.9032774657416107],
|
|
125
|
+
[
|
|
126
|
+
1.3650944117698118, -0.013962295571040945, -1.1452305089885595,
|
|
127
|
+
-0.5025987876721942, 0.003174713114731378,
|
|
128
|
+
],
|
|
129
|
+
],
|
|
130
|
+
];
|
|
131
|
+
|
|
132
|
+
// linear_Rec2020 space
|
|
133
|
+
|
|
134
|
+
// linear_Rec2020 to XYZ (D65) matrices
|
|
135
|
+
|
|
136
|
+
export const linear_Rec2020_to_XYZ_M = [
|
|
137
|
+
[0.6369580483012913, 0.14461690358620838, 0.16888097516417205],
|
|
138
|
+
[0.26270021201126703, 0.677998071518871, 0.059301716469861945],
|
|
139
|
+
[0.0, 0.028072693049087508, 1.0609850577107909],
|
|
140
|
+
];
|
|
141
|
+
|
|
142
|
+
export const XYZ_to_linear_Rec2020_M = [
|
|
143
|
+
[1.7166511879712676, -0.3556707837763924, -0.2533662813736598],
|
|
144
|
+
[-0.666684351832489, 1.616481236634939, 0.01576854581391113],
|
|
145
|
+
[0.017639857445310915, -0.042770613257808655, 0.942103121235474],
|
|
146
|
+
];
|
|
147
|
+
|
|
148
|
+
// linear_Rec2020 to LMS matrices
|
|
149
|
+
|
|
150
|
+
export const linear_Rec2020_to_LMS_M = [
|
|
151
|
+
[0.6167557848654444, 0.3601984012264634, 0.023045813908092266],
|
|
152
|
+
[0.26513305939263676, 0.6358393720678492, 0.09902756853951414],
|
|
153
|
+
[0.10010262952034828, 0.20390652261661452, 0.6959908478630372],
|
|
154
|
+
];
|
|
155
|
+
|
|
156
|
+
export const LMS_to_linear_Rec2020_M = [
|
|
157
|
+
[2.1399067304346513, -1.246389493760618, 0.10648276332596689],
|
|
158
|
+
[-0.8847358357577675, 2.1632309383612007, -0.27849510260343363],
|
|
159
|
+
[-0.04857374640044396, -0.45450314971409633, 1.5030768961145404],
|
|
160
|
+
];
|
|
161
|
+
|
|
162
|
+
// linear_Rec2020 coefficients for OKLab gamut approximation
|
|
163
|
+
|
|
164
|
+
export const OKLab_to_linear_Rec2020_coefficients = [
|
|
165
|
+
[
|
|
166
|
+
[-1.3683489920695084, -0.4666477292401165],
|
|
167
|
+
[
|
|
168
|
+
1.2572444967331895, 1.715801757890085, 0.5648732965817461,
|
|
169
|
+
0.7950731608663721, 0.5871636339819248,
|
|
170
|
+
],
|
|
171
|
+
],
|
|
172
|
+
[
|
|
173
|
+
[2.0115079619342833, -2.0379095965347],
|
|
174
|
+
[
|
|
175
|
+
0.7408775472462948, -0.4586732968366297, 0.081829765825816,
|
|
176
|
+
0.12598704592707602, -0.14570327455009213,
|
|
177
|
+
],
|
|
178
|
+
],
|
|
179
|
+
[
|
|
180
|
+
[0.06454093208719812, 2.2970933629671704],
|
|
181
|
+
[
|
|
182
|
+
1.3692048443658147, -0.016466673486950332, -1.141978697647362,
|
|
183
|
+
-0.5010647675396565, 0.001199059854416378,
|
|
184
|
+
],
|
|
185
|
+
],
|
|
186
|
+
];
|
|
187
|
+
|
|
188
|
+
// linear_A98RGB space
|
|
189
|
+
|
|
190
|
+
// linear_A98RGB to XYZ (D65) matrices
|
|
191
|
+
|
|
192
|
+
export const linear_A98RGB_to_XYZ_M = [
|
|
193
|
+
[0.5766690429101308, 0.18555823790654627, 0.18822864623499472],
|
|
194
|
+
[0.29734497525053616, 0.627363566255466, 0.07529145849399789],
|
|
195
|
+
[0.027031361386412378, 0.07068885253582714, 0.9913375368376389],
|
|
196
|
+
];
|
|
197
|
+
|
|
198
|
+
export const XYZ_to_linear_A98RGB_M = [
|
|
199
|
+
[2.041587903810746, -0.5650069742788596, -0.3447313507783295],
|
|
200
|
+
[-0.9692436362808798, 1.8759675015077206, 0.04155505740717561],
|
|
201
|
+
[0.013444280632031024, -0.11836239223101824, 1.0151749943912054],
|
|
202
|
+
];
|
|
203
|
+
|
|
204
|
+
// linear_A98RGB to LMS matrices
|
|
205
|
+
|
|
206
|
+
export const linear_A98RGB_to_LMS_M = [
|
|
207
|
+
[0.5764322596183941, 0.36991322261987963, 0.053654517761726306],
|
|
208
|
+
[0.29631647054222465, 0.5916761332521886, 0.11200739620558692],
|
|
209
|
+
[0.12347825101427762, 0.21949869837199862, 0.6570230506137239],
|
|
210
|
+
];
|
|
211
|
+
|
|
212
|
+
export const LMS_to_linear_A98RGB_M = [
|
|
213
|
+
[2.554036838611556, -1.6219761806828696, 0.06793934207131354],
|
|
214
|
+
[-1.2684379732850315, 2.6097573492876887, -0.3413193760026572],
|
|
215
|
+
[-0.0562347359374939, -0.5670418395669057, 1.6232765755043994],
|
|
216
|
+
];
|
|
217
|
+
|
|
218
|
+
// linear_A98RGB coefficients for OKLab gamut approximation
|
|
219
|
+
|
|
220
|
+
export const OKLab_to_linear_A98RGB_coefficients = [
|
|
221
|
+
[
|
|
222
|
+
[-1.591695414425798, -0.8395798483264373],
|
|
223
|
+
[
|
|
224
|
+
1.215470987494823, 1.7445423850069868, 0.5911924333317312,
|
|
225
|
+
0.774055974979685, 0.5710471573194968,
|
|
226
|
+
],
|
|
227
|
+
],
|
|
228
|
+
[
|
|
229
|
+
[1.8144407988011015, -1.1944526678052378],
|
|
230
|
+
[0.73956515, -0.45954404, 0.08285427, 0.12541073, -0.14503204],
|
|
231
|
+
],
|
|
232
|
+
[
|
|
233
|
+
[-0.014529428934082126, 2.073564997814519],
|
|
234
|
+
[1.35733652, -0.00915799, -1.1513021, -0.50559606, 0.00692167],
|
|
235
|
+
],
|
|
236
|
+
];
|
|
237
|
+
|
|
238
|
+
// linear_ProPhotoRGB space
|
|
239
|
+
|
|
240
|
+
// linear_ProPhotoRGB to XYZ (D50) matrices
|
|
241
|
+
|
|
242
|
+
export const linear_ProPhotoRGB_to_XYZ_M = [
|
|
243
|
+
[0.7977666449006423, 0.13518129740053308, 0.0313477341283922],
|
|
244
|
+
[0.2880748288194013, 0.711835234241873, 8.993693872564e-5],
|
|
245
|
+
[0.0, 0.0, 0.8251046025104602],
|
|
246
|
+
];
|
|
247
|
+
|
|
248
|
+
export const XYZ_to_linear_ProPhotoRGB_M = [
|
|
249
|
+
[1.3457868816471583, -0.25557208737979464, -0.05110186497554526],
|
|
250
|
+
[-0.5446307051249019, 1.5082477428451468, 0.02052744743642139],
|
|
251
|
+
[0.0, 0.0, 1.2119675456389452],
|
|
252
|
+
];
|
|
253
|
+
|
|
254
|
+
// linear_ProPhotoRGB to LMS matrices
|
|
255
|
+
|
|
256
|
+
export const linear_ProPhotoRGB_to_LMS_M = [
|
|
257
|
+
[0.7247750802792337, 0.3523542757724655, -0.07712935605169913],
|
|
258
|
+
[0.2967127550253245, 0.6720629323218004, 0.031224312652875095],
|
|
259
|
+
[0.13744833201856482, 0.23349936027726578, 0.6290523077041692],
|
|
260
|
+
];
|
|
261
|
+
|
|
262
|
+
export const LMS_to_linear_ProPhotoRGB_M = [
|
|
263
|
+
[1.7409200224411467, -1.004224451144535, 0.26330442870338805],
|
|
264
|
+
[-0.7641128642092264, 1.9548345194982568, -0.19072165528903018],
|
|
265
|
+
[-0.09675934345097237, -0.5061957965480232, 1.602955139998996],
|
|
266
|
+
];
|
|
267
|
+
|
|
268
|
+
// linear_ProPhotoRGB does not yet support OKLab gamut approximation
|
package/src/core.js
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { floatToByte, vec3 } from "./util.js";
|
|
2
|
+
import { LMS_to_OKLab_M, OKLab_to_LMS_M } from "./conversion_matrices.js";
|
|
3
|
+
import { XYZ } from "./spaces.js";
|
|
4
|
+
|
|
5
|
+
const tmp3 = vec3();
|
|
6
|
+
|
|
7
|
+
const cubed3 = (lms) => {
|
|
8
|
+
const l = lms[0],
|
|
9
|
+
m = lms[1],
|
|
10
|
+
s = lms[2];
|
|
11
|
+
lms[0] = l * l * l;
|
|
12
|
+
lms[1] = m * m * m;
|
|
13
|
+
lms[2] = s * s * s;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const cbrt3 = (lms) => {
|
|
17
|
+
lms[0] = Math.cbrt(lms[0]);
|
|
18
|
+
lms[1] = Math.cbrt(lms[1]);
|
|
19
|
+
lms[2] = Math.cbrt(lms[2]);
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const dot3 = (a, b) => a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
|
|
23
|
+
|
|
24
|
+
export const OKLab_to = (OKLab, LMS_to_output, out = vec3()) => {
|
|
25
|
+
transform(OKLab, OKLab_to_LMS_M, out);
|
|
26
|
+
cubed3(out);
|
|
27
|
+
return transform(out, LMS_to_output, out);
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export const OKLab_from = (input, input_to_LMS, out = vec3()) => {
|
|
31
|
+
transform(input, input_to_LMS, out);
|
|
32
|
+
cbrt3(out);
|
|
33
|
+
return transform(out, LMS_to_OKLab_M, out);
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export const transform = (input, matrix, out = vec3()) => {
|
|
37
|
+
const x = dot3(input, matrix[0]);
|
|
38
|
+
const y = dot3(input, matrix[1]);
|
|
39
|
+
const z = dot3(input, matrix[2]);
|
|
40
|
+
out[0] = x;
|
|
41
|
+
out[1] = y;
|
|
42
|
+
out[2] = z;
|
|
43
|
+
return out;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const vec3Copy = (input, output) => {
|
|
47
|
+
output[0] = input[0];
|
|
48
|
+
output[1] = input[1];
|
|
49
|
+
output[2] = input[2];
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export const serialize = (input, inputSpace, outputSpace = inputSpace) => {
|
|
53
|
+
if (!inputSpace) throw new Error(`must specify an input space`);
|
|
54
|
+
if (inputSpace !== outputSpace) {
|
|
55
|
+
convert(input, inputSpace, outputSpace, tmp3);
|
|
56
|
+
} else {
|
|
57
|
+
vec3Copy(input, tmp3);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const id = outputSpace.id;
|
|
61
|
+
if (id == "srgb") {
|
|
62
|
+
const r = floatToByte(tmp3[0]);
|
|
63
|
+
const g = floatToByte(tmp3[1]);
|
|
64
|
+
const b = floatToByte(tmp3[2]);
|
|
65
|
+
return `rgb(${r}, ${g}, ${b})`;
|
|
66
|
+
} else if (id == "oklab" || id == "oklch") {
|
|
67
|
+
return `${id}(${tmp3[0]} ${tmp3[1]} ${tmp3[2]})`;
|
|
68
|
+
} else {
|
|
69
|
+
return `color(${id} ${tmp3[0]} ${tmp3[1]} ${tmp3[2]})`;
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export const convert = (input, fromSpace, toSpace, out = vec3()) => {
|
|
74
|
+
// place into output
|
|
75
|
+
vec3Copy(input, out);
|
|
76
|
+
|
|
77
|
+
if (!fromSpace) throw new Error(`must specify a fromSpace`);
|
|
78
|
+
if (!toSpace) throw new Error(`must specify a toSpace`);
|
|
79
|
+
|
|
80
|
+
// special case: no conversion needed
|
|
81
|
+
if (fromSpace == toSpace) {
|
|
82
|
+
return out;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// e.g. convert OKLCH -> OKLab or sRGB -> sRGBLinear
|
|
86
|
+
if (fromSpace.base) {
|
|
87
|
+
out = fromSpace.toBase(out, out);
|
|
88
|
+
fromSpace = fromSpace.base;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// now we have the base space like sRGBLinear or XYZ
|
|
92
|
+
let fromBaseSpace = fromSpace;
|
|
93
|
+
|
|
94
|
+
// and the base we want to get to, linear, OKLab, XYZ etc...
|
|
95
|
+
let toBaseSpace = toSpace.base ?? toSpace;
|
|
96
|
+
|
|
97
|
+
if (fromBaseSpace === toBaseSpace) {
|
|
98
|
+
// do nothing, spaces are the same
|
|
99
|
+
} else {
|
|
100
|
+
// [from space] -> (adaptation) -> [xyz] -> (adaptation) -> [to space]
|
|
101
|
+
|
|
102
|
+
// e.g. sRGB to ProPhotoLinear
|
|
103
|
+
// sRGB -> sRGBLinear -> XYZ(D65) -> XYZD65ToD50 -> ProPhotoLinear
|
|
104
|
+
// ProPhotoLinear -> XYZ(D50) -> XYZD50ToD65 -> sRGBLinear -> sRGB
|
|
105
|
+
|
|
106
|
+
let xyzIn = fromBaseSpace.id === "xyz";
|
|
107
|
+
let xyzOut = toBaseSpace.id === "xyz";
|
|
108
|
+
let throughXYZ = false;
|
|
109
|
+
let outputOklab = false;
|
|
110
|
+
|
|
111
|
+
// spaces are different
|
|
112
|
+
// check if we have a fast path
|
|
113
|
+
// this isn't supported for d50-based whitepoints
|
|
114
|
+
if (fromBaseSpace.id === "oklab") {
|
|
115
|
+
let mat = toBaseSpace.fromLMS_M;
|
|
116
|
+
if (!mat) {
|
|
117
|
+
// space doesn't support direct
|
|
118
|
+
// let's convert OKLab to XYZ and then use that
|
|
119
|
+
mat = XYZ.fromLMS_M;
|
|
120
|
+
throughXYZ = true;
|
|
121
|
+
xyzIn = true;
|
|
122
|
+
}
|
|
123
|
+
out = OKLab_to(out, mat, out);
|
|
124
|
+
} else if (toBaseSpace.id === "oklab") {
|
|
125
|
+
let mat = fromBaseSpace.toLMS_M;
|
|
126
|
+
if (!mat) {
|
|
127
|
+
// space doesn't support direct
|
|
128
|
+
throughXYZ = true;
|
|
129
|
+
outputOklab = true;
|
|
130
|
+
} else {
|
|
131
|
+
// direct from space to oklab
|
|
132
|
+
out = OKLab_from(out, mat, out);
|
|
133
|
+
}
|
|
134
|
+
} else {
|
|
135
|
+
throughXYZ = true;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (throughXYZ) {
|
|
139
|
+
// First, convert to XYZ if we need to
|
|
140
|
+
if (!xyzIn) {
|
|
141
|
+
if (!fromBaseSpace.toXYZ_M)
|
|
142
|
+
throw new Error(`no toXYZ_M on ${fromBaseSpace.id}`);
|
|
143
|
+
out = transform(out, fromBaseSpace.toXYZ_M, out);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Then, adapt D50 <-> D65 if we need to
|
|
147
|
+
if (fromBaseSpace.adapt) {
|
|
148
|
+
out = transform(out, fromBaseSpace.adapt.to, out);
|
|
149
|
+
} else if (toBaseSpace.adapt) {
|
|
150
|
+
out = transform(out, toBaseSpace.adapt.from, out);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Now, convert XYZ to target if we need to
|
|
154
|
+
if (!xyzOut) {
|
|
155
|
+
if (outputOklab) {
|
|
156
|
+
out = OKLab_from(out, XYZ.toLMS_M, out);
|
|
157
|
+
} else {
|
|
158
|
+
if (!toBaseSpace.fromXYZ_M)
|
|
159
|
+
throw new Error(`no fromXYZ_M on ${toBaseSpace.id}`);
|
|
160
|
+
out = transform(out, toBaseSpace.fromXYZ_M, out);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Now do the final transformation to the target space
|
|
167
|
+
// e.g. OKLab -> OKLCH or sRGBLinear -> sRGB
|
|
168
|
+
if (toBaseSpace !== toSpace) {
|
|
169
|
+
if (toSpace.fromBase) {
|
|
170
|
+
out = toSpace.fromBase(out, out);
|
|
171
|
+
} else {
|
|
172
|
+
throw new Error(`could not transform ${toBaseSpace.id} to ${toSpace.id}`);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return out;
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
// Calculate deltaE OK
|
|
180
|
+
// simple root sum of squares
|
|
181
|
+
export const deltaEOK = (oklab1, oklab2) => {
|
|
182
|
+
let dL = oklab1[0] - oklab2[0];
|
|
183
|
+
let da = oklab1[1] - oklab2[1];
|
|
184
|
+
let db = oklab1[2] - oklab2[2];
|
|
185
|
+
return Math.sqrt(dL * dL + da * da + db * db);
|
|
186
|
+
};
|