@planet-matrix/mobius-model 0.5.0 → 0.6.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/CHANGELOG.md +24 -0
- package/README.md +123 -36
- package/dist/index.js +45 -4
- package/dist/index.js.map +183 -11
- package/oxlint.config.ts +6 -0
- package/package.json +16 -10
- package/src/abort/README.md +92 -0
- package/src/abort/abort-manager.ts +278 -0
- package/src/abort/abort-signal-listener-manager.ts +81 -0
- package/src/abort/index.ts +2 -0
- package/src/basic/README.md +69 -118
- package/src/basic/function.ts +81 -62
- package/src/basic/is.ts +152 -71
- package/src/basic/promise.ts +29 -8
- package/src/basic/string.ts +2 -33
- package/src/color/README.md +105 -0
- package/src/color/index.ts +3 -0
- package/src/color/internal.ts +42 -0
- package/src/color/rgb/analyze.ts +236 -0
- package/src/color/rgb/construct.ts +130 -0
- package/src/color/rgb/convert.ts +227 -0
- package/src/color/rgb/derive.ts +303 -0
- package/src/color/rgb/index.ts +6 -0
- package/src/color/rgb/internal.ts +208 -0
- package/src/color/rgb/parse.ts +302 -0
- package/src/color/rgb/serialize.ts +144 -0
- package/src/color/types.ts +57 -0
- package/src/color/xyz/analyze.ts +80 -0
- package/src/color/xyz/construct.ts +19 -0
- package/src/color/xyz/convert.ts +71 -0
- package/src/color/xyz/index.ts +3 -0
- package/src/color/xyz/internal.ts +23 -0
- package/src/css/README.md +93 -0
- package/src/css/class.ts +559 -0
- package/src/css/index.ts +1 -0
- package/src/encoding/README.md +66 -79
- package/src/encoding/base64.ts +13 -4
- package/src/environment/README.md +97 -0
- package/src/environment/basic.ts +26 -0
- package/src/environment/device.ts +311 -0
- package/src/environment/feature.ts +285 -0
- package/src/environment/geo.ts +337 -0
- package/src/environment/index.ts +7 -0
- package/src/environment/runtime.ts +400 -0
- package/src/environment/snapshot.ts +60 -0
- package/src/environment/variable.ts +239 -0
- package/src/event/README.md +90 -0
- package/src/event/class-event-proxy.ts +228 -0
- package/src/event/common.ts +19 -0
- package/src/event/event-manager.ts +203 -0
- package/src/event/index.ts +4 -0
- package/src/event/instance-event-proxy.ts +186 -0
- package/src/event/internal.ts +24 -0
- package/src/exception/README.md +96 -0
- package/src/exception/browser.ts +219 -0
- package/src/exception/index.ts +4 -0
- package/src/exception/nodejs.ts +169 -0
- package/src/exception/normalize.ts +106 -0
- package/src/exception/types.ts +99 -0
- package/src/identifier/README.md +92 -0
- package/src/identifier/id.ts +119 -0
- package/src/identifier/index.ts +2 -0
- package/src/identifier/uuid.ts +187 -0
- package/src/index.ts +16 -1
- package/src/log/README.md +79 -0
- package/src/log/index.ts +5 -0
- package/src/log/log-emitter.ts +72 -0
- package/src/log/log-record.ts +10 -0
- package/src/log/log-scheduler.ts +74 -0
- package/src/log/log-type.ts +8 -0
- package/src/log/logger.ts +543 -0
- package/src/orchestration/README.md +89 -0
- package/src/orchestration/coordination/barrier.ts +214 -0
- package/src/orchestration/coordination/count-down-latch.ts +215 -0
- package/src/orchestration/coordination/errors.ts +98 -0
- package/src/orchestration/coordination/index.ts +16 -0
- package/src/orchestration/coordination/internal/wait-constraints.ts +95 -0
- package/src/orchestration/coordination/internal/wait-queue.ts +109 -0
- package/src/orchestration/coordination/keyed-lock.ts +168 -0
- package/src/orchestration/coordination/mutex.ts +257 -0
- package/src/orchestration/coordination/permit.ts +127 -0
- package/src/orchestration/coordination/read-write-lock.ts +444 -0
- package/src/orchestration/coordination/semaphore.ts +280 -0
- package/src/orchestration/index.ts +1 -0
- package/src/random/README.md +55 -86
- package/src/random/index.ts +1 -1
- package/src/random/string.ts +35 -0
- package/src/reactor/README.md +4 -0
- package/src/reactor/reactor-core/primitive.ts +9 -9
- package/src/reactor/reactor-core/reactive-system.ts +5 -5
- package/src/singleton/README.md +79 -0
- package/src/singleton/factory.ts +55 -0
- package/src/singleton/index.ts +2 -0
- package/src/singleton/manager.ts +204 -0
- package/src/storage/README.md +107 -0
- package/src/storage/index.ts +1 -0
- package/src/storage/table.ts +449 -0
- package/src/timer/README.md +86 -0
- package/src/timer/expiration/expiration-manager.ts +594 -0
- package/src/timer/expiration/index.ts +3 -0
- package/src/timer/expiration/min-heap.ts +208 -0
- package/src/timer/expiration/remaining-manager.ts +241 -0
- package/src/timer/index.ts +1 -0
- package/src/type/README.md +54 -307
- package/src/type/class.ts +2 -2
- package/src/type/index.ts +14 -14
- package/src/type/is.ts +265 -2
- package/src/type/object.ts +37 -0
- package/src/type/string.ts +7 -2
- package/src/type/tuple.ts +6 -6
- package/src/type/union.ts +16 -0
- package/src/web/README.md +77 -0
- package/src/web/capture.ts +35 -0
- package/src/web/clipboard.ts +97 -0
- package/src/web/dom.ts +117 -0
- package/src/web/download.ts +16 -0
- package/src/web/event.ts +46 -0
- package/src/web/index.ts +10 -0
- package/src/web/local-storage.ts +113 -0
- package/src/web/location.ts +28 -0
- package/src/web/permission.ts +172 -0
- package/src/web/script-loader.ts +432 -0
- package/tests/unit/abort/abort-manager.spec.ts +225 -0
- package/tests/unit/abort/abort-signal-listener-manager.spec.ts +62 -0
- package/tests/unit/basic/array.spec.ts +1 -1
- package/tests/unit/basic/stream.spec.ts +1 -1
- package/tests/unit/basic/string.spec.ts +0 -9
- package/tests/unit/color/rgb/analyze.spec.ts +110 -0
- package/tests/unit/color/rgb/construct.spec.ts +56 -0
- package/tests/unit/color/rgb/convert.spec.ts +60 -0
- package/tests/unit/color/rgb/derive.spec.ts +103 -0
- package/tests/unit/color/rgb/parse.spec.ts +66 -0
- package/tests/unit/color/rgb/serialize.spec.ts +46 -0
- package/tests/unit/color/xyz/analyze.spec.ts +33 -0
- package/tests/unit/color/xyz/construct.spec.ts +10 -0
- package/tests/unit/color/xyz/convert.spec.ts +18 -0
- package/tests/unit/css/class.spec.ts +157 -0
- package/tests/unit/environment/basic.spec.ts +20 -0
- package/tests/unit/environment/device.spec.ts +146 -0
- package/tests/unit/environment/feature.spec.ts +388 -0
- package/tests/unit/environment/geo.spec.ts +111 -0
- package/tests/unit/environment/runtime.spec.ts +364 -0
- package/tests/unit/environment/snapshot.spec.ts +4 -0
- package/tests/unit/environment/variable.spec.ts +190 -0
- package/tests/unit/event/class-event-proxy.spec.ts +225 -0
- package/tests/unit/event/event-manager.spec.ts +246 -0
- package/tests/unit/event/instance-event-proxy.spec.ts +187 -0
- package/tests/unit/exception/browser.spec.ts +213 -0
- package/tests/unit/exception/nodejs.spec.ts +144 -0
- package/tests/unit/exception/normalize.spec.ts +57 -0
- package/tests/unit/identifier/id.spec.ts +71 -0
- package/tests/unit/identifier/uuid.spec.ts +85 -0
- package/tests/unit/log/log-emitter.spec.ts +33 -0
- package/tests/unit/log/log-scheduler.spec.ts +40 -0
- package/tests/unit/log/log-type.spec.ts +7 -0
- package/tests/unit/log/logger.spec.ts +222 -0
- package/tests/unit/orchestration/coordination/barrier.spec.ts +96 -0
- package/tests/unit/orchestration/coordination/count-down-latch.spec.ts +63 -0
- package/tests/unit/orchestration/coordination/errors.spec.ts +29 -0
- package/tests/unit/orchestration/coordination/keyed-lock.spec.ts +109 -0
- package/tests/unit/orchestration/coordination/mutex.spec.ts +132 -0
- package/tests/unit/orchestration/coordination/permit.spec.ts +43 -0
- package/tests/unit/orchestration/coordination/read-write-lock.spec.ts +154 -0
- package/tests/unit/orchestration/coordination/semaphore.spec.ts +135 -0
- package/tests/unit/random/string.spec.ts +11 -0
- package/tests/unit/reactor/alien-signals-effect.spec.ts +11 -10
- package/tests/unit/reactor/preact-signal.spec.ts +1 -2
- package/tests/unit/singleton/singleton.spec.ts +49 -0
- package/tests/unit/storage/table.spec.ts +620 -0
- package/tests/unit/timer/expiration/expiration-manager.spec.ts +464 -0
- package/tests/unit/timer/expiration/min-heap.spec.ts +71 -0
- package/tests/unit/timer/expiration/remaining-manager.spec.ts +234 -0
- package/.oxlintrc.json +0 -5
- package/src/random/uuid.ts +0 -103
- package/tests/unit/random/uuid.spec.ts +0 -37
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
import { internalAssertAlpha } from "../internal.ts"
|
|
2
|
+
import {
|
|
3
|
+
createHslColorValue,
|
|
4
|
+
createHsvColorValue,
|
|
5
|
+
createSrgbColorValue,
|
|
6
|
+
} from "./construct.ts"
|
|
7
|
+
import {
|
|
8
|
+
hslColorValueToSrgbColorValue,
|
|
9
|
+
hsvColorValueToSrgbColorValue,
|
|
10
|
+
} from "./convert.ts"
|
|
11
|
+
import {
|
|
12
|
+
internalExpandShortHex,
|
|
13
|
+
internalHexPattern,
|
|
14
|
+
internalParsePercentUnit,
|
|
15
|
+
internalParseRgbChannel,
|
|
16
|
+
} from "./internal.ts"
|
|
17
|
+
|
|
18
|
+
import type {
|
|
19
|
+
HslColorValue,
|
|
20
|
+
HsvColorValue,
|
|
21
|
+
SrgbColorValue,
|
|
22
|
+
} from "../types.ts"
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* 判断输入是否为合法的十六进制颜色字符串。
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```
|
|
29
|
+
* // Expect: true
|
|
30
|
+
* const example1 = isHexColorString("#F0A")
|
|
31
|
+
*
|
|
32
|
+
* // Expect: false
|
|
33
|
+
* const example2 = isHexColorString("#12")
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
export const isHexColorString = (input: string): boolean => {
|
|
37
|
+
return internalHexPattern.test(input.trim())
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* 将十六进制颜色字符串解析为 sRGB 颜色值对象。
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```
|
|
45
|
+
* // Expect: { red: 255, green: 0, blue: 170, alpha: 1 }
|
|
46
|
+
* const example1 = hexColorStringToSrgbColorValue("#F0A")
|
|
47
|
+
*
|
|
48
|
+
* // Expect: { red: 17, green: 34, blue: 51, alpha: 0.2667 }
|
|
49
|
+
* const example2 = hexColorStringToSrgbColorValue("#11223344")
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
export const hexColorStringToSrgbColorValue = (input: string): SrgbColorValue => {
|
|
53
|
+
const normalizedInput = input.trim()
|
|
54
|
+
if (isHexColorString(normalizedInput) === false) {
|
|
55
|
+
throw new TypeError("Invalid hex color input")
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const hex = normalizedInput.startsWith("#") ? normalizedInput.slice(1) : normalizedInput
|
|
59
|
+
const expandedHex = hex.length === 3 || hex.length === 4 ? internalExpandShortHex(hex) : hex
|
|
60
|
+
const red = Number.parseInt(expandedHex.slice(0, 2), 16)
|
|
61
|
+
const green = Number.parseInt(expandedHex.slice(2, 4), 16)
|
|
62
|
+
const blue = Number.parseInt(expandedHex.slice(4, 6), 16)
|
|
63
|
+
const alpha = expandedHex.length === 8
|
|
64
|
+
? Number((Number.parseInt(expandedHex.slice(6, 8), 16) / 255).toFixed(4))
|
|
65
|
+
: 1
|
|
66
|
+
|
|
67
|
+
return createSrgbColorValue({ red, green, blue, alpha })
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const internalParseRgbParts = (input: string, allowAlpha: boolean): SrgbColorValue => {
|
|
71
|
+
const rgbMatch = /^rgba?\((.*)\)$/i.exec(input)
|
|
72
|
+
if (rgbMatch === null) {
|
|
73
|
+
throw new TypeError("Invalid color string input")
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const partsSource = rgbMatch[1]
|
|
77
|
+
if (partsSource === undefined) {
|
|
78
|
+
throw new TypeError("Invalid color string input")
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const parts = partsSource.split(",").map(part => part.trim())
|
|
82
|
+
if (allowAlpha === true && parts.length !== 4) {
|
|
83
|
+
throw new TypeError("Invalid RGBA color string input")
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (allowAlpha === false && parts.length !== 3) {
|
|
87
|
+
throw new TypeError("Invalid RGB color string input")
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const [redPart = "", greenPart = "", bluePart = "", alphaPart] = parts
|
|
91
|
+
const red = internalParseRgbChannel(redPart, "red")
|
|
92
|
+
const green = internalParseRgbChannel(greenPart, "green")
|
|
93
|
+
const blue = internalParseRgbChannel(bluePart, "blue")
|
|
94
|
+
const alpha = allowAlpha === true ? Number(alphaPart) : 1
|
|
95
|
+
|
|
96
|
+
return createSrgbColorValue({ red, green, blue, alpha })
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* 将 `rgb(r, g, b)` 字符串解析为 sRGB 颜色值对象。
|
|
101
|
+
*
|
|
102
|
+
* @example
|
|
103
|
+
* ```
|
|
104
|
+
* // Expect: { red: 51, green: 102, blue: 153, alpha: 1 }
|
|
105
|
+
* const example1 = rgbColorStringToSrgbColorValue("rgb(51, 102, 153)")
|
|
106
|
+
*
|
|
107
|
+
* // Expect: { red: 0, green: 0, blue: 0, alpha: 1 }
|
|
108
|
+
* const example2 = rgbColorStringToSrgbColorValue("rgb(0, 0, 0)")
|
|
109
|
+
* ```
|
|
110
|
+
*/
|
|
111
|
+
export const rgbColorStringToSrgbColorValue = (input: string): SrgbColorValue => {
|
|
112
|
+
return internalParseRgbParts(input.trim(), false)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* 将 `rgba(r, g, b, a)` 字符串解析为 sRGB 颜色值对象。
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* ```
|
|
120
|
+
* // Expect: { red: 51, green: 102, blue: 153, alpha: 0.5 }
|
|
121
|
+
* const example1 = rgbaColorStringToSrgbColorValue("rgba(51, 102, 153, 0.5)")
|
|
122
|
+
*
|
|
123
|
+
* // Expect: { red: 255, green: 255, blue: 255, alpha: 1 }
|
|
124
|
+
* const example2 = rgbaColorStringToSrgbColorValue("rgba(255, 255, 255, 1)")
|
|
125
|
+
* ```
|
|
126
|
+
*/
|
|
127
|
+
export const rgbaColorStringToSrgbColorValue = (input: string): SrgbColorValue => {
|
|
128
|
+
return internalParseRgbParts(input.trim(), true)
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const internalParseHslParts = (input: string, allowAlpha: boolean): HslColorValue => {
|
|
132
|
+
const hslMatch = /^hsla?\((.*)\)$/i.exec(input)
|
|
133
|
+
if (hslMatch === null) {
|
|
134
|
+
throw new TypeError("Invalid color string input")
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const partsSource = hslMatch[1]
|
|
138
|
+
if (partsSource === undefined) {
|
|
139
|
+
throw new TypeError("Invalid color string input")
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const parts = partsSource.split(",").map(part => part.trim())
|
|
143
|
+
if (allowAlpha === true && parts.length !== 4) {
|
|
144
|
+
throw new TypeError("Invalid HSLA color string input")
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (allowAlpha === false && parts.length !== 3) {
|
|
148
|
+
throw new TypeError("Invalid HSL color string input")
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const [huePart = "", saturationPart = "", lightnessPart = "", alphaPart] = parts
|
|
152
|
+
const hue = Number(huePart)
|
|
153
|
+
const saturation = internalParsePercentUnit(saturationPart, "saturation")
|
|
154
|
+
const lightness = internalParsePercentUnit(lightnessPart, "lightness")
|
|
155
|
+
const alpha = allowAlpha === true ? Number(alphaPart) : 1
|
|
156
|
+
internalAssertAlpha(alpha)
|
|
157
|
+
|
|
158
|
+
return createHslColorValue({ hue, saturation, lightness, alpha })
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* 将 `hsl(h, s%, l%)` 字符串解析为 HSL 颜色值对象。
|
|
163
|
+
*
|
|
164
|
+
* @example
|
|
165
|
+
* ```
|
|
166
|
+
* // Expect: { hue: 210, saturation: 0.5, lightness: 0.4, alpha: 1 }
|
|
167
|
+
* const example1 = hslColorStringToHslColorValue("hsl(210, 50%, 40%)")
|
|
168
|
+
*
|
|
169
|
+
* // Expect: { hue: 330, saturation: 0.5, lightness: 0.4, alpha: 1 }
|
|
170
|
+
* const example2 = hslColorStringToHslColorValue("hsl(-30, 50%, 40%)")
|
|
171
|
+
* ```
|
|
172
|
+
*/
|
|
173
|
+
export const hslColorStringToHslColorValue = (input: string): HslColorValue => {
|
|
174
|
+
return internalParseHslParts(input.trim(), false)
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* 将 `hsla(h, s%, l%, a)` 字符串解析为 HSL 颜色值对象。
|
|
179
|
+
*
|
|
180
|
+
* @example
|
|
181
|
+
* ```
|
|
182
|
+
* // Expect: { hue: 210, saturation: 0.5, lightness: 0.4, alpha: 0.5 }
|
|
183
|
+
* const example1 = hslaColorStringToHslColorValue("hsla(210, 50%, 40%, 0.5)")
|
|
184
|
+
*
|
|
185
|
+
* // Expect: { hue: 0, saturation: 0, lightness: 1, alpha: 1 }
|
|
186
|
+
* const example2 = hslaColorStringToHslColorValue("hsla(0, 0%, 100%, 1)")
|
|
187
|
+
* ```
|
|
188
|
+
*/
|
|
189
|
+
export const hslaColorStringToHslColorValue = (input: string): HslColorValue => {
|
|
190
|
+
return internalParseHslParts(input.trim(), true)
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const internalParseHsvParts = (input: string, allowAlpha: boolean): HsvColorValue => {
|
|
194
|
+
const hsvMatch = /^hsva?\((.*)\)$/i.exec(input)
|
|
195
|
+
if (hsvMatch === null) {
|
|
196
|
+
throw new TypeError("Invalid color string input")
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const partsSource = hsvMatch[1]
|
|
200
|
+
if (partsSource === undefined) {
|
|
201
|
+
throw new TypeError("Invalid color string input")
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const parts = partsSource.split(",").map(part => part.trim())
|
|
205
|
+
if (allowAlpha === true && parts.length !== 4) {
|
|
206
|
+
throw new TypeError("Invalid HSVA color string input")
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
if (allowAlpha === false && parts.length !== 3) {
|
|
210
|
+
throw new TypeError("Invalid HSV color string input")
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const [huePart = "", saturationPart = "", valuePart = "", alphaPart] = parts
|
|
214
|
+
const hue = Number(huePart)
|
|
215
|
+
const saturation = internalParsePercentUnit(saturationPart, "saturation")
|
|
216
|
+
const value = internalParsePercentUnit(valuePart, "value")
|
|
217
|
+
const alpha = allowAlpha === true ? Number(alphaPart) : 1
|
|
218
|
+
internalAssertAlpha(alpha)
|
|
219
|
+
|
|
220
|
+
return createHsvColorValue({ hue, saturation, value, alpha })
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* 将 `hsv(h, s%, v%)` 字符串解析为 HSV 颜色值对象。
|
|
225
|
+
*
|
|
226
|
+
* @example
|
|
227
|
+
* ```
|
|
228
|
+
* // Expect: { hue: 210, saturation: 0.6667, value: 0.6, alpha: 1 }
|
|
229
|
+
* const example1 = hsvColorStringToHsvColorValue("hsv(210, 66.67%, 60%)")
|
|
230
|
+
*
|
|
231
|
+
* // Expect: { hue: 30, saturation: 0.5, value: 0.6, alpha: 1 }
|
|
232
|
+
* const example2 = hsvColorStringToHsvColorValue("hsv(390, 50%, 60%)")
|
|
233
|
+
* ```
|
|
234
|
+
*/
|
|
235
|
+
export const hsvColorStringToHsvColorValue = (input: string): HsvColorValue => {
|
|
236
|
+
return internalParseHsvParts(input.trim(), false)
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* 将 `hsva(h, s%, v%, a)` 字符串解析为 HSV 颜色值对象。
|
|
241
|
+
*
|
|
242
|
+
* @example
|
|
243
|
+
* ```
|
|
244
|
+
* // Expect: { hue: 210, saturation: 0.6667, value: 0.6, alpha: 0.5 }
|
|
245
|
+
* const example1 = hsvaColorStringToHsvColorValue("hsva(210, 66.67%, 60%, 0.5)")
|
|
246
|
+
*
|
|
247
|
+
* // Expect: { hue: 0, saturation: 0, value: 1, alpha: 1 }
|
|
248
|
+
* const example2 = hsvaColorStringToHsvColorValue("hsva(0, 0%, 100%, 1)")
|
|
249
|
+
* ```
|
|
250
|
+
*/
|
|
251
|
+
export const hsvaColorStringToHsvColorValue = (input: string): HsvColorValue => {
|
|
252
|
+
return internalParseHsvParts(input.trim(), true)
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* 将异构颜色字符串归一化为 sRGB 颜色值对象。
|
|
257
|
+
*
|
|
258
|
+
* 这是一个面向最终显示层的归一化入口。它会有意把十六进制、RGB、HSL 与 HSV
|
|
259
|
+
* 等不同语义层的字符串统一折叠为 sRGB;如果调用方需要保留输入本身的颜色语义,
|
|
260
|
+
* 应改用对应的专用解析函数。
|
|
261
|
+
*
|
|
262
|
+
* @example
|
|
263
|
+
* ```
|
|
264
|
+
* // Expect: { red: 51, green: 102, blue: 153, alpha: 1 }
|
|
265
|
+
* const example1 = colorStringToSrgbColorValue("#336699")
|
|
266
|
+
*
|
|
267
|
+
* // Expect: { red: 51, green: 102, blue: 153, alpha: 1 }
|
|
268
|
+
* const example2 = colorStringToSrgbColorValue("hsl(210, 50%, 40%)")
|
|
269
|
+
* ```
|
|
270
|
+
*/
|
|
271
|
+
export const colorStringToSrgbColorValue = (input: string): SrgbColorValue => {
|
|
272
|
+
const normalizedInput = input.trim()
|
|
273
|
+
if (normalizedInput.startsWith("#") || isHexColorString(normalizedInput) === true) {
|
|
274
|
+
return hexColorStringToSrgbColorValue(normalizedInput)
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
if (normalizedInput.toLowerCase().startsWith("rgba(")) {
|
|
278
|
+
return rgbaColorStringToSrgbColorValue(normalizedInput)
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
if (normalizedInput.toLowerCase().startsWith("rgb(")) {
|
|
282
|
+
return rgbColorStringToSrgbColorValue(normalizedInput)
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
if (normalizedInput.toLowerCase().startsWith("hsla(")) {
|
|
286
|
+
return hslColorValueToSrgbColorValue(hslaColorStringToHslColorValue(normalizedInput))
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
if (normalizedInput.toLowerCase().startsWith("hsl(")) {
|
|
290
|
+
return hslColorValueToSrgbColorValue(hslColorStringToHslColorValue(normalizedInput))
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
if (normalizedInput.toLowerCase().startsWith("hsva(")) {
|
|
294
|
+
return hsvColorValueToSrgbColorValue(hsvaColorStringToHsvColorValue(normalizedInput))
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
if (normalizedInput.toLowerCase().startsWith("hsv(")) {
|
|
298
|
+
return hsvColorValueToSrgbColorValue(hsvColorStringToHsvColorValue(normalizedInput))
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
throw new TypeError("Invalid color string input")
|
|
302
|
+
}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createHslColorValue,
|
|
3
|
+
createHsvColorValue,
|
|
4
|
+
createSrgbColorValue,
|
|
5
|
+
} from "./construct.ts"
|
|
6
|
+
import {
|
|
7
|
+
internalFormatAlpha,
|
|
8
|
+
internalFormatHexByte,
|
|
9
|
+
internalFormatPercentUnit,
|
|
10
|
+
} from "./internal.ts"
|
|
11
|
+
|
|
12
|
+
import type {
|
|
13
|
+
HslColorValue,
|
|
14
|
+
HsvColorValue,
|
|
15
|
+
SrgbColorValue,
|
|
16
|
+
} from "../types.ts"
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* 将 sRGB 颜色值序列化为十六进制颜色字符串。
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```
|
|
23
|
+
* // Expect: #336699
|
|
24
|
+
* const example1 = srgbColorValueToHexColorString({ red: 51, green: 102, blue: 153, alpha: 0.5 })
|
|
25
|
+
*
|
|
26
|
+
* // Expect: #33669980
|
|
27
|
+
* const example2 = srgbColorValueToHexColorString({ red: 51, green: 102, blue: 153, alpha: 0.5 }, { includeAlpha: true })
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export const srgbColorValueToHexColorString = (color: SrgbColorValue, options: { includeAlpha?: boolean } = {}): string => {
|
|
31
|
+
const normalizedColor = createSrgbColorValue(color)
|
|
32
|
+
const hex = [normalizedColor.red, normalizedColor.green, normalizedColor.blue]
|
|
33
|
+
.map(value => internalFormatHexByte(value))
|
|
34
|
+
.join("")
|
|
35
|
+
|
|
36
|
+
if (options.includeAlpha === true) {
|
|
37
|
+
const alphaByte = Math.round(normalizedColor.alpha * 255)
|
|
38
|
+
return `#${hex}${internalFormatHexByte(alphaByte)}`
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return `#${hex}`
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* 将 sRGB 颜色值序列化为 `rgb(...)` 字符串。
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* ```
|
|
49
|
+
* // Expect: rgb(51, 102, 153)
|
|
50
|
+
* const example1 = srgbColorValueToRgbColorString({ red: 51, green: 102, blue: 153, alpha: 0.5 })
|
|
51
|
+
*
|
|
52
|
+
* // Expect: rgb(0, 0, 0)
|
|
53
|
+
* const example2 = srgbColorValueToRgbColorString({ red: 0, green: 0, blue: 0, alpha: 1 })
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
export const srgbColorValueToRgbColorString = (color: SrgbColorValue): string => {
|
|
57
|
+
const normalizedColor = createSrgbColorValue(color)
|
|
58
|
+
return `rgb(${normalizedColor.red}, ${normalizedColor.green}, ${normalizedColor.blue})`
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* 将 sRGB 颜色值序列化为 `rgba(...)` 字符串。
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* ```
|
|
66
|
+
* // Expect: rgba(51, 102, 153, 0.5)
|
|
67
|
+
* const example1 = srgbColorValueToRgbaColorString({ red: 51, green: 102, blue: 153, alpha: 0.5 })
|
|
68
|
+
*
|
|
69
|
+
* // Expect: rgba(255, 255, 255, 1)
|
|
70
|
+
* const example2 = srgbColorValueToRgbaColorString({ red: 255, green: 255, blue: 255, alpha: 1 })
|
|
71
|
+
* ```
|
|
72
|
+
*/
|
|
73
|
+
export const srgbColorValueToRgbaColorString = (color: SrgbColorValue): string => {
|
|
74
|
+
const normalizedColor = createSrgbColorValue(color)
|
|
75
|
+
return `rgba(${normalizedColor.red}, ${normalizedColor.green}, ${normalizedColor.blue}, ${internalFormatAlpha(normalizedColor.alpha)})`
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* 将 HSL 颜色值序列化为 `hsl(...)` 字符串。
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* ```
|
|
83
|
+
* // Expect: hsl(210, 50%, 40%)
|
|
84
|
+
* const example1 = hslColorValueToHslColorString({ hue: 210, saturation: 0.5, lightness: 0.4, alpha: 0.5 })
|
|
85
|
+
*
|
|
86
|
+
* // Expect: hsl(0, 0%, 100%)
|
|
87
|
+
* const example2 = hslColorValueToHslColorString({ hue: 0, saturation: 0, lightness: 1, alpha: 1 })
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
export const hslColorValueToHslColorString = (color: HslColorValue): string => {
|
|
91
|
+
const normalizedColor = createHslColorValue(color)
|
|
92
|
+
return `hsl(${normalizedColor.hue}, ${internalFormatPercentUnit(normalizedColor.saturation)}%, ${internalFormatPercentUnit(normalizedColor.lightness)}%)`
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* 将 HSL 颜色值序列化为 `hsla(...)` 字符串。
|
|
97
|
+
*
|
|
98
|
+
* @example
|
|
99
|
+
* ```
|
|
100
|
+
* // Expect: hsla(210, 50%, 40%, 0.5)
|
|
101
|
+
* const example1 = hslColorValueToHslaColorString({ hue: 210, saturation: 0.5, lightness: 0.4, alpha: 0.5 })
|
|
102
|
+
*
|
|
103
|
+
* // Expect: hsla(0, 0%, 100%, 1)
|
|
104
|
+
* const example2 = hslColorValueToHslaColorString({ hue: 0, saturation: 0, lightness: 1, alpha: 1 })
|
|
105
|
+
* ```
|
|
106
|
+
*/
|
|
107
|
+
export const hslColorValueToHslaColorString = (color: HslColorValue): string => {
|
|
108
|
+
const normalizedColor = createHslColorValue(color)
|
|
109
|
+
return `hsla(${normalizedColor.hue}, ${internalFormatPercentUnit(normalizedColor.saturation)}%, ${internalFormatPercentUnit(normalizedColor.lightness)}%, ${internalFormatAlpha(normalizedColor.alpha)})`
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* 将 HSV 颜色值序列化为 `hsv(...)` 字符串。
|
|
114
|
+
*
|
|
115
|
+
* @example
|
|
116
|
+
* ```
|
|
117
|
+
* // Expect: hsv(210, 66.67%, 60%)
|
|
118
|
+
* const example1 = hsvColorValueToHsvColorString({ hue: 210, saturation: 0.6667, value: 0.6, alpha: 0.5 })
|
|
119
|
+
*
|
|
120
|
+
* // Expect: hsv(0, 0%, 100%)
|
|
121
|
+
* const example2 = hsvColorValueToHsvColorString({ hue: 0, saturation: 0, value: 1, alpha: 1 })
|
|
122
|
+
* ```
|
|
123
|
+
*/
|
|
124
|
+
export const hsvColorValueToHsvColorString = (color: HsvColorValue): string => {
|
|
125
|
+
const normalizedColor = createHsvColorValue(color)
|
|
126
|
+
return `hsv(${normalizedColor.hue}, ${internalFormatPercentUnit(normalizedColor.saturation)}%, ${internalFormatPercentUnit(normalizedColor.value)}%)`
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* 将 HSV 颜色值序列化为 `hsva(...)` 字符串。
|
|
131
|
+
*
|
|
132
|
+
* @example
|
|
133
|
+
* ```
|
|
134
|
+
* // Expect: hsva(210, 66.67%, 60%, 0.5)
|
|
135
|
+
* const example1 = hsvColorValueToHsvaColorString({ hue: 210, saturation: 0.6667, value: 0.6, alpha: 0.5 })
|
|
136
|
+
*
|
|
137
|
+
* // Expect: hsva(0, 0%, 100%, 1)
|
|
138
|
+
* const example2 = hsvColorValueToHsvaColorString({ hue: 0, saturation: 0, value: 1, alpha: 1 })
|
|
139
|
+
* ```
|
|
140
|
+
*/
|
|
141
|
+
export const hsvColorValueToHsvaColorString = (color: HsvColorValue): string => {
|
|
142
|
+
const normalizedColor = createHsvColorValue(color)
|
|
143
|
+
return `hsva(${normalizedColor.hue}, ${internalFormatPercentUnit(normalizedColor.saturation)}%, ${internalFormatPercentUnit(normalizedColor.value)}%, ${internalFormatAlpha(normalizedColor.alpha)})`
|
|
144
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 表示 XYZ 颜色值结构,使用 `x`、`y`、`z` 三个通道和 `alpha` 透明度通道。
|
|
3
|
+
*/
|
|
4
|
+
export type XyzColorValue = Readonly<{
|
|
5
|
+
x: number
|
|
6
|
+
y: number
|
|
7
|
+
z: number
|
|
8
|
+
alpha: number
|
|
9
|
+
}>
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* 表示基于 XYZ 颜色值计算得到的 `xy` 色度坐标结构。
|
|
13
|
+
*/
|
|
14
|
+
export type XyChromaticityValue = Readonly<{
|
|
15
|
+
x: number
|
|
16
|
+
y: number
|
|
17
|
+
}>
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* 表示 Linear RGB 颜色值结构,使用线性 `red`、`green`、`blue` 三个通道和 `alpha` 透明度通道。
|
|
21
|
+
*/
|
|
22
|
+
export type LinearRgbColorValue = Readonly<{
|
|
23
|
+
red: number
|
|
24
|
+
green: number
|
|
25
|
+
blue: number
|
|
26
|
+
alpha: number
|
|
27
|
+
}>
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* 表示 sRGB 颜色值结构,使用 `red`、`green`、`blue` 三个 8 位通道和 `alpha` 透明度通道。
|
|
31
|
+
*/
|
|
32
|
+
export type SrgbColorValue = Readonly<{
|
|
33
|
+
red: number
|
|
34
|
+
green: number
|
|
35
|
+
blue: number
|
|
36
|
+
alpha: number
|
|
37
|
+
}>
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* 表示 HSL 颜色值结构,使用 `hue`、`saturation`、`lightness` 和 `alpha` 四个通道。
|
|
41
|
+
*/
|
|
42
|
+
export type HslColorValue = Readonly<{
|
|
43
|
+
hue: number
|
|
44
|
+
saturation: number
|
|
45
|
+
lightness: number
|
|
46
|
+
alpha: number
|
|
47
|
+
}>
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* 表示 HSV 颜色值结构,使用 `hue`、`saturation`、`value` 和 `alpha` 四个通道。
|
|
51
|
+
*/
|
|
52
|
+
export type HsvColorValue = Readonly<{
|
|
53
|
+
hue: number
|
|
54
|
+
saturation: number
|
|
55
|
+
value: number
|
|
56
|
+
alpha: number
|
|
57
|
+
}>
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { createXyzColorValue } from "./construct.ts"
|
|
2
|
+
import { internalRoundColorFloat } from "../internal.ts"
|
|
3
|
+
|
|
4
|
+
import type {
|
|
5
|
+
XyChromaticityValue,
|
|
6
|
+
XyzColorValue,
|
|
7
|
+
} from "../types.ts"
|
|
8
|
+
|
|
9
|
+
const internalGetNormalizedXyzColorData = (color: XyzColorValue): { color: XyzColorValue, tristimulusSum: number } => {
|
|
10
|
+
const normalizedColor = createXyzColorValue(color)
|
|
11
|
+
const tristimulusSum = internalRoundColorFloat(normalizedColor.x + normalizedColor.y + normalizedColor.z)
|
|
12
|
+
|
|
13
|
+
return {
|
|
14
|
+
color: normalizedColor,
|
|
15
|
+
tristimulusSum,
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* 读取 XYZ 颜色值的相对亮度。
|
|
21
|
+
*
|
|
22
|
+
* 在当前模块约定下,`Y` 通道直接表示相对亮度。
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```
|
|
26
|
+
* // Expect: 0.3
|
|
27
|
+
* const example1 = xyzColorValueToRelativeLuminance({ x: 0.25, y: 0.3, z: 0.4, alpha: 1 })
|
|
28
|
+
*
|
|
29
|
+
* // Expect: 0
|
|
30
|
+
* const example2 = xyzColorValueToRelativeLuminance({ x: 0, y: 0, z: 0, alpha: 1 })
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export const xyzColorValueToRelativeLuminance = (color: XyzColorValue): number => {
|
|
34
|
+
return createXyzColorValue(color).y
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* 读取 XYZ 颜色值的三刺激总量。
|
|
39
|
+
*
|
|
40
|
+
* 在当前模块约定下,结果等于 `x + y + z`。
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```
|
|
44
|
+
* // Expect: 0.95
|
|
45
|
+
* const example1 = xyzColorValueToTristimulusSum({ x: 0.25, y: 0.3, z: 0.4, alpha: 1 })
|
|
46
|
+
*
|
|
47
|
+
* // Expect: 0
|
|
48
|
+
* const example2 = xyzColorValueToTristimulusSum({ x: 0, y: 0, z: 0, alpha: 1 })
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
export const xyzColorValueToTristimulusSum = (color: XyzColorValue): number => {
|
|
52
|
+
return internalGetNormalizedXyzColorData(color).tristimulusSum
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* 读取 XYZ 颜色值对应的 `xy` 色度坐标。
|
|
57
|
+
*
|
|
58
|
+
* 当三刺激总量为 `0` 时,该结果没有定义,因此会抛出异常。
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* ```
|
|
62
|
+
* // Expect: { x: 0.263158, y: 0.315789 }
|
|
63
|
+
* const example1 = xyzColorValueToXyChromaticityValue({ x: 0.25, y: 0.3, z: 0.4, alpha: 1 })
|
|
64
|
+
*
|
|
65
|
+
* // Expect: { x: 0.64, y: 0.33 }
|
|
66
|
+
* const example2 = xyzColorValueToXyChromaticityValue({ x: 0.412456, y: 0.212673, z: 0.019334, alpha: 1 })
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
export const xyzColorValueToXyChromaticityValue = (color: XyzColorValue): XyChromaticityValue => {
|
|
70
|
+
const normalizedData = internalGetNormalizedXyzColorData(color)
|
|
71
|
+
|
|
72
|
+
if (normalizedData.tristimulusSum === 0) {
|
|
73
|
+
throw new RangeError("XYZ tristimulus sum must be greater than 0 to compute xy chromaticity")
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return {
|
|
77
|
+
x: internalRoundColorFloat(normalizedData.color.x / normalizedData.tristimulusSum),
|
|
78
|
+
y: internalRoundColorFloat(normalizedData.color.y / normalizedData.tristimulusSum),
|
|
79
|
+
}
|
|
80
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { internalNormalizeXyzColorValue } from "./internal.ts"
|
|
2
|
+
|
|
3
|
+
import type { XyzColorValue } from "../types.ts"
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 构造一个 XYZ 颜色值对象。
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```
|
|
10
|
+
* // Expect: { x: 0.25, y: 0.3, z: 0.4, alpha: 1 }
|
|
11
|
+
* const example1 = createXyzColorValue({ x: 0.25, y: 0.3, z: 0.4, alpha: 1 })
|
|
12
|
+
*
|
|
13
|
+
* // Expect: { x: 0, y: 0, z: 0, alpha: 0.5 }
|
|
14
|
+
* const example2 = createXyzColorValue({ x: 0, y: 0, z: 0, alpha: 0.5 })
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
export const createXyzColorValue = (color: XyzColorValue): XyzColorValue => {
|
|
18
|
+
return internalNormalizeXyzColorValue(color)
|
|
19
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { internalNormalizeXyzColorValue } from "./internal.ts"
|
|
2
|
+
import {
|
|
3
|
+
internalAssertAlpha,
|
|
4
|
+
internalAssertFinite,
|
|
5
|
+
internalRoundColorFloat,
|
|
6
|
+
} from "../internal.ts"
|
|
7
|
+
|
|
8
|
+
import type {
|
|
9
|
+
LinearRgbColorValue,
|
|
10
|
+
XyzColorValue,
|
|
11
|
+
} from "../types.ts"
|
|
12
|
+
|
|
13
|
+
const internalNormalizeLinearRgbColorValueForXyzConversion = (color: LinearRgbColorValue): LinearRgbColorValue => {
|
|
14
|
+
internalAssertFinite(color.red, "Color channel red")
|
|
15
|
+
internalAssertFinite(color.green, "Color channel green")
|
|
16
|
+
internalAssertFinite(color.blue, "Color channel blue")
|
|
17
|
+
internalAssertAlpha(color.alpha)
|
|
18
|
+
|
|
19
|
+
return {
|
|
20
|
+
red: color.red,
|
|
21
|
+
green: color.green,
|
|
22
|
+
blue: color.blue,
|
|
23
|
+
alpha: color.alpha,
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* 将 XYZ 颜色值转换为 Linear RGB 颜色值。
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```
|
|
32
|
+
* // Expect: { red: 0.2, green: 0.4, blue: 0.6, alpha: 1 }
|
|
33
|
+
* const example1 = xyzColorValueToLinearRgbColorValue({ x: 0.333784, y: 0.3719, z: 0.621726, alpha: 1 })
|
|
34
|
+
*
|
|
35
|
+
* // Expect: { red: 1, green: 0, blue: 0, alpha: 1 }
|
|
36
|
+
* const example2 = xyzColorValueToLinearRgbColorValue({ x: 0.412456, y: 0.212673, z: 0.019334, alpha: 1 })
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export const xyzColorValueToLinearRgbColorValue = (color: XyzColorValue): LinearRgbColorValue => {
|
|
40
|
+
const normalizedColor = internalNormalizeXyzColorValue(color)
|
|
41
|
+
|
|
42
|
+
return internalNormalizeLinearRgbColorValueForXyzConversion({
|
|
43
|
+
red: internalRoundColorFloat((3.240_454_2 * normalizedColor.x) - (1.537_138_5 * normalizedColor.y) - (0.498_531_4 * normalizedColor.z)),
|
|
44
|
+
green: internalRoundColorFloat((-0.969_266 * normalizedColor.x) + (1.876_010_8 * normalizedColor.y) + (0.041_556 * normalizedColor.z)),
|
|
45
|
+
blue: internalRoundColorFloat((0.055_643_4 * normalizedColor.x) - (0.204_025_9 * normalizedColor.y) + (1.057_225_2 * normalizedColor.z)),
|
|
46
|
+
alpha: normalizedColor.alpha,
|
|
47
|
+
})
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* 将 Linear RGB 颜色值转换为 XYZ 颜色值。
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```
|
|
55
|
+
* // Expect: { x: 0.333784, y: 0.3719, z: 0.621726, alpha: 1 }
|
|
56
|
+
* const example1 = linearRgbColorValueToXyzColorValue({ red: 0.2, green: 0.4, blue: 0.6, alpha: 1 })
|
|
57
|
+
*
|
|
58
|
+
* // Expect: { x: 0.412456, y: 0.212673, z: 0.019334, alpha: 1 }
|
|
59
|
+
* const example2 = linearRgbColorValueToXyzColorValue({ red: 1, green: 0, blue: 0, alpha: 1 })
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
export const linearRgbColorValueToXyzColorValue = (color: LinearRgbColorValue): XyzColorValue => {
|
|
63
|
+
const normalizedColor = internalNormalizeLinearRgbColorValueForXyzConversion(color)
|
|
64
|
+
|
|
65
|
+
return internalNormalizeXyzColorValue({
|
|
66
|
+
x: internalRoundColorFloat((0.412_456_4 * normalizedColor.red) + (0.357_576_1 * normalizedColor.green) + (0.180_437_5 * normalizedColor.blue)),
|
|
67
|
+
y: internalRoundColorFloat((0.212_672_9 * normalizedColor.red) + (0.715_152_2 * normalizedColor.green) + (0.072_175 * normalizedColor.blue)),
|
|
68
|
+
z: internalRoundColorFloat((0.019_333_9 * normalizedColor.red) + (0.119_192 * normalizedColor.green) + (0.950_304_1 * normalizedColor.blue)),
|
|
69
|
+
alpha: normalizedColor.alpha,
|
|
70
|
+
})
|
|
71
|
+
}
|