@thi.ng/color
Version:
Array-based color types, CSS parsing, conversions, transformations, declarative theme generation, gradients, presets
1,353 lines (1,352 loc) • 11.4 kB
JavaScript
import { clamp01 } from "@thi.ng/math/interval";
import { mix, mixBilinear } from "@thi.ng/math/mix";
import { fract } from "@thi.ng/math/prec";
import { lch } from "./lch/lch.js";
const MAX_CHROMA = [
[
4,
22,
30,
34,
38,
43,
47,
52,
56,
61,
66,
70,
75,
80,
84,
74,
65,
56,
47,
39,
32,
25,
18,
11,
5
],
[
4,
22,
30,
34,
39,
43,
48,
52,
57,
61,
66,
71,
75,
80,
82,
72,
63,
54,
46,
38,
31,
24,
17,
10,
5
],
[
4,
22,
31,
35,
39,
44,
49,
53,
58,
63,
67,
72,
77,
82,
83,
73,
63,
54,
46,
38,
31,
24,
17,
10,
5
],
[
3,
20,
32,
37,
41,
46,
51,
55,
60,
65,
70,
75,
80,
85,
85,
74,
65,
55,
47,
39,
31,
24,
17,
10,
5
],
[
2,
15,
27,
39,
44,
49,
54,
59,
64,
69,
75,
80,
85,
90,
89,
78,
67,
57,
48,
40,
32,
25,
18,
10,
5
],
[
2,
11,
22,
32,
43,
53,
59,
64,
70,
76,
81,
87,
93,
99,
96,
84,
72,
61,
51,
42,
34,
26,
19,
11,
5
],
[
1,
10,
19,
27,
36,
44,
52,
59,
66,
72,
77,
83,
88,
93,
98,
92,
79,
67,
56,
45,
36,
28,
20,
12,
6
],
[
1,
9,
17,
24,
31,
38,
45,
51,
57,
61,
66,
70,
75,
79,
84,
88,
90,
75,
62,
51,
40,
30,
22,
13,
6
],
[
1,
8,
15,
22,
28,
35,
40,
46,
50,
54,
58,
62,
66,
70,
74,
78,
82,
86,
73,
59,
46,
35,
24,
15,
7
],
[
1,
7,
13,
20,
26,
32,
37,
42,
46,
50,
53,
57,
61,
64,
68,
72,
75,
79,
83,
72,
55,
41,
29,
18,
8
],
[
1,
7,
12,
19,
25,
30,
35,
40,
43,
47,
50,
54,
57,
60,
64,
67,
71,
74,
78,
81,
73,
53,
36,
22,
10
],
[
1,
7,
12,
19,
24,
29,
34,
38,
42,
45,
48,
51,
55,
58,
61,
65,
68,
71,
75,
78,
82,
79,
50,
29,
12
],
[
1,
7,
12,
19,
24,
29,
33,
37,
41,
44,
47,
50,
54,
57,
60,
63,
67,
70,
73,
77,
80,
83,
86,
48,
19
],
[
1,
7,
12,
19,
24,
29,
33,
37,
41,
44,
47,
50,
53,
57,
60,
63,
66,
70,
73,
76,
80,
83,
86,
90,
45
],
[
1,
7,
12,
19,
25,
30,
34,
38,
41,
44,
48,
51,
54,
58,
61,
64,
67,
71,
74,
78,
81,
84,
88,
91,
94
],
[
1,
7,
13,
20,
26,
31,
35,
39,
43,
46,
49,
53,
56,
60,
63,
66,
70,
73,
77,
80,
84,
87,
91,
94,
60
],
[
1,
8,
15,
21,
27,
33,
37,
42,
45,
49,
52,
56,
59,
63,
66,
70,
74,
77,
81,
85,
88,
92,
96,
96,
44
],
[
1,
9,
16,
23,
29,
35,
40,
45,
49,
52,
56,
60,
64,
68,
72,
76,
80,
84,
87,
91,
95,
99,
103,
77,
35
],
[
1,
10,
18,
26,
33,
39,
44,
48,
52,
56,
60,
65,
69,
73,
77,
82,
86,
90,
94,
99,
103,
107,
110,
65,
30
],
[
2,
10,
21,
28,
30,
34,
37,
40,
44,
47,
51,
55,
58,
62,
65,
69,
73,
76,
80,
83,
87,
91,
94,
58,
26
],
[
1,
10,
18,
24,
26,
29,
32,
35,
38,
41,
44,
47,
50,
53,
56,
60,
63,
66,
69,
72,
75,
78,
81,
52,
24
],
[
1,
8,
15,
21,
23,
26,
28,
31,
33,
36,
39,
42,
44,
47,
50,
53,
55,
58,
61,
64,
66,
69,
72,
48,
22
],
[
1,
7,
13,
19,
21,
23,
25,
28,
30,
33,
35,
37,
40,
42,
45,
47,
50,
52,
55,
57,
60,
62,
65,
46,
21
],
[
1,
7,
12,
17,
19,
21,
23,
25,
28,
30,
32,
34,
37,
39,
41,
44,
46,
48,
50,
53,
55,
57,
60,
44,
20
],
[
1,
6,
11,
16,
18,
20,
22,
24,
26,
28,
30,
32,
34,
36,
39,
41,
43,
45,
47,
49,
51,
54,
56,
43,
19
],
[
1,
6,
11,
15,
17,
19,
21,
23,
25,
27,
29,
31,
33,
35,
37,
39,
41,
43,
45,
47,
49,
51,
53,
43,
19
],
[
1,
6,
10,
15,
16,
18,
20,
22,
24,
26,
28,
30,
32,
34,
35,
37,
39,
41,
43,
45,
47,
49,
51,
43,
20
],
[
1,
6,
10,
13,
16,
18,
20,
21,
23,
25,
27,
29,
31,
33,
35,
37,
39,
41,
43,
45,
46,
48,
49,
33,
16
],
[
1,
6,
10,
13,
16,
18,
19,
21,
23,
25,
27,
29,
31,
33,
35,
37,
39,
41,
42,
44,
46,
48,
37,
25,
11
],
[
1,
7,
11,
13,
16,
18,
20,
22,
23,
25,
27,
29,
31,
33,
35,
37,
39,
41,
43,
45,
47,
40,
30,
20,
10
],
[
1,
7,
11,
15,
16,
18,
20,
22,
24,
26,
28,
30,
32,
34,
36,
38,
40,
42,
44,
46,
43,
34,
26,
17,
8
],
[
1,
7,
12,
15,
17,
19,
21,
23,
25,
27,
29,
31,
34,
36,
38,
40,
42,
44,
46,
46,
38,
31,
23,
15,
7
],
[
1,
8,
13,
16,
18,
20,
22,
25,
27,
29,
31,
33,
36,
38,
40,
42,
45,
47,
49,
42,
35,
28,
21,
13,
7
],
[
1,
10,
15,
18,
20,
22,
24,
27,
29,
31,
34,
36,
39,
41,
43,
46,
48,
51,
46,
40,
33,
26,
19,
12,
6
],
[
2,
10,
17,
19,
22,
24,
27,
29,
32,
35,
37,
40,
43,
45,
48,
51,
53,
51,
44,
38,
31,
25,
18,
11,
6
],
[
2,
13,
19,
22,
25,
28,
30,
33,
36,
39,
42,
45,
48,
51,
54,
57,
56,
49,
43,
37,
30,
24,
18,
11,
6
],
[
3,
17,
22,
26,
29,
32,
36,
39,
42,
46,
49,
53,
56,
60,
63,
62,
55,
49,
43,
36,
30,
24,
18,
11,
6
],
[
6,
23,
27,
31,
35,
39,
43,
47,
51,
56,
60,
64,
68,
73,
69,
62,
56,
49,
43,
36,
30,
24,
18,
11,
6
],
[
18,
30,
34,
39,
44,
49,
54,
60,
65,
70,
76,
81,
84,
77,
70,
64,
57,
50,
44,
37,
31,
25,
18,
11,
6
],
[
12,
41,
45,
52,
59,
66,
73,
80,
87,
94,
102,
95,
88,
81,
74,
66,
60,
53,
46,
39,
32,
26,
19,
11,
6
],
[
9,
58,
65,
75,
85,
96,
106,
117,
124,
116,
109,
101,
93,
86,
78,
71,
63,
56,
49,
42,
34,
27,
20,
12,
6
],
[
7,
42,
58,
66,
74,
82,
91,
99,
108,
117,
119,
110,
102,
94,
85,
77,
69,
61,
53,
45,
37,
30,
22,
13,
7
],
[
6,
34,
47,
53,
60,
67,
74,
81,
88,
95,
102,
109,
114,
105,
95,
86,
77,
68,
59,
51,
42,
33,
25,
16,
8
],
[
5,
29,
40,
46,
52,
57,
63,
70,
76,
82,
88,
94,
100,
107,
110,
100,
89,
79,
69,
58,
48,
38,
29,
19,
9
],
[
4,
26,
36,
41,
46,
52,
57,
62,
68,
73,
79,
85,
90,
96,
101,
104,
91,
79,
67,
56,
45,
35,
26,
17,
8
],
[
4,
24,
34,
38,
43,
48,
53,
58,
63,
68,
73,
78,
83,
88,
94,
91,
79,
69,
59,
49,
40,
31,
23,
15,
7
],
[
4,
23,
32,
36,
40,
45,
50,
55,
59,
64,
69,
74,
79,
84,
89,
82,
72,
62,
53,
44,
36,
28,
20,
12,
6
],
[
4,
22,
31,
35,
39,
44,
48,
53,
57,
62,
67,
71,
76,
81,
86,
77,
67,
58,
50,
41,
33,
26,
19,
11,
6
]
];
const RES_H = MAX_CHROMA.length;
const RES_L = MAX_CHROMA[0].length;
const maxChroma = (l, h) => {
h = fract(h);
l = clamp01(l);
if (l < 1) {
const h1 = h * RES_H | 0;
const l1 = l * RES_L | 0;
const lutH1 = MAX_CHROMA[h1];
const lutH2 = MAX_CHROMA[(h1 + 1) % RES_H];
return mixBilinear(
lutH1[l1],
lutH2[l1],
l1 < RES_L - 1 ? lutH1[l1 + 1] : 0,
l1 < RES_L - 1 ? lutH2[l1 + 1] : 0,
h * RES_H - h1,
l * RES_L - l1
) * 0.01;
}
return 0;
};
const lchMaxChroma = (l, h, a = 1) => lch(l, maxChroma(l, h), h, a);
const maxLumaChroma = (h) => {
const h1 = fract(h) * RES_H | 0;
const t = h * RES_H - h1;
const [l1, c1] = __maxLC(MAX_CHROMA[h1]);
const [l2, c2] = __maxLC(MAX_CHROMA[(h1 + 1) % RES_H]);
return { l: mix(l1, l2, t) / RES_L, c: mix(c1, c2, t) * 0.01 };
};
const lchMaxLumaChroma = (h, a = 1) => {
const max = maxLumaChroma(h);
return lch(max.l, max.c, h, a);
};
const __maxLC = (chroma) => {
let maxL = 0;
let maxC = 0;
for (let i = RES_L; i-- > 0; ) {
if (chroma[i] >= maxC) {
maxC = chroma[i];
maxL = i;
} else break;
}
return [maxL, maxC];
};
export {
lchMaxChroma,
lchMaxLumaChroma,
maxChroma,
maxLumaChroma
};