color-bits 0.1.0 → 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/README.md +82 -2
- package/benchmarks/index.ts +35 -0
- package/build/bit.d.ts +3 -0
- package/{src/bit.ts → build/bit.js} +15 -13
- package/build/bit.js.map +1 -0
- package/build/convert.d.ts +23 -0
- package/build/convert.js +347 -0
- package/build/convert.js.map +1 -0
- package/build/core.d.ts +27 -0
- package/build/core.js +75 -0
- package/build/core.js.map +1 -0
- package/build/format.d.ts +24 -0
- package/build/format.js +133 -0
- package/build/format.js.map +1 -0
- package/build/functions.d.ts +33 -0
- package/build/functions.js +95 -0
- package/build/functions.js.map +1 -0
- package/{src/index.ts → build/index.d.ts} +1 -1
- package/build/index.js +21 -0
- package/build/index.js.map +1 -0
- package/build/parse.d.ts +17 -0
- package/build/parse.js +392 -0
- package/build/parse.js.map +1 -0
- package/build/string.d.ts +5 -0
- package/build/string.js +38 -0
- package/build/string.js.map +1 -0
- package/build/transform.d.ts +19 -0
- package/build/transform.js +40 -0
- package/build/transform.js.map +1 -0
- package/build/transformString.d.ts +3 -0
- package/build/transformString.js +35 -0
- package/build/transformString.js.map +1 -0
- package/package.json +24 -1
- package/tsconfig.json +4 -2
- package/src/color.test.ts +0 -66
- package/src/convert.ts +0 -392
- package/src/core.ts +0 -58
- package/src/functions.ts +0 -27
- package/src/parse.ts +0 -392
- package/src/transform.ts +0 -58
- package/src/transformString.ts +0 -7
package/src/color.test.ts
DELETED
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import { expect } from 'chai'
|
|
2
|
-
import * as Color from './index';
|
|
3
|
-
|
|
4
|
-
const c = Color.from;
|
|
5
|
-
|
|
6
|
-
describe('Color', () => {
|
|
7
|
-
it('can encode/decode the representation', () => {
|
|
8
|
-
const color = Color.from(0x599eff80)
|
|
9
|
-
expect(Color.getRed(color)).to.equal(0x59)
|
|
10
|
-
expect(Color.getGreen(color)).to.equal(0x9e)
|
|
11
|
-
expect(Color.getBlue(color)).to.equal(0xff)
|
|
12
|
-
expect(Color.getAlpha(color)).to.equal(0x80)
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
it('can set channels', () => {
|
|
16
|
-
const color = Color.parse('#ffffff')
|
|
17
|
-
expect(Color.setRed(color, 0)).to.equal(c(0x00ffffff))
|
|
18
|
-
expect(Color.setGreen(color, 0)).to.equal(c(0xff00ffff))
|
|
19
|
-
expect(Color.setBlue(color, 0)).to.equal(c(0xffff00ff))
|
|
20
|
-
expect(Color.setAlpha(color, 0)).to.equal(c(0xffffff00))
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
describe('.parse():', () => {
|
|
24
|
-
it('parses CSS hexadecimal', () => {
|
|
25
|
-
expect(Color.parse('#59f')).to.equal(c(0x5599ffff));
|
|
26
|
-
expect(Color.parse('#5599ff')).to.equal(c(0x5599ffff));
|
|
27
|
-
expect(Color.parse('#5599ffff')).to.equal(c(0x5599ffff));
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
it('parses CSS color spaces', () => {
|
|
31
|
-
['rgb', 'rgba'].forEach(type => {
|
|
32
|
-
expect(Color.parse(`${type}(255 153 85)`)).to.equal(c(0xff9955ff));
|
|
33
|
-
expect(Color.parse(`${type}(255, 153, 85)`)).to.equal(c(0xff9955ff));
|
|
34
|
-
expect(Color.parse(`${type}(255 153 85 / 50%)`)).to.equal(c(0xff995580));
|
|
35
|
-
expect(Color.parse(`${type}(255 153 85 / .5)`)).to.equal(c(0xff995580));
|
|
36
|
-
expect(Color.parse(`${type}(255 153 85 / 0.5)`)).to.equal(c(0xff995580));
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
['hsl', 'hsla'].forEach(type => {
|
|
40
|
-
expect(Color.parse(`${type}(50deg 80% 40% / 50%)`)).to.equal(c(0xb89c1480));
|
|
41
|
-
expect(Color.parse(`${type}(50deg 80% 40% / 0.5)`)).to.equal(c(0xb89c1480));
|
|
42
|
-
expect(Color.parse(`${type}(0 80% 40% / 0.5)`)).to.equal(c(0xb8141480));
|
|
43
|
-
expect(Color.parse(`${type}(none 80% 40% / 0.5)`)).to.equal(c(0xb8141480));
|
|
44
|
-
expect(Color.parse(`${type}(1turn 80% 40% / 0.5)`)).to.equal(c(0xb8141480));
|
|
45
|
-
expect(Color.parse(`${type}(400grad 80% 40% / 0.5)`)).to.equal(c(0xb8141480));
|
|
46
|
-
expect(Color.parse(`${type}(0rad 80% 40% / 0.5)`)).to.equal(c(0xb8141480));
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
expect(Color.parse('hwb(12 50% 0%)')).to.equal(c(0xff9980ff));
|
|
50
|
-
expect(Color.parse('hwb(50deg 30% 40%)')).to.equal(c(0x998c4dff));
|
|
51
|
-
expect(Color.parse('hwb(0.5turn 10% 0% / .5)')).to.equal(c(0x1affff80));
|
|
52
|
-
|
|
53
|
-
// FIXME:
|
|
54
|
-
// expect(Color.parse('lab(50% 40 59.5 / 0.5)')).to.equal(c(0xbf570080))
|
|
55
|
-
// expect(Color.parse('lch(52.2% 72.2 50 / 0.5)')).to.equal(c(0xcd561a80))
|
|
56
|
-
|
|
57
|
-
expect(Color.parse('color(srgb 1 0.5 0 / 0.5)')).to.equal(c(0xff800080))
|
|
58
|
-
expect(Color.parse('color(srgb-linear 1 0.5 0 / 0.5)')).to.equal(c(0xffbc0080))
|
|
59
|
-
expect(Color.parse('color(display-p3 1 0.5 0 / 0.5)')).to.equal(c(0xff760080))
|
|
60
|
-
expect(Color.parse('color(a98-rgb 1 0.5 0 / 0.5)')).to.equal(c(0xff810080))
|
|
61
|
-
expect(Color.parse('color(prophoto-rgb 1 0.5 0 / 0.5)')).to.equal(c(0xff630080))
|
|
62
|
-
expect(Color.parse('color(rec2020 1 0.5 0 / 0.5)')).to.equal(c(0xff720080))
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
});
|
|
66
|
-
});
|
package/src/convert.ts
DELETED
|
@@ -1,392 +0,0 @@
|
|
|
1
|
-
// Copyright 2022 The Chromium Authors. All rights reserved.
|
|
2
|
-
// Use of this source code is governed by a BSD-style license that can be
|
|
3
|
-
// found in the LICENSE file.
|
|
4
|
-
//
|
|
5
|
-
// Source: https://github.com/ChromeDevTools/devtools-frontend/blob/c51201e6ee70370f7f1ac8a1a49dca7d4561aeaa/front_end/core/common/ColorConverter.ts
|
|
6
|
-
// License: https://github.com/ChromeDevTools/devtools-frontend/blob/c51201e6ee70370f7f1ac8a1a49dca7d4561aeaa/LICENSE
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Implementation of this module and all the tests are heavily influenced by
|
|
10
|
-
* https://source.chromium.org/chromium/chromium/src/+/main:ui/gfx/color_conversions.cc
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
// https://en.wikipedia.org/wiki/CIELAB_color_space#Converting_between_CIELAB_and_CIEXYZ_coordinates
|
|
14
|
-
const D50_X = 0.9642;
|
|
15
|
-
const D50_Y = 1.0;
|
|
16
|
-
const D50_Z = 0.8251;
|
|
17
|
-
|
|
18
|
-
type Matrix3x3 = [
|
|
19
|
-
[number, number, number],
|
|
20
|
-
[number, number, number],
|
|
21
|
-
[number, number, number],
|
|
22
|
-
];
|
|
23
|
-
|
|
24
|
-
type Vector3 = [number, number, number];
|
|
25
|
-
|
|
26
|
-
function multiply(matrix: Matrix3x3, other: Vector3): Vector3 {
|
|
27
|
-
const dst = [0, 0, 0] as Vector3;
|
|
28
|
-
for (let row = 0; row < 3; ++row) {
|
|
29
|
-
dst[row] = matrix[row][0] * other[0] + matrix[row][1] * other[1] +
|
|
30
|
-
matrix[row][2] * other[2];
|
|
31
|
-
}
|
|
32
|
-
return dst;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// A transfer function mapping encoded values to linear values,
|
|
36
|
-
// represented by this 7-parameter piecewise function:
|
|
37
|
-
//
|
|
38
|
-
// linear = sign(encoded) * (c*|encoded| + f) , 0 <= |encoded| < d
|
|
39
|
-
// = sign(encoded) * ((a*|encoded| + b)^g + e), d <= |encoded|
|
|
40
|
-
//
|
|
41
|
-
// (A simple gamma transfer function sets g to gamma and a to 1.)
|
|
42
|
-
class TransferFunction {
|
|
43
|
-
g: number;
|
|
44
|
-
a: number;
|
|
45
|
-
b: number;
|
|
46
|
-
c: number;
|
|
47
|
-
d: number;
|
|
48
|
-
e: number;
|
|
49
|
-
f: number;
|
|
50
|
-
|
|
51
|
-
constructor(g: number, a: number, b: number = 0, c: number = 0, d: number = 0, e: number = 0, f: number = 0) {
|
|
52
|
-
this.g = g;
|
|
53
|
-
this.a = a;
|
|
54
|
-
this.b = b;
|
|
55
|
-
this.c = c;
|
|
56
|
-
this.d = d;
|
|
57
|
-
this.e = e;
|
|
58
|
-
this.f = f;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
eval(val: number): number {
|
|
62
|
-
const sign = val < 0 ? -1.0 : 1.0;
|
|
63
|
-
const abs = val * sign;
|
|
64
|
-
|
|
65
|
-
// 0 <= |encoded| < d path
|
|
66
|
-
if (abs < this.d) {
|
|
67
|
-
return sign * (this.c * abs + this.f);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// d <= |encoded| path
|
|
71
|
-
return sign * (Math.pow(this.a * abs + this.b, this.g) + this.e);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
const NAMED_TRANSFER_FN = {
|
|
76
|
-
sRGB: new TransferFunction(2.4, (1 / 1.055), (0.055 / 1.055), (1 / 12.92), 0.04045, 0.0, 0.0),
|
|
77
|
-
sRGB_INVERSE: new TransferFunction(0.416667, 1.13728, -0, 12.92, 0.0031308, -0.0549698, -0),
|
|
78
|
-
|
|
79
|
-
proPhotoRGB: new TransferFunction(1.8, 1),
|
|
80
|
-
proPhotoRGB_INVERSE: new TransferFunction(0.555556, 1, -0, 0, 0, 0, 0),
|
|
81
|
-
|
|
82
|
-
k2Dot2: new TransferFunction(2.2, 1.0),
|
|
83
|
-
k2Dot2_INVERSE: new TransferFunction(0.454545, 1),
|
|
84
|
-
|
|
85
|
-
rec2020: new TransferFunction(2.22222, 0.909672, 0.0903276, 0.222222, 0.0812429, 0, 0),
|
|
86
|
-
rec2020_INVERSE: new TransferFunction(0.45, 1.23439, -0, 4.5, 0.018054, -0.0993195, -0),
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
const NAMED_GAMUTS = {
|
|
90
|
-
sRGB: [
|
|
91
|
-
[0.436065674, 0.385147095, 0.143066406],
|
|
92
|
-
[0.222488403, 0.716873169, 0.060607910],
|
|
93
|
-
[0.013916016, 0.097076416, 0.714096069],
|
|
94
|
-
] as Matrix3x3,
|
|
95
|
-
sRGB_INVERSE: [
|
|
96
|
-
[3.134112151374599, -1.6173924597114966, -0.4906334036481285],
|
|
97
|
-
[-0.9787872938826594, 1.9162795854799963, 0.0334547139520088],
|
|
98
|
-
[0.07198304248352326, -0.2289858493321844, 1.4053851325241447],
|
|
99
|
-
] as Matrix3x3,
|
|
100
|
-
displayP3: [
|
|
101
|
-
[0.515102, 0.291965, 0.157153],
|
|
102
|
-
[0.241182, 0.692236, 0.0665819],
|
|
103
|
-
[-0.00104941, 0.0418818, 0.784378],
|
|
104
|
-
] as Matrix3x3,
|
|
105
|
-
displayP3_INVERSE: [
|
|
106
|
-
[2.404045155982687, -0.9898986932663839, -0.3976317191366333],
|
|
107
|
-
[-0.8422283799266768, 1.7988505115115485, 0.016048170293157416],
|
|
108
|
-
[0.04818705979712955, -0.09737385156228891, 1.2735066448052303],
|
|
109
|
-
] as Matrix3x3,
|
|
110
|
-
adobeRGB: [
|
|
111
|
-
[0.60974, 0.20528, 0.14919],
|
|
112
|
-
[0.31111, 0.62567, 0.06322],
|
|
113
|
-
[0.01947, 0.06087, 0.74457],
|
|
114
|
-
] as Matrix3x3,
|
|
115
|
-
adobeRGB_INVERSE: [
|
|
116
|
-
[1.9625385510109137, -0.6106892546501431, -0.3413827467482388],
|
|
117
|
-
[-0.9787580455521, 1.9161624707082339, 0.03341676594241408],
|
|
118
|
-
[0.028696263137883395, -0.1406807819331586, 1.349252109991369],
|
|
119
|
-
] as Matrix3x3,
|
|
120
|
-
rec2020: [
|
|
121
|
-
[0.673459, 0.165661, 0.125100],
|
|
122
|
-
[0.279033, 0.675338, 0.0456288],
|
|
123
|
-
[-0.00193139, 0.0299794, 0.797162],
|
|
124
|
-
] as Matrix3x3,
|
|
125
|
-
rec2020_INVERSE: [
|
|
126
|
-
[1.647275201661012, -0.3936024771460771, -0.23598028884792507],
|
|
127
|
-
[-0.6826176165196962, 1.647617775014935, 0.01281626807852422],
|
|
128
|
-
[0.029662725298529837, -0.06291668721366285, 1.2533964313435522],
|
|
129
|
-
] as Matrix3x3,
|
|
130
|
-
xyz: [
|
|
131
|
-
[1.0, 0.0, 0.0],
|
|
132
|
-
[0.0, 1.0, 0.0],
|
|
133
|
-
[0.0, 0.0, 1.0],
|
|
134
|
-
] as Matrix3x3,
|
|
135
|
-
|
|
136
|
-
};
|
|
137
|
-
|
|
138
|
-
function degToRad(deg: number): number {
|
|
139
|
-
return deg * (Math.PI / 180);
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
function radToDeg(rad: number): number {
|
|
143
|
-
return rad * (180 / Math.PI);
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
function applyTransferFns(fn: TransferFunction, r: number, g: number, b: number): [number, number, number] {
|
|
147
|
-
return [fn.eval(r), fn.eval(g), fn.eval(b)];
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
const OKLAB_TO_LMS_MATRIX = [
|
|
151
|
-
[0.99999999845051981432, 0.39633779217376785678, 0.21580375806075880339],
|
|
152
|
-
[1.0000000088817607767, -0.1055613423236563494, -0.063854174771705903402],
|
|
153
|
-
[1.0000000546724109177, -0.089484182094965759684, -1.2914855378640917399],
|
|
154
|
-
] as Matrix3x3;
|
|
155
|
-
|
|
156
|
-
// Inverse of the OKLAB_TO_LMS_MATRIX
|
|
157
|
-
const LMS_TO_OKLAB_MATRIX = [
|
|
158
|
-
[0.2104542553, 0.7936177849999999, -0.0040720468],
|
|
159
|
-
[1.9779984951000003, -2.4285922049999997, 0.4505937099000001],
|
|
160
|
-
[0.025904037099999982, 0.7827717662, -0.8086757660000001],
|
|
161
|
-
] as Matrix3x3;
|
|
162
|
-
|
|
163
|
-
const XYZ_TO_LMS_MATRIX = [
|
|
164
|
-
[0.8190224432164319, 0.3619062562801221, -0.12887378261216414],
|
|
165
|
-
[0.0329836671980271, 0.9292868468965546, 0.03614466816999844],
|
|
166
|
-
[0.048177199566046255, 0.26423952494422764, 0.6335478258136937],
|
|
167
|
-
] as Matrix3x3;
|
|
168
|
-
// Inverse of XYZ_TO_LMS_MATRIX
|
|
169
|
-
const LMS_TO_XYZ_MATRIX = [
|
|
170
|
-
[1.226879873374156, -0.5578149965554814, 0.2813910501772159],
|
|
171
|
-
[-0.040575762624313734, 1.1122868293970596, -0.07171106666151703],
|
|
172
|
-
[-0.07637294974672144, -0.4214933239627915, 1.586924024427242],
|
|
173
|
-
] as Matrix3x3;
|
|
174
|
-
|
|
175
|
-
const PRO_PHOTO_TO_XYZD50_MATRIX = [
|
|
176
|
-
[0.7976700747153241, 0.13519395152800417, 0.03135596341127167],
|
|
177
|
-
[0.28803902352472205, 0.7118744007923554, 0.00008661179538844252],
|
|
178
|
-
[2.739876695467402e-7, -0.0000014405226518969991, 0.825211112593861],
|
|
179
|
-
] as Matrix3x3;
|
|
180
|
-
// Inverse of PRO_PHOTO_TO_XYZD50_MATRIX
|
|
181
|
-
const XYZD50_TO_PRO_PHOTO_MATRIX = [
|
|
182
|
-
[1.3459533710138858, -0.25561367037652133, -0.051116041522131374],
|
|
183
|
-
[-0.544600415668951, 1.5081687311475767, 0.020535163968720935],
|
|
184
|
-
[-0.0000013975622054109725, 0.000002717590904589903, 1.2118111696814942],
|
|
185
|
-
] as Matrix3x3;
|
|
186
|
-
|
|
187
|
-
const XYZD65_TO_XYZD50_MATRIX = [
|
|
188
|
-
[1.0478573189120088, 0.022907374491829943, -0.050162247377152525],
|
|
189
|
-
[0.029570500050499514, 0.9904755577034089, -0.017061518194840468],
|
|
190
|
-
[-0.00924047197558879, 0.015052921526981566, 0.7519708530777581],
|
|
191
|
-
] as Matrix3x3;
|
|
192
|
-
// Inverse of XYZD65_TO_XYZD50_MATRIX
|
|
193
|
-
const XYZD50_TO_XYZD65_MATRIX = [
|
|
194
|
-
[0.9555366447632887, -0.02306009252137888, 0.06321844147263304],
|
|
195
|
-
[-0.028315378228764922, 1.009951351591575, 0.021026001591792402],
|
|
196
|
-
[0.012308773293784308, -0.02050053471777469, 1.3301947294775631],
|
|
197
|
-
] as Matrix3x3;
|
|
198
|
-
|
|
199
|
-
const XYZD65_TO_SRGB_MATRIX = [
|
|
200
|
-
[3.2408089365140573, -1.5375788839307314, -0.4985609572551541],
|
|
201
|
-
[-0.9692732213205414, 1.876110235238969, 0.041560501141251774],
|
|
202
|
-
[0.05567030990267439, -0.2040007921971802, 1.0571046720577026],
|
|
203
|
-
] as Matrix3x3;
|
|
204
|
-
|
|
205
|
-
export function labToXyzd50(l: number, a: number, b: number): [number, number, number] {
|
|
206
|
-
let y = (l + 16.0) / 116.0;
|
|
207
|
-
let x = y + a / 500.0;
|
|
208
|
-
let z = y - b / 200.0;
|
|
209
|
-
|
|
210
|
-
function labInverseTransferFunction(t: number): number {
|
|
211
|
-
const delta = (24.0 / 116.0);
|
|
212
|
-
|
|
213
|
-
if (t <= delta) {
|
|
214
|
-
return (108.0 / 841.0) * (t - (16.0 / 116.0));
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
return t * t * t;
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
x = labInverseTransferFunction(x) * D50_X;
|
|
221
|
-
y = labInverseTransferFunction(y) * D50_Y;
|
|
222
|
-
z = labInverseTransferFunction(z) * D50_Z;
|
|
223
|
-
|
|
224
|
-
return [x, y, z];
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
export function xyzd50ToLab(x: number, y: number, z: number): [number, number, number] {
|
|
228
|
-
function labTransferFunction(t: number): number {
|
|
229
|
-
const deltaLimit: number = (24.0 / 116.0) * (24.0 / 116.0) * (24.0 / 116.0);
|
|
230
|
-
|
|
231
|
-
if (t <= deltaLimit) {
|
|
232
|
-
return (841.0 / 108.0) * t + (16.0 / 116.0);
|
|
233
|
-
}
|
|
234
|
-
return Math.pow(t, 1.0 / 3.0);
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
x = labTransferFunction(x / D50_X);
|
|
238
|
-
y = labTransferFunction(y / D50_Y);
|
|
239
|
-
z = labTransferFunction(z / D50_Z);
|
|
240
|
-
|
|
241
|
-
const l = 116.0 * y - 16.0;
|
|
242
|
-
const a = 500.0 * (x - y);
|
|
243
|
-
const b = 200.0 * (y - z);
|
|
244
|
-
|
|
245
|
-
return [l, a, b];
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
export function oklabToXyzd65(l: number, a: number, b: number): [number, number, number] {
|
|
249
|
-
const labInput = [l, a, b] as Vector3;
|
|
250
|
-
const lmsIntermediate = multiply(OKLAB_TO_LMS_MATRIX, labInput);
|
|
251
|
-
lmsIntermediate[0] = lmsIntermediate[0] * lmsIntermediate[0] * lmsIntermediate[0];
|
|
252
|
-
lmsIntermediate[1] = lmsIntermediate[1] * lmsIntermediate[1] * lmsIntermediate[1];
|
|
253
|
-
lmsIntermediate[2] = lmsIntermediate[2] * lmsIntermediate[2] * lmsIntermediate[2];
|
|
254
|
-
const xyzOutput = multiply(LMS_TO_XYZ_MATRIX, lmsIntermediate);
|
|
255
|
-
return xyzOutput;
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
export function xyzd65ToOklab(x: number, y: number, z: number): [number, number, number] {
|
|
259
|
-
const xyzInput = [x, y, z] as Vector3;
|
|
260
|
-
const lmsIntermediate = multiply(XYZ_TO_LMS_MATRIX, xyzInput);
|
|
261
|
-
|
|
262
|
-
lmsIntermediate[0] = Math.pow(lmsIntermediate[0], 1.0 / 3.0);
|
|
263
|
-
lmsIntermediate[1] = Math.pow(lmsIntermediate[1], 1.0 / 3.0);
|
|
264
|
-
lmsIntermediate[2] = Math.pow(lmsIntermediate[2], 1.0 / 3.0);
|
|
265
|
-
|
|
266
|
-
const labOutput = multiply(LMS_TO_OKLAB_MATRIX, lmsIntermediate);
|
|
267
|
-
return [labOutput[0], labOutput[1], labOutput[2]];
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
export function lchToLab(l: number, c: number, h: number|undefined): [number, number, number] {
|
|
271
|
-
if (h === undefined) {
|
|
272
|
-
return [l, 0, 0];
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
return [l, c * Math.cos(degToRad(h)), c * Math.sin(degToRad(h))];
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
export function labToLch(l: number, a: number, b: number): [number, number, number] {
|
|
279
|
-
return [l, Math.sqrt(a * a + b * b), radToDeg(Math.atan2(b, a))];
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
export function displayP3ToXyzd50(r: number, g: number, b: number): [number, number, number] {
|
|
283
|
-
const [mappedR, mappedG, mappedB] = applyTransferFns(NAMED_TRANSFER_FN.sRGB, r, g, b);
|
|
284
|
-
const rgbInput = [mappedR, mappedG, mappedB] as Vector3;
|
|
285
|
-
const xyzOutput = multiply(NAMED_GAMUTS.displayP3, rgbInput);
|
|
286
|
-
return xyzOutput;
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
export function xyzd50ToDisplayP3(x: number, y: number, z: number): [number, number, number] {
|
|
290
|
-
const xyzInput = [x, y, z] as Vector3;
|
|
291
|
-
const rgbOutput = multiply(NAMED_GAMUTS.displayP3_INVERSE, xyzInput);
|
|
292
|
-
return applyTransferFns(
|
|
293
|
-
NAMED_TRANSFER_FN.sRGB_INVERSE, rgbOutput[0], rgbOutput[1], rgbOutput[2]);
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
export function proPhotoToXyzd50(r: number, g: number, b: number): [number, number, number] {
|
|
297
|
-
const [mappedR, mappedG, mappedB] = applyTransferFns(NAMED_TRANSFER_FN.proPhotoRGB, r, g, b);
|
|
298
|
-
const rgbInput = [mappedR, mappedG, mappedB] as Vector3;
|
|
299
|
-
const xyzOutput = multiply(PRO_PHOTO_TO_XYZD50_MATRIX, rgbInput);
|
|
300
|
-
return xyzOutput;
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
export function xyzd50ToProPhoto(x: number, y: number, z: number): [number, number, number] {
|
|
304
|
-
const xyzInput = [x, y, z] as Vector3;
|
|
305
|
-
const rgbOutput = multiply(XYZD50_TO_PRO_PHOTO_MATRIX, xyzInput);
|
|
306
|
-
return applyTransferFns(
|
|
307
|
-
NAMED_TRANSFER_FN.proPhotoRGB_INVERSE, rgbOutput[0], rgbOutput[1], rgbOutput[2]);
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
export function adobeRGBToXyzd50(r: number, g: number, b: number): [number, number, number] {
|
|
311
|
-
const [mappedR, mappedG, mappedB] = applyTransferFns(NAMED_TRANSFER_FN.k2Dot2, r, g, b);
|
|
312
|
-
const rgbInput = [mappedR, mappedG, mappedB] as Vector3;
|
|
313
|
-
const xyzOutput = multiply(NAMED_GAMUTS.adobeRGB, rgbInput);
|
|
314
|
-
return xyzOutput;
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
export function xyzd50ToAdobeRGB(x: number, y: number, z: number): [number, number, number] {
|
|
318
|
-
const xyzInput = [x, y, z] as Vector3;
|
|
319
|
-
const rgbOutput = multiply(NAMED_GAMUTS.adobeRGB_INVERSE, xyzInput);
|
|
320
|
-
return applyTransferFns(
|
|
321
|
-
NAMED_TRANSFER_FN.k2Dot2_INVERSE, rgbOutput[0], rgbOutput[1], rgbOutput[2]);
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
export function rec2020ToXyzd50(r: number, g: number, b: number): [number, number, number] {
|
|
325
|
-
const [mappedR, mappedG, mappedB] = applyTransferFns(NAMED_TRANSFER_FN.rec2020, r, g, b);
|
|
326
|
-
const rgbInput = [mappedR, mappedG, mappedB] as Vector3;
|
|
327
|
-
const xyzOutput = multiply(NAMED_GAMUTS.rec2020, rgbInput);
|
|
328
|
-
return xyzOutput;
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
export function xyzd50ToRec2020(x: number, y: number, z: number): [number, number, number] {
|
|
332
|
-
const xyzInput = [x, y, z] as Vector3;
|
|
333
|
-
const rgbOutput = multiply(NAMED_GAMUTS.rec2020_INVERSE, xyzInput);
|
|
334
|
-
return applyTransferFns(
|
|
335
|
-
NAMED_TRANSFER_FN.rec2020_INVERSE, rgbOutput[0], rgbOutput[1], rgbOutput[2]);
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
export function xyzd50ToD65(x: number, y: number, z: number): [number, number, number] {
|
|
339
|
-
const xyzInput = [x, y, z] as Vector3;
|
|
340
|
-
const xyzOutput = multiply(XYZD50_TO_XYZD65_MATRIX, xyzInput);
|
|
341
|
-
return xyzOutput;
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
export function xyzd65ToD50(x: number, y: number, z: number): [number, number, number] {
|
|
345
|
-
const xyzInput = [x, y, z] as Vector3;
|
|
346
|
-
const xyzOutput = multiply(XYZD65_TO_XYZD50_MATRIX, xyzInput);
|
|
347
|
-
return xyzOutput;
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
export function xyzd65TosRGBLinear(x: number, y: number, z: number): [number, number, number] {
|
|
351
|
-
const xyzInput = [x, y, z] as Vector3;
|
|
352
|
-
const rgbResult = multiply(XYZD65_TO_SRGB_MATRIX, xyzInput);
|
|
353
|
-
return rgbResult;
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
export function xyzd50TosRGBLinear(x: number, y: number, z: number): [number, number, number] {
|
|
357
|
-
const xyzInput = [x, y, z] as Vector3;
|
|
358
|
-
const rgbResult = multiply(NAMED_GAMUTS.sRGB_INVERSE, xyzInput);
|
|
359
|
-
return rgbResult;
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
export function srgbLinearToXyzd50(r: number, g: number, b: number): [number, number, number] {
|
|
363
|
-
const rgbInput = [r, g, b] as Vector3;
|
|
364
|
-
const xyzOutput = multiply(NAMED_GAMUTS.sRGB, rgbInput);
|
|
365
|
-
return xyzOutput;
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
export function srgbToXyzd50(r: number, g: number, b: number): [number, number, number] {
|
|
369
|
-
const [mappedR, mappedG, mappedB] = applyTransferFns(NAMED_TRANSFER_FN.sRGB, r, g, b);
|
|
370
|
-
const rgbInput = [mappedR, mappedG, mappedB] as Vector3;
|
|
371
|
-
const xyzOutput = multiply(NAMED_GAMUTS.sRGB, rgbInput);
|
|
372
|
-
return xyzOutput;
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
export function xyzd50ToSrgb(x: number, y: number, z: number): [number, number, number] {
|
|
376
|
-
const xyzInput = [x, y, z] as Vector3;
|
|
377
|
-
const rgbOutput = multiply(NAMED_GAMUTS.sRGB_INVERSE, xyzInput);
|
|
378
|
-
return applyTransferFns(
|
|
379
|
-
NAMED_TRANSFER_FN.sRGB_INVERSE, rgbOutput[0], rgbOutput[1], rgbOutput[2]);
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
export function oklchToXyzd50(lInput: number, c: number, h: number): [number, number, number] {
|
|
383
|
-
const [l, a, b] = lchToLab(lInput, c, h);
|
|
384
|
-
const [x65, y65, z65] = oklabToXyzd65(l, a, b);
|
|
385
|
-
return xyzd65ToD50(x65, y65, z65);
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
export function xyzd50ToOklch(x: number, y: number, z: number): [number, number, number] {
|
|
389
|
-
const [x65, y65, z65] = xyzd50ToD65(x, y, z);
|
|
390
|
-
const [l, a, b] = xyzd65ToOklab(x65, y65, z65);
|
|
391
|
-
return labToLch(l, a, b);
|
|
392
|
-
}
|
package/src/core.ts
DELETED
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import { cast, get, set } from './bit';
|
|
2
|
-
|
|
3
|
-
export type Color = number;
|
|
4
|
-
|
|
5
|
-
export const OFFSET_R = 24;
|
|
6
|
-
export const OFFSET_G = 16;
|
|
7
|
-
export const OFFSET_B = 8;
|
|
8
|
-
export const OFFSET_A = 0;
|
|
9
|
-
|
|
10
|
-
export function newColor(r: number, g: number, b: number, a: number) {
|
|
11
|
-
return (
|
|
12
|
-
(r << OFFSET_R) +
|
|
13
|
-
(g << OFFSET_G) +
|
|
14
|
-
(b << OFFSET_B) +
|
|
15
|
-
(a << OFFSET_A)
|
|
16
|
-
);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export function from(hex: number) {
|
|
20
|
-
return newColor(
|
|
21
|
-
get(hex, OFFSET_R),
|
|
22
|
-
get(hex, OFFSET_G),
|
|
23
|
-
get(hex, OFFSET_B),
|
|
24
|
-
get(hex, OFFSET_A),
|
|
25
|
-
);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export function toNumber(color: Color) {
|
|
29
|
-
return cast(color);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export function getRed(c: Color) { return get(c, OFFSET_R); }
|
|
33
|
-
export function getGreen(c: Color) { return get(c, OFFSET_G); }
|
|
34
|
-
export function getBlue(c: Color) { return get(c, OFFSET_B); }
|
|
35
|
-
export function getAlpha(c: Color) { return get(c, OFFSET_A); }
|
|
36
|
-
|
|
37
|
-
export function setRed(c: Color, value: number) { return set(c, OFFSET_R, value); }
|
|
38
|
-
export function setGreen(c: Color, value: number) { return set(c, OFFSET_G, value); }
|
|
39
|
-
export function setBlue(c: Color, value: number) { return set(c, OFFSET_B, value); }
|
|
40
|
-
export function setAlpha(c: Color, value: number) { return set(c, OFFSET_A, value); }
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Map 8-bits value to its hexadecimal representation
|
|
44
|
-
* ['00', '01', '02', ..., 'fe', 'ff']
|
|
45
|
-
*/
|
|
46
|
-
const FORMAT_HEX =
|
|
47
|
-
Array.from({ length: 256 })
|
|
48
|
-
.map((_, byte) => byte.toString(16).padStart(2, '0'))
|
|
49
|
-
|
|
50
|
-
export function format(color: Color): string {
|
|
51
|
-
/*
|
|
52
|
-
* Implementing this as `cast(color).toString(16).padStart(8, '0')` would be simpler,
|
|
53
|
-
* but `cast()` makes the color a non-Smi value on V8, as well as allocates more strings
|
|
54
|
-
* and makes more function calls.
|
|
55
|
-
* This version is about 4 times faster than the simple one.
|
|
56
|
-
*/
|
|
57
|
-
return '#' + FORMAT_HEX[getRed(color)] + FORMAT_HEX[getGreen(color)] + FORMAT_HEX[getBlue(color)] + FORMAT_HEX[getAlpha(color)];
|
|
58
|
-
}
|
package/src/functions.ts
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Color,
|
|
3
|
-
getRed,
|
|
4
|
-
getGreen,
|
|
5
|
-
getBlue,
|
|
6
|
-
} from './core';
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* The relative brightness of any point in a color space, normalized to 0 for
|
|
10
|
-
* darkest black and 1 for lightest white.
|
|
11
|
-
* Formula: https://www.w3.org/TR/WCAG20-TECHS/G17.html#G17-tests
|
|
12
|
-
* @returns The relative brightness of the color in the range 0 - 1
|
|
13
|
-
*/
|
|
14
|
-
export function getLuminance(color: Color) {
|
|
15
|
-
const r = getRed(color) / 255;
|
|
16
|
-
const g = getGreen(color) / 255;
|
|
17
|
-
const b = getBlue(color) / 255;
|
|
18
|
-
|
|
19
|
-
const apply = (v: number) => v <= 0.03928 ? v / 12.92 : ((v + 0.055) / 1.055) ** 2.4;
|
|
20
|
-
|
|
21
|
-
const r1 = apply(r)
|
|
22
|
-
const g1 = apply(g)
|
|
23
|
-
const b1 = apply(b)
|
|
24
|
-
|
|
25
|
-
// Truncate at 3 digits
|
|
26
|
-
return Number((0.2126 * r1 + 0.7152 * g1 + 0.0722 * b1).toFixed(3));
|
|
27
|
-
}
|