color-value-tools 1.2.0 → 1.2.2
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/README.md +18 -0
- package/dist/cjs/a11y.d.ts +40 -0
- package/dist/cjs/a11y.js +253 -0
- package/dist/cjs/cache.d.ts +9 -0
- package/dist/cjs/cache.js +38 -0
- package/dist/cjs/convert/format.d.ts +3 -0
- package/dist/cjs/convert/format.js +42 -0
- package/dist/cjs/convert/index.d.ts +2 -0
- package/dist/cjs/convert/index.js +18 -0
- package/dist/cjs/convert/spaces.d.ts +189 -0
- package/dist/cjs/convert/spaces.js +556 -0
- package/dist/cjs/index.d.ts +6 -397
- package/dist/cjs/index.js +20 -1450
- package/dist/cjs/internal/named-colors.d.ts +1 -0
- package/dist/cjs/internal/named-colors.js +165 -0
- package/dist/cjs/internal/transfer.d.ts +2 -0
- package/dist/cjs/internal/transfer.js +12 -0
- package/dist/cjs/manipulate.d.ts +15 -0
- package/dist/cjs/manipulate.js +223 -0
- package/dist/cjs/palette.d.ts +40 -0
- package/dist/cjs/palette.js +164 -0
- package/dist/cjs/parse.d.ts +102 -0
- package/dist/cjs/parse.js +257 -0
- package/dist/cli/{bin/cli.js → cli.js} +28 -26
- package/dist/esm/a11y.d.ts +40 -0
- package/dist/esm/a11y.js +237 -0
- package/dist/esm/cache.d.ts +9 -0
- package/dist/esm/cache.js +31 -0
- package/dist/esm/convert/format.d.ts +3 -0
- package/dist/esm/convert/format.js +37 -0
- package/dist/esm/convert/index.d.ts +2 -0
- package/dist/esm/convert/index.js +2 -0
- package/dist/esm/convert/spaces.d.ts +189 -0
- package/dist/esm/convert/spaces.js +520 -0
- package/dist/esm/index.d.ts +6 -0
- package/dist/esm/index.js +6 -1352
- package/dist/esm/internal/named-colors.d.ts +1 -0
- package/dist/esm/internal/named-colors.js +162 -0
- package/dist/esm/internal/transfer.d.ts +2 -0
- package/dist/esm/internal/transfer.js +8 -0
- package/dist/esm/manipulate.d.ts +15 -0
- package/dist/esm/manipulate.js +210 -0
- package/dist/esm/package.json +3 -1
- package/dist/esm/palette.d.ts +40 -0
- package/dist/esm/palette.js +145 -0
- package/dist/esm/parse.d.ts +102 -0
- package/dist/esm/parse.js +241 -0
- package/package.json +100 -8
- package/dist/cli/src/index.js +0 -1452
|
@@ -0,0 +1,556 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.rgbToDisplayP3 = rgbToDisplayP3;
|
|
4
|
+
exports.displayP3ToRgb = displayP3ToRgb;
|
|
5
|
+
exports.shortHexToRgba = shortHexToRgba;
|
|
6
|
+
exports.normalizeHex = normalizeHex;
|
|
7
|
+
exports.hexToRgb = hexToRgb;
|
|
8
|
+
exports.hexToRgba = hexToRgba;
|
|
9
|
+
exports.hexToHsl = hexToHsl;
|
|
10
|
+
exports.hslToHex = hslToHex;
|
|
11
|
+
exports.rgbToHex = rgbToHex;
|
|
12
|
+
exports.rgbaToHex = rgbaToHex;
|
|
13
|
+
exports.rgbToRgbaString = rgbToRgbaString;
|
|
14
|
+
exports.rgbaStringToRgba = rgbaStringToRgba;
|
|
15
|
+
exports.rgbToHsl = rgbToHsl;
|
|
16
|
+
exports.hslToRgb = hslToRgb;
|
|
17
|
+
exports.rgbToHsv = rgbToHsv;
|
|
18
|
+
exports.hsvToRgb = hsvToRgb;
|
|
19
|
+
exports.hexToHsv = hexToHsv;
|
|
20
|
+
exports.hsvToHex = hsvToHex;
|
|
21
|
+
exports.hex8ToRgba = hex8ToRgba;
|
|
22
|
+
exports.rgbaToHex8 = rgbaToHex8;
|
|
23
|
+
exports.rgbToCmyk = rgbToCmyk;
|
|
24
|
+
exports.cmykToRgb = cmykToRgb;
|
|
25
|
+
exports.rgbToLab = rgbToLab;
|
|
26
|
+
exports.labToRgb = labToRgb;
|
|
27
|
+
exports.rgbToLch = rgbToLch;
|
|
28
|
+
exports.lchToRgb = lchToRgb;
|
|
29
|
+
exports.rgbToHwb = rgbToHwb;
|
|
30
|
+
exports.hwbToRgb = hwbToRgb;
|
|
31
|
+
exports.toHwbString = toHwbString;
|
|
32
|
+
exports.rgbToOklab = rgbToOklab;
|
|
33
|
+
exports.oklabToRgb = oklabToRgb;
|
|
34
|
+
exports.rgbToOklch = rgbToOklch;
|
|
35
|
+
exports.oklchToRgb = oklchToRgb;
|
|
36
|
+
exports.toHslString = toHslString;
|
|
37
|
+
// Pure numeric conversions between color spaces and hex/rgba strings.
|
|
38
|
+
const transfer_js_1 = require("../internal/transfer.js");
|
|
39
|
+
// ─── Display P3 ────────────────────────────────────────────────
|
|
40
|
+
function rgbToDisplayP3(rgb) {
|
|
41
|
+
// Remove sRGB gamma (linearize)
|
|
42
|
+
const rl = (0, transfer_js_1.srgbChanToLinear)(rgb.r / 255);
|
|
43
|
+
const gl = (0, transfer_js_1.srgbChanToLinear)(rgb.g / 255);
|
|
44
|
+
const bl = (0, transfer_js_1.srgbChanToLinear)(rgb.b / 255);
|
|
45
|
+
// sRGB-linear → P3-linear matrix
|
|
46
|
+
const pr = 0.8226 * rl + 0.1774 * gl + 0.0 * bl;
|
|
47
|
+
const pg = 0.0332 * rl + 0.9669 * gl + 0.0 * bl;
|
|
48
|
+
const pb = 0.0171 * rl + 0.0724 * gl + 0.9103 * bl;
|
|
49
|
+
// Apply P3 gamma (same as sRGB)
|
|
50
|
+
return {
|
|
51
|
+
r: (0, transfer_js_1.linearChanToSrgb)(pr),
|
|
52
|
+
g: (0, transfer_js_1.linearChanToSrgb)(pg),
|
|
53
|
+
b: (0, transfer_js_1.linearChanToSrgb)(pb),
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
function displayP3ToRgb(p3) {
|
|
57
|
+
// Remove P3 gamma
|
|
58
|
+
const rl = (0, transfer_js_1.srgbChanToLinear)(p3.r);
|
|
59
|
+
const gl = (0, transfer_js_1.srgbChanToLinear)(p3.g);
|
|
60
|
+
const bl = (0, transfer_js_1.srgbChanToLinear)(p3.b);
|
|
61
|
+
// P3-linear → sRGB-linear inverse matrix
|
|
62
|
+
const sr = 1.2247 * rl + -0.2247 * gl + 0.0 * bl;
|
|
63
|
+
const sg = -0.0421 * rl + 1.0432 * gl + 0.0 * bl;
|
|
64
|
+
const sb = -0.0197 * rl + -0.0786 * gl + 1.0983 * bl;
|
|
65
|
+
// Apply sRGB gamma and scale to 0-255
|
|
66
|
+
return {
|
|
67
|
+
r: Math.round(Math.max(0, Math.min(255, (0, transfer_js_1.linearChanToSrgb)(sr) * 255))),
|
|
68
|
+
g: Math.round(Math.max(0, Math.min(255, (0, transfer_js_1.linearChanToSrgb)(sg) * 255))),
|
|
69
|
+
b: Math.round(Math.max(0, Math.min(255, (0, transfer_js_1.linearChanToSrgb)(sb) * 255))),
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
// ─── Short RGBA hex #RGBA ──────────────────────────────────────
|
|
73
|
+
function shortHexToRgba(hex) {
|
|
74
|
+
let h = hex.trim();
|
|
75
|
+
if (!h.startsWith('#'))
|
|
76
|
+
h = `#${h}`;
|
|
77
|
+
if (!/^#[0-9a-f]{4}$/i.test(h))
|
|
78
|
+
return null;
|
|
79
|
+
const r = parseInt(h[1] + h[1], 16);
|
|
80
|
+
const g = parseInt(h[2] + h[2], 16);
|
|
81
|
+
const b = parseInt(h[3] + h[3], 16);
|
|
82
|
+
const a = parseInt(h[4] + h[4], 16) / 255;
|
|
83
|
+
return { r, g, b, a };
|
|
84
|
+
}
|
|
85
|
+
function normalizeHex(hex) {
|
|
86
|
+
let cleanHex = hex.trim();
|
|
87
|
+
if (!cleanHex.startsWith('#'))
|
|
88
|
+
cleanHex = `#${cleanHex}`;
|
|
89
|
+
if (cleanHex.length === 4) {
|
|
90
|
+
cleanHex = `#${cleanHex
|
|
91
|
+
.slice(1)
|
|
92
|
+
.split('')
|
|
93
|
+
.map((c) => c + c)
|
|
94
|
+
.join('')}`;
|
|
95
|
+
}
|
|
96
|
+
if (!/^#[0-9A-Fa-f]{6}$/.test(cleanHex)) {
|
|
97
|
+
return '#f5e477';
|
|
98
|
+
}
|
|
99
|
+
return cleanHex.toLowerCase();
|
|
100
|
+
}
|
|
101
|
+
function hexToRgb(hex) {
|
|
102
|
+
const normalizedHex = normalizeHex(hex);
|
|
103
|
+
const r = parseInt(normalizedHex.slice(1, 3), 16);
|
|
104
|
+
const g = parseInt(normalizedHex.slice(3, 5), 16);
|
|
105
|
+
const b = parseInt(normalizedHex.slice(5, 7), 16);
|
|
106
|
+
return [r, g, b];
|
|
107
|
+
}
|
|
108
|
+
function hexToRgba(hex, opacity = 1) {
|
|
109
|
+
const [r, g, b] = hexToRgb(hex);
|
|
110
|
+
return `rgba(${r}, ${g}, ${b}, ${opacity})`;
|
|
111
|
+
}
|
|
112
|
+
function hexToHsl(hex) {
|
|
113
|
+
const [r, g, b] = hexToRgb(hex);
|
|
114
|
+
const red = r / 255;
|
|
115
|
+
const green = g / 255;
|
|
116
|
+
const blue = b / 255;
|
|
117
|
+
const max = Math.max(red, green, blue);
|
|
118
|
+
const min = Math.min(red, green, blue);
|
|
119
|
+
let h = 0, s = 0;
|
|
120
|
+
const l = (max + min) / 2;
|
|
121
|
+
if (max !== min) {
|
|
122
|
+
const d = max - min;
|
|
123
|
+
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
|
|
124
|
+
switch (max) {
|
|
125
|
+
case red:
|
|
126
|
+
h = (green - blue) / d + (green < blue ? 6 : 0);
|
|
127
|
+
break;
|
|
128
|
+
case green:
|
|
129
|
+
h = (blue - red) / d + 2;
|
|
130
|
+
break;
|
|
131
|
+
case blue:
|
|
132
|
+
h = (red - green) / d + 4;
|
|
133
|
+
break;
|
|
134
|
+
}
|
|
135
|
+
h /= 6;
|
|
136
|
+
}
|
|
137
|
+
return [Math.round(h * 360), Math.round(s * 100), Math.round(l * 100)];
|
|
138
|
+
}
|
|
139
|
+
function hslToHex(h, s, l) {
|
|
140
|
+
h = ((h % 360) + 360) % 360;
|
|
141
|
+
s = Math.max(0, Math.min(100, s)) / 100;
|
|
142
|
+
l = Math.max(0, Math.min(100, l)) / 100;
|
|
143
|
+
const c = (1 - Math.abs(2 * l - 1)) * s;
|
|
144
|
+
const x = c * (1 - Math.abs(((h / 60) % 2) - 1));
|
|
145
|
+
const m = l - c / 2;
|
|
146
|
+
let r = 0, g = 0, b = 0;
|
|
147
|
+
if (h >= 0 && h < 60) {
|
|
148
|
+
r = c;
|
|
149
|
+
g = x;
|
|
150
|
+
b = 0;
|
|
151
|
+
}
|
|
152
|
+
else if (h >= 60 && h < 120) {
|
|
153
|
+
r = x;
|
|
154
|
+
g = c;
|
|
155
|
+
b = 0;
|
|
156
|
+
}
|
|
157
|
+
else if (h >= 120 && h < 180) {
|
|
158
|
+
r = 0;
|
|
159
|
+
g = c;
|
|
160
|
+
b = x;
|
|
161
|
+
}
|
|
162
|
+
else if (h >= 180 && h < 240) {
|
|
163
|
+
r = 0;
|
|
164
|
+
g = x;
|
|
165
|
+
b = c;
|
|
166
|
+
}
|
|
167
|
+
else if (h >= 240 && h < 300) {
|
|
168
|
+
r = x;
|
|
169
|
+
g = 0;
|
|
170
|
+
b = c;
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
r = c;
|
|
174
|
+
g = 0;
|
|
175
|
+
b = x;
|
|
176
|
+
}
|
|
177
|
+
r = Math.round((r + m) * 255);
|
|
178
|
+
g = Math.round((g + m) * 255);
|
|
179
|
+
b = Math.round((b + m) * 255);
|
|
180
|
+
return `#${r.toString(16).padStart(2, '0')}${g.toString(16).padStart(2, '0')}${b.toString(16).padStart(2, '0')}`;
|
|
181
|
+
}
|
|
182
|
+
function clamp01(v) {
|
|
183
|
+
return Math.max(0, Math.min(1, v));
|
|
184
|
+
}
|
|
185
|
+
function toHex2(n) {
|
|
186
|
+
return Math.round(n).toString(16).padStart(2, '0');
|
|
187
|
+
}
|
|
188
|
+
function rgbToHex({ r, g, b }) {
|
|
189
|
+
return `#${toHex2(r)}${toHex2(g)}${toHex2(b)}`.toLowerCase();
|
|
190
|
+
}
|
|
191
|
+
function rgbaToHex({ r, g, b, a }) {
|
|
192
|
+
const aa = Math.round(clamp01(a) * 255);
|
|
193
|
+
return `#${toHex2(r)}${toHex2(g)}${toHex2(b)}${toHex2(aa)}`.toLowerCase();
|
|
194
|
+
}
|
|
195
|
+
function rgbToRgbaString({ r, g, b }, a) {
|
|
196
|
+
return `rgba(${Math.round(r)}, ${Math.round(g)}, ${Math.round(b)}, ${+a.toFixed(3)})`;
|
|
197
|
+
}
|
|
198
|
+
function rgbaStringToRgba(str) {
|
|
199
|
+
const s = str.trim().toLowerCase();
|
|
200
|
+
const m = s.match(/rgba?\(([^)]+)\)/);
|
|
201
|
+
if (!m)
|
|
202
|
+
return null;
|
|
203
|
+
const parts = m[1].split(/,\s*/).map((p) => p.trim());
|
|
204
|
+
if (parts.length < 3)
|
|
205
|
+
return null;
|
|
206
|
+
// Clamp channels to a valid byte and alpha to [0,1] — an out-of-range input
|
|
207
|
+
// like "rgb(300, -20, 0)" or "rgba(0,0,0,2)" is invalid CSS, but previously
|
|
208
|
+
// passed straight through unclamped, which could even corrupt downstream hex
|
|
209
|
+
// output (a negative channel stringifies with a leading "-" via toString(16)).
|
|
210
|
+
const parseChannel = (v) => {
|
|
211
|
+
const n = v.endsWith('%') ? parseFloat(v) * 2.55 : parseFloat(v);
|
|
212
|
+
return Math.round(Math.max(0, Math.min(255, n)));
|
|
213
|
+
};
|
|
214
|
+
const r = parseChannel(parts[0]);
|
|
215
|
+
const g = parseChannel(parts[1]);
|
|
216
|
+
const b = parseChannel(parts[2]);
|
|
217
|
+
const a = parts[3] !== undefined ? Math.max(0, Math.min(1, parseFloat(parts[3]))) : 1;
|
|
218
|
+
return { r, g, b, a };
|
|
219
|
+
}
|
|
220
|
+
function rgbToHsl({ r, g, b, }) {
|
|
221
|
+
const rd = r / 255, gd = g / 255, bd = b / 255;
|
|
222
|
+
const max = Math.max(rd, gd, bd), min = Math.min(rd, gd, bd);
|
|
223
|
+
let h = 0, s = 0;
|
|
224
|
+
const l = (max + min) / 2;
|
|
225
|
+
if (max !== min) {
|
|
226
|
+
const d = max - min;
|
|
227
|
+
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
|
|
228
|
+
switch (max) {
|
|
229
|
+
case rd:
|
|
230
|
+
h = (gd - bd) / d + (gd < bd ? 6 : 0);
|
|
231
|
+
break;
|
|
232
|
+
case gd:
|
|
233
|
+
h = (bd - rd) / d + 2;
|
|
234
|
+
break;
|
|
235
|
+
case bd:
|
|
236
|
+
h = (rd - gd) / d + 4;
|
|
237
|
+
break;
|
|
238
|
+
}
|
|
239
|
+
h /= 6;
|
|
240
|
+
}
|
|
241
|
+
return [Math.round(h * 360), Math.round(s * 100), Math.round(l * 100)];
|
|
242
|
+
}
|
|
243
|
+
function hslToRgb(h, s, l) {
|
|
244
|
+
h = ((h % 360) + 360) % 360;
|
|
245
|
+
s = Math.max(0, Math.min(100, s)) / 100;
|
|
246
|
+
l = Math.max(0, Math.min(100, l)) / 100;
|
|
247
|
+
const c = (1 - Math.abs(2 * l - 1)) * s;
|
|
248
|
+
const x = c * (1 - Math.abs(((h / 60) % 2) - 1));
|
|
249
|
+
const m = l - c / 2;
|
|
250
|
+
let rd = 0, gd = 0, bd = 0;
|
|
251
|
+
if (h >= 0 && h < 60) {
|
|
252
|
+
rd = c;
|
|
253
|
+
gd = x;
|
|
254
|
+
bd = 0;
|
|
255
|
+
}
|
|
256
|
+
else if (h >= 60 && h < 120) {
|
|
257
|
+
rd = x;
|
|
258
|
+
gd = c;
|
|
259
|
+
bd = 0;
|
|
260
|
+
}
|
|
261
|
+
else if (h >= 120 && h < 180) {
|
|
262
|
+
rd = 0;
|
|
263
|
+
gd = c;
|
|
264
|
+
bd = x;
|
|
265
|
+
}
|
|
266
|
+
else if (h >= 180 && h < 240) {
|
|
267
|
+
rd = 0;
|
|
268
|
+
gd = x;
|
|
269
|
+
bd = c;
|
|
270
|
+
}
|
|
271
|
+
else if (h >= 240 && h < 300) {
|
|
272
|
+
rd = x;
|
|
273
|
+
gd = 0;
|
|
274
|
+
bd = c;
|
|
275
|
+
}
|
|
276
|
+
else {
|
|
277
|
+
rd = c;
|
|
278
|
+
gd = 0;
|
|
279
|
+
bd = x;
|
|
280
|
+
}
|
|
281
|
+
return {
|
|
282
|
+
r: Math.round((rd + m) * 255),
|
|
283
|
+
g: Math.round((gd + m) * 255),
|
|
284
|
+
b: Math.round((bd + m) * 255),
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
function rgbToHsv({ r, g, b, }) {
|
|
288
|
+
const rd = r / 255, gd = g / 255, bd = b / 255;
|
|
289
|
+
const max = Math.max(rd, gd, bd), min = Math.min(rd, gd, bd);
|
|
290
|
+
const v = max;
|
|
291
|
+
const d = max - min;
|
|
292
|
+
const s = max === 0 ? 0 : d / max;
|
|
293
|
+
let h = 0;
|
|
294
|
+
if (d !== 0) {
|
|
295
|
+
switch (max) {
|
|
296
|
+
case rd:
|
|
297
|
+
h = (gd - bd) / d + (gd < bd ? 6 : 0);
|
|
298
|
+
break;
|
|
299
|
+
case gd:
|
|
300
|
+
h = (bd - rd) / d + 2;
|
|
301
|
+
break;
|
|
302
|
+
case bd:
|
|
303
|
+
h = (rd - gd) / d + 4;
|
|
304
|
+
break;
|
|
305
|
+
}
|
|
306
|
+
h /= 6;
|
|
307
|
+
}
|
|
308
|
+
return [Math.round(h * 360), Math.round(s * 100), Math.round(v * 100)];
|
|
309
|
+
}
|
|
310
|
+
function hsvToRgb(h, s, v) {
|
|
311
|
+
h = ((h % 360) + 360) % 360;
|
|
312
|
+
s = Math.max(0, Math.min(100, s)) / 100;
|
|
313
|
+
v = Math.max(0, Math.min(100, v)) / 100;
|
|
314
|
+
const i = Math.floor(h / 60);
|
|
315
|
+
const f = h / 60 - i;
|
|
316
|
+
const p = v * (1 - s);
|
|
317
|
+
const q = v * (1 - f * s);
|
|
318
|
+
const t = v * (1 - (1 - f) * s);
|
|
319
|
+
let rd = 0, gd = 0, bd = 0;
|
|
320
|
+
switch (i) {
|
|
321
|
+
case 0:
|
|
322
|
+
rd = v;
|
|
323
|
+
gd = t;
|
|
324
|
+
bd = p;
|
|
325
|
+
break;
|
|
326
|
+
case 1:
|
|
327
|
+
rd = q;
|
|
328
|
+
gd = v;
|
|
329
|
+
bd = p;
|
|
330
|
+
break;
|
|
331
|
+
case 2:
|
|
332
|
+
rd = p;
|
|
333
|
+
gd = v;
|
|
334
|
+
bd = t;
|
|
335
|
+
break;
|
|
336
|
+
case 3:
|
|
337
|
+
rd = p;
|
|
338
|
+
gd = q;
|
|
339
|
+
bd = v;
|
|
340
|
+
break;
|
|
341
|
+
case 4:
|
|
342
|
+
rd = t;
|
|
343
|
+
gd = p;
|
|
344
|
+
bd = v;
|
|
345
|
+
break;
|
|
346
|
+
default:
|
|
347
|
+
rd = v;
|
|
348
|
+
gd = p;
|
|
349
|
+
bd = q;
|
|
350
|
+
break;
|
|
351
|
+
}
|
|
352
|
+
return { r: Math.round(rd * 255), g: Math.round(gd * 255), b: Math.round(bd * 255) };
|
|
353
|
+
}
|
|
354
|
+
function hexToHsv(hex) {
|
|
355
|
+
const [r, g, b] = hexToRgb(hex);
|
|
356
|
+
return rgbToHsv({ r, g, b });
|
|
357
|
+
}
|
|
358
|
+
function hsvToHex(h, s, v) {
|
|
359
|
+
const { r, g, b } = hsvToRgb(h, s, v);
|
|
360
|
+
return rgbToHex({ r, g, b });
|
|
361
|
+
}
|
|
362
|
+
function hex8ToRgba(hex) {
|
|
363
|
+
let h = hex.trim();
|
|
364
|
+
if (!h.startsWith('#'))
|
|
365
|
+
h = `#${h}`;
|
|
366
|
+
if (h.length === 5) {
|
|
367
|
+
// #rgba shorthand
|
|
368
|
+
h = `#${h[1]}${h[1]}${h[2]}${h[2]}${h[3]}${h[3]}${h[4]}${h[4]}`;
|
|
369
|
+
}
|
|
370
|
+
if (h.length !== 9)
|
|
371
|
+
return null;
|
|
372
|
+
const r = parseInt(h.slice(1, 3), 16);
|
|
373
|
+
const g = parseInt(h.slice(3, 5), 16);
|
|
374
|
+
const b = parseInt(h.slice(5, 7), 16);
|
|
375
|
+
const a = parseInt(h.slice(7, 9), 16) / 255;
|
|
376
|
+
return { r, g, b, a };
|
|
377
|
+
}
|
|
378
|
+
function rgbaToHex8({ r, g, b, a }) {
|
|
379
|
+
return rgbaToHex({ r, g, b, a });
|
|
380
|
+
}
|
|
381
|
+
function rgbToCmyk({ r, g, b }) {
|
|
382
|
+
const rd = r / 255, gd = g / 255, bd = b / 255;
|
|
383
|
+
const k = 1 - Math.max(rd, gd, bd);
|
|
384
|
+
if (k === 1)
|
|
385
|
+
return { c: 0, m: 0, y: 0, k: 1 };
|
|
386
|
+
const c = (1 - rd - k) / (1 - k);
|
|
387
|
+
const m = (1 - gd - k) / (1 - k);
|
|
388
|
+
const y = (1 - bd - k) / (1 - k);
|
|
389
|
+
return { c, m, y, k };
|
|
390
|
+
}
|
|
391
|
+
function cmykToRgb({ c, m, y, k }) {
|
|
392
|
+
const r = 255 * (1 - c) * (1 - k);
|
|
393
|
+
const g = 255 * (1 - m) * (1 - k);
|
|
394
|
+
const b = 255 * (1 - y) * (1 - k);
|
|
395
|
+
return { r: Math.round(r), g: Math.round(g), b: Math.round(b) };
|
|
396
|
+
}
|
|
397
|
+
function srgbToLinear(v) {
|
|
398
|
+
v = v / 255;
|
|
399
|
+
return v <= 0.04045 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
|
|
400
|
+
}
|
|
401
|
+
function linearToSrgb(v) {
|
|
402
|
+
const t = v <= 0.0031308 ? 12.92 * v : 1.055 * Math.pow(v, 1 / 2.4) - 0.055;
|
|
403
|
+
return Math.round(Math.max(0, Math.min(1, t)) * 255);
|
|
404
|
+
}
|
|
405
|
+
function rgbToXyz({ r, g, b }) {
|
|
406
|
+
const R = srgbToLinear(r);
|
|
407
|
+
const G = srgbToLinear(g);
|
|
408
|
+
const B = srgbToLinear(b);
|
|
409
|
+
const X = R * 0.4124564 + G * 0.3575761 + B * 0.1804375;
|
|
410
|
+
const Y = R * 0.2126729 + G * 0.7151522 + B * 0.072175;
|
|
411
|
+
const Z = R * 0.0193339 + G * 0.119192 + B * 0.9503041;
|
|
412
|
+
return { X: X * 100, Y: Y * 100, Z: Z * 100 };
|
|
413
|
+
}
|
|
414
|
+
function xyzToRgb({ X, Y, Z }) {
|
|
415
|
+
X = X / 100;
|
|
416
|
+
Y = Y / 100;
|
|
417
|
+
Z = Z / 100;
|
|
418
|
+
let R = X * 3.2404542 + Y * -1.5371385 + Z * -0.4985314;
|
|
419
|
+
let G = X * -0.969266 + Y * 1.8760108 + Z * 0.041556;
|
|
420
|
+
let B = X * 0.0556434 + Y * -0.2040259 + Z * 1.0572252;
|
|
421
|
+
R = linearToSrgb(R);
|
|
422
|
+
G = linearToSrgb(G);
|
|
423
|
+
B = linearToSrgb(B);
|
|
424
|
+
return { r: R, g: G, b: B };
|
|
425
|
+
}
|
|
426
|
+
function rgbToLab({ r, g, b }) {
|
|
427
|
+
const { X, Y, Z } = rgbToXyz({ r, g, b });
|
|
428
|
+
const refX = 95.047, refY = 100.0, refZ = 108.883;
|
|
429
|
+
const x = X / refX, y = Y / refY, z = Z / refZ;
|
|
430
|
+
const fx = x > 0.008856 ? Math.cbrt(x) : 7.787 * x + 16 / 116;
|
|
431
|
+
const fy = y > 0.008856 ? Math.cbrt(y) : 7.787 * y + 16 / 116;
|
|
432
|
+
const fz = z > 0.008856 ? Math.cbrt(z) : 7.787 * z + 16 / 116;
|
|
433
|
+
const L = 116 * fy - 16;
|
|
434
|
+
const a = 500 * (fx - fy);
|
|
435
|
+
const b2 = 200 * (fy - fz);
|
|
436
|
+
return { L, a, b: b2 };
|
|
437
|
+
}
|
|
438
|
+
function labToRgb({ L, a, b }) {
|
|
439
|
+
const refX = 95.047, refY = 100.0, refZ = 108.883;
|
|
440
|
+
let fy = (L + 16) / 116;
|
|
441
|
+
let fx = a / 500 + fy;
|
|
442
|
+
let fz = fy - b / 200;
|
|
443
|
+
const fx3 = Math.pow(fx, 3);
|
|
444
|
+
const fz3 = Math.pow(fz, 3);
|
|
445
|
+
const fy3 = Math.pow(fy, 3);
|
|
446
|
+
const xr = fx3 > 0.008856 ? fx3 : (fx - 16 / 116) / 7.787;
|
|
447
|
+
const yr = L > 903.3 * 0.008856 ? fy3 : L / 903.3;
|
|
448
|
+
const zr = fz3 > 0.008856 ? fz3 : (fz - 16 / 116) / 7.787;
|
|
449
|
+
const X = xr * refX, Y = yr * refY, Z = zr * refZ;
|
|
450
|
+
return xyzToRgb({ X, Y, Z });
|
|
451
|
+
}
|
|
452
|
+
function rgbToLch({ r, g, b }) {
|
|
453
|
+
const { L, a, b: bb } = rgbToLab({ r, g, b });
|
|
454
|
+
const C = Math.sqrt(a * a + bb * bb);
|
|
455
|
+
let H = Math.atan2(bb, a) * (180 / Math.PI);
|
|
456
|
+
if (H < 0)
|
|
457
|
+
H += 360;
|
|
458
|
+
return { L, C, H };
|
|
459
|
+
}
|
|
460
|
+
function lchToRgb({ L, C, H }) {
|
|
461
|
+
const a = Math.cos((H * Math.PI) / 180) * C;
|
|
462
|
+
const b = Math.sin((H * Math.PI) / 180) * C;
|
|
463
|
+
return labToRgb({ L, a, b });
|
|
464
|
+
}
|
|
465
|
+
// ─── HWB ─────────────────────────────────────────────────────────────────────
|
|
466
|
+
function rgbToHwb({ r, g, b, }) {
|
|
467
|
+
const rd = r / 255, gd = g / 255, bd = b / 255;
|
|
468
|
+
const max = Math.max(rd, gd, bd), min = Math.min(rd, gd, bd);
|
|
469
|
+
const w = min;
|
|
470
|
+
const bl = 1 - max;
|
|
471
|
+
let h = 0;
|
|
472
|
+
if (max !== min) {
|
|
473
|
+
const d = max - min;
|
|
474
|
+
switch (max) {
|
|
475
|
+
case rd:
|
|
476
|
+
h = (gd - bd) / d + (gd < bd ? 6 : 0);
|
|
477
|
+
break;
|
|
478
|
+
case gd:
|
|
479
|
+
h = (bd - rd) / d + 2;
|
|
480
|
+
break;
|
|
481
|
+
case bd:
|
|
482
|
+
h = (rd - gd) / d + 4;
|
|
483
|
+
break;
|
|
484
|
+
}
|
|
485
|
+
h /= 6;
|
|
486
|
+
}
|
|
487
|
+
return [Math.round(h * 360), Math.round(w * 100), Math.round(bl * 100)];
|
|
488
|
+
}
|
|
489
|
+
function hwbToRgb(H, W, B) {
|
|
490
|
+
H = ((H % 360) + 360) % 360;
|
|
491
|
+
const w = W / 100, b = B / 100;
|
|
492
|
+
if (w + b >= 1) {
|
|
493
|
+
const gray = Math.round((w / (w + b)) * 255);
|
|
494
|
+
return { r: gray, g: gray, b: gray };
|
|
495
|
+
}
|
|
496
|
+
const { r, g, b: rb } = hslToRgb(H, 100, 50);
|
|
497
|
+
const factor = 1 - w - b;
|
|
498
|
+
return {
|
|
499
|
+
r: Math.round((r / 255) * factor * 255 + w * 255),
|
|
500
|
+
g: Math.round((g / 255) * factor * 255 + w * 255),
|
|
501
|
+
b: Math.round((rb / 255) * factor * 255 + w * 255),
|
|
502
|
+
};
|
|
503
|
+
}
|
|
504
|
+
function toHwbString(H, W, B, alpha) {
|
|
505
|
+
if (alpha !== undefined)
|
|
506
|
+
return `hwb(${H} ${W}% ${B}% / ${+alpha.toFixed(3)})`;
|
|
507
|
+
return `hwb(${H} ${W}% ${B}%)`;
|
|
508
|
+
}
|
|
509
|
+
// ─── OKLCH / OKLAB ───────────────────────────────────────────────────────────
|
|
510
|
+
function srgbToOkLinear(v) {
|
|
511
|
+
v = v / 255;
|
|
512
|
+
return v <= 0.04045 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
|
|
513
|
+
}
|
|
514
|
+
function okLinearToSrgb(v) {
|
|
515
|
+
const t = v <= 0.0031308 ? 12.92 * v : 1.055 * Math.pow(v, 1 / 2.4) - 0.055;
|
|
516
|
+
return Math.round(Math.max(0, Math.min(1, t)) * 255);
|
|
517
|
+
}
|
|
518
|
+
function rgbToOklab({ r, g, b }) {
|
|
519
|
+
const R = srgbToOkLinear(r), G = srgbToOkLinear(g), B = srgbToOkLinear(b);
|
|
520
|
+
const l = Math.cbrt(0.4122214708 * R + 0.5363325363 * G + 0.0514459929 * B);
|
|
521
|
+
const m = Math.cbrt(0.2119034982 * R + 0.6806995451 * G + 0.1073969566 * B);
|
|
522
|
+
const s = Math.cbrt(0.0883024619 * R + 0.2817188376 * G + 0.6299787005 * B);
|
|
523
|
+
return {
|
|
524
|
+
L: 0.2104542553 * l + 0.793617785 * m - 0.0040720468 * s,
|
|
525
|
+
a: 1.9779984951 * l - 2.428592205 * m + 0.4505937099 * s,
|
|
526
|
+
b: 0.0259040371 * l + 0.7827717662 * m - 0.808675766 * s,
|
|
527
|
+
};
|
|
528
|
+
}
|
|
529
|
+
function oklabToRgb({ L, a, b }) {
|
|
530
|
+
const l = Math.pow(L + 0.3963377774 * a + 0.2158037573 * b, 3);
|
|
531
|
+
const m = Math.pow(L - 0.1055613458 * a - 0.0638541728 * b, 3);
|
|
532
|
+
const s = Math.pow(L - 0.0894841775 * a - 1.291485548 * b, 3);
|
|
533
|
+
const R = okLinearToSrgb(+4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s);
|
|
534
|
+
const G = okLinearToSrgb(-1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s);
|
|
535
|
+
const B = okLinearToSrgb(-0.0041960863 * l - 0.7034186147 * m + 1.707614701 * s);
|
|
536
|
+
return { r: R, g: G, b: B };
|
|
537
|
+
}
|
|
538
|
+
function rgbToOklch({ r, g, b }) {
|
|
539
|
+
const { L, a, b: bb } = rgbToOklab({ r, g, b });
|
|
540
|
+
const C = Math.sqrt(a * a + bb * bb);
|
|
541
|
+
let H = Math.atan2(bb, a) * (180 / Math.PI);
|
|
542
|
+
if (H < 0)
|
|
543
|
+
H += 360;
|
|
544
|
+
return { L, C, H };
|
|
545
|
+
}
|
|
546
|
+
function oklchToRgb({ L, C, H }) {
|
|
547
|
+
const a = Math.cos((H * Math.PI) / 180) * C;
|
|
548
|
+
const b = Math.sin((H * Math.PI) / 180) * C;
|
|
549
|
+
return oklabToRgb({ L, a, b });
|
|
550
|
+
}
|
|
551
|
+
// ─── Utilities ───────────────────────────────────────────────────────────────
|
|
552
|
+
function toHslString(h, s, l, alpha) {
|
|
553
|
+
if (alpha !== undefined)
|
|
554
|
+
return `hsla(${h}, ${s}%, ${l}%, ${+alpha.toFixed(3)})`;
|
|
555
|
+
return `hsl(${h}, ${s}%, ${l}%)`;
|
|
556
|
+
}
|