color-bits 1.1.0 → 1.2.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/.claude/settings.local.json +9 -0
- package/README.md +30 -14
- package/benchmarks/compare-oklab.ts +44 -0
- package/benchmarks/compare-srgb.ts +59 -0
- package/benchmarks/compare.ts +46 -0
- package/benchmarks/parse.ts +41 -0
- package/build/conversion/channels.d.ts +61 -0
- package/build/conversion/channels.js +353 -0
- package/build/conversion/channels.js.map +1 -0
- package/build/{convert.d.ts → conversion/color-spaces.d.ts} +25 -23
- package/build/conversion/color-spaces.js +263 -0
- package/build/conversion/color-spaces.js.map +1 -0
- package/build/core/bits.d.ts +28 -0
- package/build/{core.js → core/bits.js} +25 -26
- package/build/core/bits.js.map +1 -0
- package/build/core/bytes.d.ts +5 -0
- package/build/core/bytes.js +12 -0
- package/build/core/bytes.js.map +1 -0
- package/build/css.d.ts +1 -0
- package/build/css.js +18 -0
- package/build/css.js.map +1 -0
- package/build/formatting/index.d.ts +27 -0
- package/build/{format.js → formatting/index.js} +13 -67
- package/build/formatting/index.js.map +1 -0
- package/build/index.d.ts +6 -4
- package/build/index.js +6 -4
- package/build/index.js.map +1 -1
- package/build/namedColors.d.ts +1 -0
- package/build/namedColors.js +18 -0
- package/build/namedColors.js.map +1 -0
- package/build/operations/adjust.d.ts +19 -0
- package/build/operations/adjust.js +40 -0
- package/build/operations/adjust.js.map +1 -0
- package/build/operations/blend.d.ts +9 -0
- package/build/operations/blend.js +19 -0
- package/build/operations/blend.js.map +1 -0
- package/build/operations/color-mix.d.ts +20 -0
- package/build/operations/color-mix.js +144 -0
- package/build/operations/color-mix.js.map +1 -0
- package/build/operations/luminance.d.ts +7 -0
- package/build/operations/luminance.js +20 -0
- package/build/operations/luminance.js.map +1 -0
- package/build/parsing/calc.d.ts +8 -0
- package/build/parsing/calc.js +205 -0
- package/build/parsing/calc.js.map +1 -0
- package/build/parsing/color-mix.d.ts +8 -0
- package/build/parsing/color-mix.js +70 -0
- package/build/parsing/color-mix.js.map +1 -0
- package/build/parsing/css.d.ts +23 -0
- package/build/parsing/css.js +115 -0
- package/build/parsing/css.js.map +1 -0
- package/build/parsing/fast.d.ts +19 -0
- package/build/parsing/fast.js +184 -0
- package/build/parsing/fast.js.map +1 -0
- package/build/parsing/named-colors.d.ts +12 -0
- package/build/parsing/named-colors.js +68 -0
- package/build/parsing/named-colors.js.map +1 -0
- package/build/parsing/relative.d.ts +9 -0
- package/build/parsing/relative.js +158 -0
- package/build/parsing/relative.js.map +1 -0
- package/build/parsing/tokenizer.d.ts +16 -0
- package/build/parsing/tokenizer.js +78 -0
- package/build/parsing/tokenizer.js.map +1 -0
- package/build/parsing/values.d.ts +41 -0
- package/build/parsing/values.js +139 -0
- package/build/parsing/values.js.map +1 -0
- package/package.json +30 -12
- package/benchmarks/index.ts +0 -35
- package/build/bit.d.ts +0 -3
- package/build/bit.js +0 -29
- package/build/bit.js.map +0 -1
- package/build/convert.js +0 -347
- package/build/convert.js.map +0 -1
- package/build/core.d.ts +0 -27
- package/build/core.js.map +0 -1
- package/build/format.d.ts +0 -27
- package/build/format.js.map +0 -1
- package/build/functions.d.ts +0 -33
- package/build/functions.js +0 -95
- package/build/functions.js.map +0 -1
- package/build/parse.d.ts +0 -17
- package/build/parse.js +0 -392
- package/build/parse.js.map +0 -1
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
<b>High-performance color library</b>
|
|
7
7
|
</p>
|
|
8
8
|
|
|
9
|
-
This library represents RGBA colors as a single `int32` number and avoids allocating memory as much as possible while parsing, handling, and formatting colors, to provide the best possible memory and CPU efficiency.
|
|
9
|
+
This library represents RGBA colors as a single `int32` number and avoids allocating memory as much as possible while parsing, handling, and formatting colors, to provide the best possible memory and CPU efficiency. For a full technical overview, [read the blog post](https://romgrk.com/posts/color-bits/).
|
|
10
10
|
|
|
11
11
|
<p align="center">
|
|
12
12
|
<a href="#-benchmarks">Benchmarks</a> •
|
|
@@ -24,11 +24,13 @@ This library represents RGBA colors as a single `int32` number and avoids alloca
|
|
|
24
24
|
|
|
25
25
|
| Library | Operations/sec | Relative speed |
|
|
26
26
|
| --- | --: | --- |
|
|
27
|
-
| **color-bits** | **
|
|
28
|
-
|
|
|
29
|
-
|
|
|
30
|
-
|
|
|
31
|
-
|
|
|
27
|
+
| **color-bits** | **84 428 994** | fastest |
|
|
28
|
+
| @texel/color | 7 160 587 | 91.52% slower |
|
|
29
|
+
| colord | 6 604 745 | 92.18% slower |
|
|
30
|
+
| culori | 5 223 367 | 93.81% slower |
|
|
31
|
+
| tinycolor2 | 2 479 660 | 97.06% slower |
|
|
32
|
+
| color | 1 440 968 | 98.29% slower |
|
|
33
|
+
| chroma-js | 1 348 236 | 98.40% slower |
|
|
32
34
|
|
|
33
35
|
### 🛠️ Install
|
|
34
36
|
|
|
@@ -36,19 +38,29 @@ This library represents RGBA colors as a single `int32` number and avoids alloca
|
|
|
36
38
|
pnpm install color-bits
|
|
37
39
|
```
|
|
38
40
|
|
|
39
|
-
### 📑
|
|
41
|
+
### 📑 Usage
|
|
40
42
|
|
|
41
|
-
|
|
43
|
+
The fast `Color.parse` supports the full **CSS Color Module Level 4** color spaces in **absolute** representations (`#hex`, `rgb()`, `hsl()`, `hwb()`, `lab()`, `lch()`, `oklab()`, `oklch()`, `color()`).
|
|
42
44
|
|
|
43
|
-
`color-
|
|
44
|
-
- Yes: `oklab(59.69% 0.1007 0.1191)`
|
|
45
|
-
- No: `oklab(from green l a b / 0.5)`
|
|
45
|
+
Named colors, **relative** colors and `color-mix()` are supported through `parseCSS()` from the separate `color-bits/css` entry, which is slower and bigger. If you don't need those features, go for `parse()`.
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
```tsx
|
|
48
|
+
import { parseCSS } from 'color-bits/css'
|
|
49
|
+
|
|
50
|
+
parseCSS('rebeccapurple') // named colors
|
|
51
|
+
parseCSS('oklab(from green l a b / 0.5)') // relative colors
|
|
52
|
+
parseCSS('hsl(from red calc(h + 120) s l)') // relative colors with calc()
|
|
53
|
+
parseCSS('color-mix(in oklch, red 40%, blue)') // color-mix()
|
|
54
|
+
|
|
55
|
+
// currentColor / system colors need context, passed via `resolve`:
|
|
56
|
+
parseCSS('currentColor', { resolve: () => getComputedStyle(el).color })
|
|
57
|
+
```
|
|
48
58
|
|
|
49
|
-
For performance reasons, the representation is `int32`, not `uint32`. It is expected if you see negative numbers when you print the color value.
|
|
59
|
+
**WARNING**: Due to the compact representation, `color-bits` preserves **at most 8 bits of precision for each channel**, so an operation like `lighten(color, 0.000001)` would simply return the same color with no modification. For performance reasons, the color representation is `int32`, not `uint32`. **It is expected if you see negative numbers when you print the raw color value**. Use the formatting functions to transform the color representation back into a usable format.
|
|
50
60
|
|
|
51
|
-
|
|
61
|
+
The named-color table lives in its own `color-bits/named` entry (`resolveNamed`, `namedColors`), and `color-mix` is also exposed programmatically over parsed colors from `color-bits/css`.
|
|
62
|
+
|
|
63
|
+
Every function is tree-shakeable, so the bundle size cost should be from 1.5kb to 3kb, depending on which functions you use. `parseCSS` and the named-color table are only pulled into your bundle if you import them.
|
|
52
64
|
|
|
53
65
|
### 📚 Documentation
|
|
54
66
|
|
|
@@ -73,6 +85,10 @@ import * as Color from 'color-bits/string'
|
|
|
73
85
|
const output = Color.alpha('#232323', 0.5) // #RRGGBBAA string
|
|
74
86
|
```
|
|
75
87
|
|
|
88
|
+
### Color conversion & gamut-mapping
|
|
89
|
+
|
|
90
|
+
When parsing and converting non-sRGB color spaces, `color-bits` behaves the same as browsers (Chrome in particular) do, which differs from the formal CSS spec! In technical terms: non-sRGB color spaces with a wider gamut are converted using clipping rather than gamut-mapping.
|
|
91
|
+
|
|
76
92
|
### 📜 License
|
|
77
93
|
|
|
78
94
|
I release any of the code I wrote here to the public domain. Feel free to copy/paste in part or in full without attribution.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import b from 'benny'
|
|
2
|
+
import { alpha as colorBitsAlpha } from '../src/string'
|
|
3
|
+
import chroma from 'chroma-js'
|
|
4
|
+
import { parse as culoriParse, formatHex8 as culoriFormatHex8 } from 'culori'
|
|
5
|
+
|
|
6
|
+
const input = 'oklab(40.1% 0.1143 0.045)'
|
|
7
|
+
|
|
8
|
+
async function main() {
|
|
9
|
+
// @texel/color is ESM-only; load it dynamically so this file still runs under tsx's CJS.
|
|
10
|
+
const { parse: texelParse, sRGB, RGBToHex } = (await import('@texel/color')) as any
|
|
11
|
+
|
|
12
|
+
b.suite(
|
|
13
|
+
'Parse an OKLab color, set to 0.5 opacity, and convert back to hexadecimal',
|
|
14
|
+
|
|
15
|
+
b.add('color-bits', () => {
|
|
16
|
+
colorBitsAlpha(input, 0.5)
|
|
17
|
+
}),
|
|
18
|
+
|
|
19
|
+
b.add('chroma-js', () => {
|
|
20
|
+
chroma(input).alpha(0.5).hex()
|
|
21
|
+
}),
|
|
22
|
+
|
|
23
|
+
b.add('culori', () => {
|
|
24
|
+
const parsed = culoriParse(input)!
|
|
25
|
+
parsed.alpha = 0.5
|
|
26
|
+
culoriFormatHex8(parsed)
|
|
27
|
+
}),
|
|
28
|
+
|
|
29
|
+
b.add('@texel/color', () => {
|
|
30
|
+
const rgb = texelParse(input, sRGB)
|
|
31
|
+
rgb[3] = 0.5
|
|
32
|
+
RGBToHex(rgb)
|
|
33
|
+
}),
|
|
34
|
+
|
|
35
|
+
b.cycle(),
|
|
36
|
+
b.complete((summary: any) => {
|
|
37
|
+
for (const r of summary.results) {
|
|
38
|
+
console.log(`RESULT ${r.name.padEnd(14)} ${Math.round(r.ops).toString().padStart(12)} ops/s`)
|
|
39
|
+
}
|
|
40
|
+
}),
|
|
41
|
+
)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
main()
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import b from 'benny'
|
|
2
|
+
import { alpha as colorBitsAlpha } from '../src/string'
|
|
3
|
+
import { colord } from 'colord'
|
|
4
|
+
import tinycolor2 from 'tinycolor2'
|
|
5
|
+
import color from 'color'
|
|
6
|
+
import chroma from 'chroma-js'
|
|
7
|
+
import { parse as culoriParse, formatHex8 as culoriFormatHex8 } from 'culori'
|
|
8
|
+
|
|
9
|
+
const input = '#808080'
|
|
10
|
+
|
|
11
|
+
async function main() {
|
|
12
|
+
// @texel/color is ESM-only; load it dynamically so this file still runs under tsx's CJS.
|
|
13
|
+
const { hexToRGB, RGBToHex } = (await import('@texel/color')) as any
|
|
14
|
+
|
|
15
|
+
b.suite(
|
|
16
|
+
`Parse color, set to 0.5 opacity, and convert back to hexadecimal`,
|
|
17
|
+
|
|
18
|
+
b.add('color-bits', () => {
|
|
19
|
+
colorBitsAlpha(input, 0.5)
|
|
20
|
+
}),
|
|
21
|
+
|
|
22
|
+
b.add('colord', () => {
|
|
23
|
+
colord(input).alpha(0.5).toHex()
|
|
24
|
+
}),
|
|
25
|
+
|
|
26
|
+
b.add('color', () => {
|
|
27
|
+
color(input).alpha(0.5).hex()
|
|
28
|
+
}),
|
|
29
|
+
|
|
30
|
+
b.add('tinycolor2', () => {
|
|
31
|
+
tinycolor2(input).setAlpha(0.5).toHexString()
|
|
32
|
+
}),
|
|
33
|
+
|
|
34
|
+
b.add('chroma-js', () => {
|
|
35
|
+
chroma(input).alpha(0.5).hex()
|
|
36
|
+
}),
|
|
37
|
+
|
|
38
|
+
b.add('culori', () => {
|
|
39
|
+
const parsed = culoriParse(input)!
|
|
40
|
+
parsed.alpha = 0.5
|
|
41
|
+
culoriFormatHex8(parsed)
|
|
42
|
+
}),
|
|
43
|
+
|
|
44
|
+
b.add('@texel/color', () => {
|
|
45
|
+
const rgb = hexToRGB(input)
|
|
46
|
+
rgb[3] = 0.5
|
|
47
|
+
RGBToHex(rgb)
|
|
48
|
+
}),
|
|
49
|
+
|
|
50
|
+
b.cycle(),
|
|
51
|
+
b.complete((summary: any) => {
|
|
52
|
+
for (const r of summary.results) {
|
|
53
|
+
console.log(`RESULT ${r.name.padEnd(14)} ${Math.round(r.ops).toString().padStart(12)} ops/s`)
|
|
54
|
+
}
|
|
55
|
+
}),
|
|
56
|
+
)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
main()
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { parse } from '../src/index'
|
|
2
|
+
|
|
3
|
+
// Deterministic best-of-N micro-benchmark for one case, run in an isolated
|
|
4
|
+
// process to avoid cross-case JIT pollution. Usage:
|
|
5
|
+
// tsx benchmarks/compare.ts <case-name>
|
|
6
|
+
// Compare before/after a refactor by running it, then `git stash` + run again.
|
|
7
|
+
|
|
8
|
+
const cases: Record<string, string> = {
|
|
9
|
+
'hex-short': '#59f',
|
|
10
|
+
'hex': '#5599ff',
|
|
11
|
+
'hex-alpha': '#5599ff88',
|
|
12
|
+
'rgb': 'rgb(255 153 85)',
|
|
13
|
+
'rgb-legacy': 'rgb(255, 153, 85)',
|
|
14
|
+
'rgb-alpha': 'rgb(255 153 85 / 50%)',
|
|
15
|
+
'hsl': 'hsl(50deg 80% 40%)',
|
|
16
|
+
'hwb': 'hwb(50deg 30% 40%)',
|
|
17
|
+
'lab': 'lab(50% 40 59.5)',
|
|
18
|
+
'lch': 'lch(52.2% 72.2 50)',
|
|
19
|
+
'oklab': 'oklab(40.1% 0.1143 0.045)',
|
|
20
|
+
'oklch': 'oklch(40.1% 0.123 21.57)',
|
|
21
|
+
'color-srgb': 'color(srgb 1 0.5 0)',
|
|
22
|
+
'color-p3': 'color(display-p3 1 0.5 0)',
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const name = process.argv[2]
|
|
26
|
+
const input = cases[name]
|
|
27
|
+
if (!input) { console.error(`unknown case: ${name}`); process.exit(1) }
|
|
28
|
+
|
|
29
|
+
const ITERATIONS = 1_000_000
|
|
30
|
+
const TRIALS = 15
|
|
31
|
+
let sink = 0
|
|
32
|
+
|
|
33
|
+
// warmup
|
|
34
|
+
for (let i = 0; i < 200_000; i++) sink ^= parse(input)
|
|
35
|
+
|
|
36
|
+
let best = Infinity
|
|
37
|
+
for (let t = 0; t < TRIALS; t++) {
|
|
38
|
+
const start = process.hrtime.bigint()
|
|
39
|
+
for (let i = 0; i < ITERATIONS; i++) sink ^= parse(input)
|
|
40
|
+
const ns = Number(process.hrtime.bigint() - start)
|
|
41
|
+
if (ns < best) best = ns
|
|
42
|
+
}
|
|
43
|
+
const opsPerSec = Math.round((ITERATIONS / best) * 1e9)
|
|
44
|
+
console.log(`RESULT ${name.padEnd(12)} ${opsPerSec.toString().padStart(12)} ops/s`)
|
|
45
|
+
|
|
46
|
+
if (sink === 42) console.log('') // prevent dead-code elimination
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import b from 'benny'
|
|
2
|
+
import { parse } from '../src/index'
|
|
3
|
+
|
|
4
|
+
// Benchmarks the `parse` fast path across every absolute representation.
|
|
5
|
+
// Used as the regression gate for the channels.ts refactor: the hex hot path
|
|
6
|
+
// must stay flat, and the function parsers must not regress.
|
|
7
|
+
|
|
8
|
+
const cases: Record<string, string> = {
|
|
9
|
+
'hex-short': '#59f',
|
|
10
|
+
'hex': '#5599ff',
|
|
11
|
+
'hex-alpha': '#5599ff88',
|
|
12
|
+
'rgb': 'rgb(255 153 85)',
|
|
13
|
+
'rgb-legacy': 'rgb(255, 153, 85)',
|
|
14
|
+
'rgb-alpha': 'rgb(255 153 85 / 50%)',
|
|
15
|
+
'hsl': 'hsl(50deg 80% 40%)',
|
|
16
|
+
'hwb': 'hwb(50deg 30% 40%)',
|
|
17
|
+
'lab': 'lab(50% 40 59.5)',
|
|
18
|
+
'lch': 'lch(52.2% 72.2 50)',
|
|
19
|
+
'oklab': 'oklab(40.1% 0.1143 0.045)',
|
|
20
|
+
'oklch': 'oklch(40.1% 0.123 21.57)',
|
|
21
|
+
'color-srgb': 'color(srgb 1 0.5 0)',
|
|
22
|
+
'color-p3': 'color(display-p3 1 0.5 0)',
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// XOR results into a sink so the (pure, number-returning) parse call cannot be
|
|
26
|
+
// dead-code-eliminated, which would inflate ops/s and hide regressions.
|
|
27
|
+
let sink = 0
|
|
28
|
+
|
|
29
|
+
b.suite(
|
|
30
|
+
'Color.parse() — absolute representations',
|
|
31
|
+
...Object.entries(cases).map(([name, input]) =>
|
|
32
|
+
b.add(name, () => { sink ^= parse(input) })
|
|
33
|
+
),
|
|
34
|
+
b.cycle(),
|
|
35
|
+
b.complete((summary) => {
|
|
36
|
+
for (const r of summary.results) {
|
|
37
|
+
console.log(`RESULT ${r.name.padEnd(12)} ${Math.round(r.ops).toString().padStart(12)} ops/s`)
|
|
38
|
+
}
|
|
39
|
+
if (sink === 42) console.log('')
|
|
40
|
+
}),
|
|
41
|
+
)
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { ColorBits } from '../core/bits';
|
|
2
|
+
/** Build ColorBits from sRGB components in [0, 1] and an alpha byte (0..255). */
|
|
3
|
+
export declare function srgbToColor(r: number, g: number, b: number, a: number): ColorBits;
|
|
4
|
+
/**
|
|
5
|
+
* @param h degrees, any value (wrapped by 360°)
|
|
6
|
+
* @param s nominally 0..100 (clamped)
|
|
7
|
+
* @param l nominally 0..100 (clamped)
|
|
8
|
+
* @param a alpha byte
|
|
9
|
+
*/
|
|
10
|
+
export declare function hslToColor(h: number, s: number, l: number, a: number): ColorBits;
|
|
11
|
+
/** @param sRGB in [0, 1] @returns out as [h degrees, s 0..100, l 0..100] */
|
|
12
|
+
export declare function srgbToHsl(r: number, g: number, b: number, out: Float64Array): Float64Array;
|
|
13
|
+
/**
|
|
14
|
+
* @param h degrees, any value (wrapped by 360°)
|
|
15
|
+
* @param w nominally 0..100 (clamped)
|
|
16
|
+
* @param b nominally 0..100 (clamped)
|
|
17
|
+
* @param a alpha byte
|
|
18
|
+
*/
|
|
19
|
+
export declare function hwbToColor(h: number, w: number, b: number, a: number): ColorBits;
|
|
20
|
+
/** @param sRGB in [0, 1] @returns out as [h degrees, w 0..100, b 0..100] */
|
|
21
|
+
export declare function srgbToHwb(r: number, g: number, b: number, out: Float64Array): Float64Array;
|
|
22
|
+
/** @param l 0..100 @param a raw @param b raw @param alpha alpha byte */
|
|
23
|
+
export declare function labToColor(l: number, a: number, b: number, alpha: number): ColorBits;
|
|
24
|
+
/** @param sRGB in [0, 1] @returns out as [l 0..100, a raw, b raw] */
|
|
25
|
+
export declare function srgbToLab(r: number, g: number, b: number, out: Float64Array): Float64Array;
|
|
26
|
+
/** @param l 0..100 @param c raw @param h degrees @param alpha alpha byte */
|
|
27
|
+
export declare function lchToColor(l: number, c: number, h: number, alpha: number): ColorBits;
|
|
28
|
+
/** @param sRGB in [0, 1] @returns out as [l 0..100, c raw, h degrees] */
|
|
29
|
+
export declare function srgbToLch(r: number, g: number, b: number, out: Float64Array): Float64Array;
|
|
30
|
+
/** @param l 0..1 @param a raw @param b raw @param alpha alpha byte */
|
|
31
|
+
export declare function oklabToColor(l: number, a: number, b: number, alpha: number): ColorBits;
|
|
32
|
+
/** @param sRGB in [0, 1] @returns out as [l 0..1, a raw, b raw] */
|
|
33
|
+
export declare function srgbToOklab(r: number, g: number, b: number, out: Float64Array): Float64Array;
|
|
34
|
+
/** @param l 0..1 @param c raw @param h degrees @param alpha alpha byte */
|
|
35
|
+
export declare function oklchToColor(l: number, c: number, h: number, alpha: number): ColorBits;
|
|
36
|
+
/** @param sRGB in [0, 1] @returns out as [l 0..1, c raw, h degrees] */
|
|
37
|
+
export declare function srgbToOklch(r: number, g: number, b: number, out: Float64Array): Float64Array;
|
|
38
|
+
/** Channel keywords exposed by color(from <origin> <space> …) per color space. */
|
|
39
|
+
export declare function colorSpaceChannels(space: string): string[] | null;
|
|
40
|
+
/** @param channels in 0..1 @returns out as sRGB in [0, 1], or null for an unknown space */
|
|
41
|
+
export declare function colorSpaceToSrgb(space: string, c1: number, c2: number, c3: number, out: Float64Array): Float64Array | null;
|
|
42
|
+
/** @param channels in 0..1 @returns ColorBits, or null for an unknown space */
|
|
43
|
+
export declare function colorSpaceToColor(space: string, c1: number, c2: number, c3: number, alpha: number): ColorBits | null;
|
|
44
|
+
/** @param sRGB in [0, 1] @returns out as the space's channels in 0..1, or null for an unknown space */
|
|
45
|
+
export declare function srgbToColorSpace(space: string, r: number, g: number, b: number, out: Float64Array): Float64Array | null;
|
|
46
|
+
export interface ColorModel {
|
|
47
|
+
keys: [string, string, string];
|
|
48
|
+
/** percentage reference per channel (e.g. 100 for lab L, 360 for hues) */
|
|
49
|
+
ranges: [number, number, number];
|
|
50
|
+
/** whether each channel is a hue angle */
|
|
51
|
+
hues: [boolean, boolean, boolean];
|
|
52
|
+
/** sRGB in [0, 1] -> the model's keyword-unit channels, written into `out` and returned */
|
|
53
|
+
fromSrgb: (r: number, g: number, b: number, out: Float64Array) => Float64Array;
|
|
54
|
+
/** keyword-unit channels + alpha byte -> ColorBits */
|
|
55
|
+
toColor: (c1: number, c2: number, c3: number, alpha: number) => ColorBits;
|
|
56
|
+
}
|
|
57
|
+
/** Model for a color-model name (hsl, oklch, …), or null. Own-key lookup so
|
|
58
|
+
* that Object.prototype names ('constructor', '__proto__') are not models. */
|
|
59
|
+
export declare function colorModel(name: string): ColorModel | null;
|
|
60
|
+
/** Model for a color() predefined space (channels in 0..1), or null. */
|
|
61
|
+
export declare function colorSpaceModel(space: string): ColorModel | null;
|