@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,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 断言一个数值是有限数字。
|
|
3
|
+
*/
|
|
4
|
+
export const internalAssertFinite = (value: number, name: string): void => {
|
|
5
|
+
if (Number.isFinite(value) === false) {
|
|
6
|
+
throw new RangeError(`${name} must be a finite number`)
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* 断言一个数值是非负有限数字。
|
|
12
|
+
*/
|
|
13
|
+
export const internalAssertNonNegativeFinite = (value: number, name: string): void => {
|
|
14
|
+
internalAssertFinite(value, name)
|
|
15
|
+
|
|
16
|
+
if (value < 0) {
|
|
17
|
+
throw new RangeError(`${name} must be a non-negative finite number`)
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* 断言一个颜色单位值位于 `0` 到 `1` 之间。
|
|
23
|
+
*/
|
|
24
|
+
export const internalAssertColorUnit = (value: number, unitName: string): void => {
|
|
25
|
+
if (Number.isFinite(value) === false || value < 0 || value > 1) {
|
|
26
|
+
throw new RangeError(`Color ${unitName} must be a finite number between 0 and 1`)
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* 断言一个透明度值位于 `0` 到 `1` 之间。
|
|
32
|
+
*/
|
|
33
|
+
export const internalAssertAlpha = (value: number): void => {
|
|
34
|
+
internalAssertColorUnit(value, "alpha")
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* 将浮点数按颜色计算常用精度进行圆整。
|
|
39
|
+
*/
|
|
40
|
+
export const internalRoundColorFloat = (value: number): number => {
|
|
41
|
+
return Number(value.toFixed(6))
|
|
42
|
+
}
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import { createSrgbColorValue } from "./construct.ts"
|
|
2
|
+
import { internalAssertColorUnit } from "../internal.ts"
|
|
3
|
+
import { linearRgbColorValueToXyzColorValue } from "../xyz/convert.ts"
|
|
4
|
+
import { srgbColorValueToLinearRgbColorValue } from "./convert.ts"
|
|
5
|
+
import {
|
|
6
|
+
xyzColorValueToRelativeLuminance,
|
|
7
|
+
xyzColorValueToTristimulusSum,
|
|
8
|
+
xyzColorValueToXyChromaticityValue,
|
|
9
|
+
} from "../xyz/analyze.ts"
|
|
10
|
+
|
|
11
|
+
import type {
|
|
12
|
+
LinearRgbColorValue,
|
|
13
|
+
SrgbColorValue,
|
|
14
|
+
XyChromaticityValue,
|
|
15
|
+
} from "../types.ts"
|
|
16
|
+
|
|
17
|
+
const internalDefaultDarkSrgbColorValue: SrgbColorValue = { red: 0, green: 0, blue: 0, alpha: 1 }
|
|
18
|
+
const internalDefaultLightSrgbColorValue: SrgbColorValue = { red: 255, green: 255, blue: 255, alpha: 1 }
|
|
19
|
+
|
|
20
|
+
const internalNormalizeContrastRatio = (value: number): number => {
|
|
21
|
+
if (Number.isFinite(value) === false || value < 1) {
|
|
22
|
+
throw new RangeError("Contrast ratio must be a finite number greater than or equal to 1")
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return value
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* 读取 Linear RGB 颜色值的相对亮度。
|
|
30
|
+
*
|
|
31
|
+
* 该函数会沿合法路径 `Linear RGB -> XYZ -> luminance` 计算。
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```
|
|
35
|
+
* // Expect: 0.212673
|
|
36
|
+
* const example1 = linearRgbColorValueToRelativeLuminance({ red: 1, green: 0, blue: 0, alpha: 1 })
|
|
37
|
+
*
|
|
38
|
+
* // Expect: 1
|
|
39
|
+
* const example2 = linearRgbColorValueToRelativeLuminance({ red: 1, green: 1, blue: 1, alpha: 1 })
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
export const linearRgbColorValueToRelativeLuminance = (color: LinearRgbColorValue): number => {
|
|
43
|
+
return xyzColorValueToRelativeLuminance(linearRgbColorValueToXyzColorValue(color))
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* 读取 sRGB 颜色值的相对亮度。
|
|
48
|
+
*
|
|
49
|
+
* 该函数会沿合法路径 `sRGB -> Linear RGB -> XYZ -> luminance` 计算。
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* ```
|
|
53
|
+
* // Expect: 0.125053
|
|
54
|
+
* const example1 = srgbColorValueToRelativeLuminance({ red: 51, green: 102, blue: 153, alpha: 1 })
|
|
55
|
+
*
|
|
56
|
+
* // Expect: 1
|
|
57
|
+
* const example2 = srgbColorValueToRelativeLuminance({ red: 255, green: 255, blue: 255, alpha: 1 })
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
export const srgbColorValueToRelativeLuminance = (color: SrgbColorValue): number => {
|
|
61
|
+
return linearRgbColorValueToRelativeLuminance(srgbColorValueToLinearRgbColorValue(color))
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* 读取两个 sRGB 颜色值之间的对比度。
|
|
66
|
+
*
|
|
67
|
+
* 该函数假定输入已经是最终显示颜色;若存在透明叠加,应先完成合成。
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* ```
|
|
71
|
+
* // Expect: 21
|
|
72
|
+
* const example1 = srgbColorValuesToContrastRatio(
|
|
73
|
+
* { red: 0, green: 0, blue: 0, alpha: 1 },
|
|
74
|
+
* { red: 255, green: 255, blue: 255, alpha: 1 },
|
|
75
|
+
* )
|
|
76
|
+
*
|
|
77
|
+
* // Expect: 1
|
|
78
|
+
* const example2 = srgbColorValuesToContrastRatio(
|
|
79
|
+
* { red: 51, green: 102, blue: 153, alpha: 1 },
|
|
80
|
+
* { red: 51, green: 102, blue: 153, alpha: 1 },
|
|
81
|
+
* )
|
|
82
|
+
* ```
|
|
83
|
+
*/
|
|
84
|
+
export const srgbColorValuesToContrastRatio = (first: SrgbColorValue, second: SrgbColorValue): number => {
|
|
85
|
+
const firstLuminance = srgbColorValueToRelativeLuminance(first)
|
|
86
|
+
const secondLuminance = srgbColorValueToRelativeLuminance(second)
|
|
87
|
+
const lighterLuminance = Math.max(firstLuminance, secondLuminance)
|
|
88
|
+
const darkerLuminance = Math.min(firstLuminance, secondLuminance)
|
|
89
|
+
|
|
90
|
+
return lighterLuminance === darkerLuminance
|
|
91
|
+
? 1
|
|
92
|
+
: Number((((lighterLuminance + 0.05) / (darkerLuminance + 0.05))).toFixed(6))
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* 判断两个 sRGB 颜色值是否达到指定对比度阈值。
|
|
97
|
+
*
|
|
98
|
+
* 该函数假定输入已经是最终显示颜色;若存在透明叠加,应先完成合成。
|
|
99
|
+
*
|
|
100
|
+
* @example
|
|
101
|
+
* ```
|
|
102
|
+
* // Expect: true
|
|
103
|
+
* const example1 = doSrgbColorValuesMeetContrastRatio(
|
|
104
|
+
* { red: 0, green: 0, blue: 0, alpha: 1 },
|
|
105
|
+
* { red: 255, green: 255, blue: 255, alpha: 1 },
|
|
106
|
+
* 4.5,
|
|
107
|
+
* )
|
|
108
|
+
*
|
|
109
|
+
* // Expect: false
|
|
110
|
+
* const example2 = doSrgbColorValuesMeetContrastRatio(
|
|
111
|
+
* { red: 120, green: 120, blue: 120, alpha: 1 },
|
|
112
|
+
* { red: 255, green: 255, blue: 255, alpha: 1 },
|
|
113
|
+
* 4.5,
|
|
114
|
+
* )
|
|
115
|
+
* ```
|
|
116
|
+
*/
|
|
117
|
+
export const doSrgbColorValuesMeetContrastRatio = (first: SrgbColorValue, second: SrgbColorValue, minimumContrastRatio = 4.5): boolean => {
|
|
118
|
+
return srgbColorValuesToContrastRatio(first, second) >= internalNormalizeContrastRatio(minimumContrastRatio)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* 为给定背景色选择更可读的黑色或白色文本颜色。
|
|
123
|
+
*
|
|
124
|
+
* 该函数假定背景色已经是最终显示颜色。
|
|
125
|
+
*
|
|
126
|
+
* @example
|
|
127
|
+
* ```
|
|
128
|
+
* // Expect: { red: 255, green: 255, blue: 255, alpha: 1 }
|
|
129
|
+
* const example1 = pickReadableSrgbTextColorValue({ red: 0, green: 102, blue: 204, alpha: 1 })
|
|
130
|
+
*
|
|
131
|
+
* // Expect: { red: 0, green: 0, blue: 0, alpha: 1 }
|
|
132
|
+
* const example2 = pickReadableSrgbTextColorValue({ red: 250, green: 240, blue: 210, alpha: 1 })
|
|
133
|
+
* ```
|
|
134
|
+
*/
|
|
135
|
+
export const pickReadableSrgbTextColorValue = (
|
|
136
|
+
backgroundColor: SrgbColorValue,
|
|
137
|
+
options: { darkColor?: SrgbColorValue, lightColor?: SrgbColorValue } = {},
|
|
138
|
+
): SrgbColorValue => {
|
|
139
|
+
const normalizedDarkColor = createSrgbColorValue(options.darkColor ?? internalDefaultDarkSrgbColorValue)
|
|
140
|
+
const normalizedLightColor = createSrgbColorValue(options.lightColor ?? internalDefaultLightSrgbColorValue)
|
|
141
|
+
const darkContrastRatio = srgbColorValuesToContrastRatio(normalizedDarkColor, backgroundColor)
|
|
142
|
+
const lightContrastRatio = srgbColorValuesToContrastRatio(normalizedLightColor, backgroundColor)
|
|
143
|
+
|
|
144
|
+
return lightContrastRatio > darkContrastRatio ? normalizedLightColor : normalizedDarkColor
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* 读取 Linear RGB 颜色值沿合法路径得到的三刺激总量。
|
|
149
|
+
*
|
|
150
|
+
* 该函数会沿合法路径 `Linear RGB -> XYZ -> tristimulus sum` 计算。
|
|
151
|
+
*
|
|
152
|
+
* @example
|
|
153
|
+
* ```
|
|
154
|
+
* // Expect: 0.644463
|
|
155
|
+
* const example1 = linearRgbColorValueToTristimulusSum({ red: 1, green: 0, blue: 0, alpha: 1 })
|
|
156
|
+
*
|
|
157
|
+
* // Expect: 3.0393
|
|
158
|
+
* const example2 = linearRgbColorValueToTristimulusSum({ red: 1, green: 1, blue: 1, alpha: 1 })
|
|
159
|
+
* ```
|
|
160
|
+
*/
|
|
161
|
+
export const linearRgbColorValueToTristimulusSum = (color: LinearRgbColorValue): number => {
|
|
162
|
+
return xyzColorValueToTristimulusSum(linearRgbColorValueToXyzColorValue(color))
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* 读取 sRGB 颜色值沿合法路径得到的三刺激总量。
|
|
167
|
+
*
|
|
168
|
+
* 该函数会沿合法路径 `sRGB -> Linear RGB -> XYZ -> tristimulus sum` 计算。
|
|
169
|
+
*
|
|
170
|
+
* @example
|
|
171
|
+
* ```
|
|
172
|
+
* // Expect: 0.562889
|
|
173
|
+
* const example1 = srgbColorValueToTristimulusSum({ red: 51, green: 102, blue: 153, alpha: 1 })
|
|
174
|
+
*
|
|
175
|
+
* // Expect: 3.0393
|
|
176
|
+
* const example2 = srgbColorValueToTristimulusSum({ red: 255, green: 255, blue: 255, alpha: 1 })
|
|
177
|
+
* ```
|
|
178
|
+
*/
|
|
179
|
+
export const srgbColorValueToTristimulusSum = (color: SrgbColorValue): number => {
|
|
180
|
+
return linearRgbColorValueToTristimulusSum(srgbColorValueToLinearRgbColorValue(color))
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* 读取 Linear RGB 颜色值沿合法路径得到的 `xy` 色度坐标。
|
|
185
|
+
*
|
|
186
|
+
* 该函数会沿合法路径 `Linear RGB -> XYZ -> xy chromaticity` 计算。
|
|
187
|
+
*
|
|
188
|
+
* @example
|
|
189
|
+
* ```
|
|
190
|
+
* // Expect: { x: 0.64, y: 0.33 }
|
|
191
|
+
* const example1 = linearRgbColorValueToXyChromaticityValue({ red: 1, green: 0, blue: 0, alpha: 1 })
|
|
192
|
+
*
|
|
193
|
+
* // Expect: { x: 0.312727, y: 0.329023 }
|
|
194
|
+
* const example2 = linearRgbColorValueToXyChromaticityValue({ red: 1, green: 1, blue: 1, alpha: 1 })
|
|
195
|
+
* ```
|
|
196
|
+
*/
|
|
197
|
+
export const linearRgbColorValueToXyChromaticityValue = (color: LinearRgbColorValue): XyChromaticityValue => {
|
|
198
|
+
return xyzColorValueToXyChromaticityValue(linearRgbColorValueToXyzColorValue(color))
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* 读取 sRGB 颜色值沿合法路径得到的 `xy` 色度坐标。
|
|
203
|
+
*
|
|
204
|
+
* 该函数会沿合法路径 `sRGB -> Linear RGB -> XYZ -> xy chromaticity` 计算。
|
|
205
|
+
*
|
|
206
|
+
* @example
|
|
207
|
+
* ```
|
|
208
|
+
* // Expect: { x: 0.210775, y: 0.222163 }
|
|
209
|
+
* const example1 = srgbColorValueToXyChromaticityValue({ red: 51, green: 102, blue: 153, alpha: 1 })
|
|
210
|
+
*
|
|
211
|
+
* // Expect: { x: 0.312727, y: 0.329023 }
|
|
212
|
+
* const example2 = srgbColorValueToXyChromaticityValue({ red: 255, green: 255, blue: 255, alpha: 1 })
|
|
213
|
+
* ```
|
|
214
|
+
*/
|
|
215
|
+
export const srgbColorValueToXyChromaticityValue = (color: SrgbColorValue): XyChromaticityValue => {
|
|
216
|
+
return linearRgbColorValueToXyChromaticityValue(srgbColorValueToLinearRgbColorValue(color))
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* 判断一个 sRGB 颜色值是否可视为亮色。
|
|
221
|
+
*
|
|
222
|
+
* 阈值位于 `0` 到 `1` 之间,判断依据是相对亮度。
|
|
223
|
+
*
|
|
224
|
+
* @example
|
|
225
|
+
* ```
|
|
226
|
+
* // Expect: true
|
|
227
|
+
* const example1 = isLightSrgbColorValue({ red: 255, green: 255, blue: 255, alpha: 1 })
|
|
228
|
+
*
|
|
229
|
+
* // Expect: false
|
|
230
|
+
* const example2 = isLightSrgbColorValue({ red: 0, green: 0, blue: 0, alpha: 1 })
|
|
231
|
+
* ```
|
|
232
|
+
*/
|
|
233
|
+
export const isLightSrgbColorValue = (color: SrgbColorValue, threshold = 0.5): boolean => {
|
|
234
|
+
internalAssertColorUnit(threshold, "threshold")
|
|
235
|
+
return srgbColorValueToRelativeLuminance(createSrgbColorValue(color)) >= threshold
|
|
236
|
+
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import {
|
|
2
|
+
internalGetStableSrgbColorValueByString,
|
|
3
|
+
internalNormalizeHslColorValue,
|
|
4
|
+
internalNormalizeHsvColorValue,
|
|
5
|
+
internalNormalizeLinearRgbColorValue,
|
|
6
|
+
internalNormalizeSrgbColorValue,
|
|
7
|
+
} from "./internal.ts"
|
|
8
|
+
import {
|
|
9
|
+
srgbColorValueToHslColorValue,
|
|
10
|
+
srgbColorValueToHsvColorValue,
|
|
11
|
+
} from "./convert.ts"
|
|
12
|
+
|
|
13
|
+
import type {
|
|
14
|
+
HslColorValue,
|
|
15
|
+
HsvColorValue,
|
|
16
|
+
LinearRgbColorValue,
|
|
17
|
+
SrgbColorValue,
|
|
18
|
+
} from "../types.ts"
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* 构造一个 Linear RGB 颜色值对象。
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```
|
|
25
|
+
* // Expect: { red: 0.2, green: 0.4, blue: 0.6, alpha: 1 }
|
|
26
|
+
* const example1 = createLinearRgbColorValue({ red: 0.2, green: 0.4, blue: 0.6, alpha: 1 })
|
|
27
|
+
*
|
|
28
|
+
* // Expect: { red: -0.25, green: 0.4, blue: 1.2, alpha: 0.5 }
|
|
29
|
+
* const example2 = createLinearRgbColorValue({ red: -0.25, green: 0.4, blue: 1.2, alpha: 0.5 })
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export const createLinearRgbColorValue = (color: LinearRgbColorValue): LinearRgbColorValue => {
|
|
33
|
+
return internalNormalizeLinearRgbColorValue(color)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* 构造一个 sRGB 颜色值对象。
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```
|
|
41
|
+
* // Expect: { red: 51, green: 102, blue: 153, alpha: 1 }
|
|
42
|
+
* const example1 = createSrgbColorValue({ red: 51, green: 102, blue: 153, alpha: 1 })
|
|
43
|
+
*
|
|
44
|
+
* // Expect: { red: 255, green: 255, blue: 255, alpha: 0.5 }
|
|
45
|
+
* const example2 = createSrgbColorValue({ red: 255, green: 255, blue: 255, alpha: 0.5 })
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
export const createSrgbColorValue = (color: SrgbColorValue): SrgbColorValue => {
|
|
49
|
+
return internalNormalizeSrgbColorValue(color)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* 构造一个 HSL 颜色值对象。
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* ```
|
|
57
|
+
* // Expect: { hue: 330, saturation: 0.5, lightness: 0.4, alpha: 1 }
|
|
58
|
+
* const example1 = createHslColorValue({ hue: -30, saturation: 0.5, lightness: 0.4, alpha: 1 })
|
|
59
|
+
*
|
|
60
|
+
* // Expect: { hue: 0, saturation: 0, lightness: 1, alpha: 0.5 }
|
|
61
|
+
* const example2 = createHslColorValue({ hue: 360, saturation: 0, lightness: 1, alpha: 0.5 })
|
|
62
|
+
* ```
|
|
63
|
+
*/
|
|
64
|
+
export const createHslColorValue = (color: HslColorValue): HslColorValue => {
|
|
65
|
+
return internalNormalizeHslColorValue(color)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* 构造一个 HSV 颜色值对象。
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* ```
|
|
73
|
+
* // Expect: { hue: 330, saturation: 0.5, value: 0.6, alpha: 1 }
|
|
74
|
+
* const example1 = createHsvColorValue({ hue: -30, saturation: 0.5, value: 0.6, alpha: 1 })
|
|
75
|
+
*
|
|
76
|
+
* // Expect: { hue: 30, saturation: 0.5, value: 0.6, alpha: 1 }
|
|
77
|
+
* const example2 = createHsvColorValue({ hue: 390, saturation: 0.5, value: 0.6, alpha: 1 })
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
export const createHsvColorValue = (color: HsvColorValue): HsvColorValue => {
|
|
81
|
+
return internalNormalizeHsvColorValue(color)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* 根据稳定字符串构造 sRGB 颜色值。
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* ```
|
|
89
|
+
* // Expect: { red: 254, green: 192, blue: 46, alpha: 1 }
|
|
90
|
+
* const example1 = createSrgbColorValueByString("mobius")
|
|
91
|
+
*
|
|
92
|
+
* // Expect: { red: 101, green: 227, blue: 144, alpha: 1 }
|
|
93
|
+
* const example2 = createSrgbColorValueByString("planet")
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
96
|
+
export const createSrgbColorValueByString = (input: string): SrgbColorValue => {
|
|
97
|
+
return internalGetStableSrgbColorValueByString(input)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* 根据稳定字符串构造 HSL 颜色值。
|
|
102
|
+
*
|
|
103
|
+
* @example
|
|
104
|
+
* ```
|
|
105
|
+
* // Expect: { hue: 42.992126, saturation: 0.991597, lightness: 0.588235, alpha: 1 }
|
|
106
|
+
* const example1 = createHslColorValueByString("mobius")
|
|
107
|
+
*
|
|
108
|
+
* // Expect: { hue: 139.777778, saturation: 0.71831, lightness: 0.643137, alpha: 1 }
|
|
109
|
+
* const example2 = createHslColorValueByString("planet")
|
|
110
|
+
* ```
|
|
111
|
+
*/
|
|
112
|
+
export const createHslColorValueByString = (input: string): HslColorValue => {
|
|
113
|
+
return srgbColorValueToHslColorValue(createSrgbColorValueByString(input))
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* 根据稳定字符串构造 HSV 颜色值。
|
|
118
|
+
*
|
|
119
|
+
* @example
|
|
120
|
+
* ```
|
|
121
|
+
* // Expect: { hue: 42.992126, saturation: 0.818898, value: 0.996078, alpha: 1 }
|
|
122
|
+
* const example1 = createHsvColorValueByString("mobius")
|
|
123
|
+
*
|
|
124
|
+
* // Expect: { hue: 139.777778, saturation: 0.555066, value: 0.890196, alpha: 1 }
|
|
125
|
+
* const example2 = createHsvColorValueByString("planet")
|
|
126
|
+
* ```
|
|
127
|
+
*/
|
|
128
|
+
export const createHsvColorValueByString = (input: string): HsvColorValue => {
|
|
129
|
+
return srgbColorValueToHsvColorValue(createSrgbColorValueByString(input))
|
|
130
|
+
}
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
import {
|
|
2
|
+
internalRoundColorFloat,
|
|
3
|
+
} from "../internal.ts"
|
|
4
|
+
import {
|
|
5
|
+
internalGetLinearRgbChannelBySrgbChannel,
|
|
6
|
+
internalGetSrgbChannelByLinearRgbChannel,
|
|
7
|
+
internalNormalizeHslColorValue,
|
|
8
|
+
internalNormalizeHsvColorValue,
|
|
9
|
+
internalNormalizeLinearRgbColorValue,
|
|
10
|
+
internalNormalizeSrgbColorValue,
|
|
11
|
+
} from "./internal.ts"
|
|
12
|
+
|
|
13
|
+
import type {
|
|
14
|
+
HslColorValue,
|
|
15
|
+
HsvColorValue,
|
|
16
|
+
LinearRgbColorValue,
|
|
17
|
+
SrgbColorValue,
|
|
18
|
+
} from "../types.ts"
|
|
19
|
+
|
|
20
|
+
const internalGetHueByNormalizedRgbChannels = (red: number, green: number, blue: number, delta: number, max: number): number => {
|
|
21
|
+
if (delta === 0) {
|
|
22
|
+
return 0
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
let hue = 0
|
|
26
|
+
|
|
27
|
+
if (max === red) {
|
|
28
|
+
hue = 60 * (((green - blue) / delta) % 6)
|
|
29
|
+
} else if (max === green) {
|
|
30
|
+
hue = 60 * (((blue - red) / delta) + 2)
|
|
31
|
+
} else {
|
|
32
|
+
hue = 60 * (((red - green) / delta) + 4)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (hue < 0) {
|
|
36
|
+
return hue + 360
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return hue
|
|
40
|
+
}
|
|
41
|
+
const internalGetNormalizedRgbChannelsByHue = (hue: number, chroma: number): { red: number, green: number, blue: number } => {
|
|
42
|
+
const segment = hue / 60
|
|
43
|
+
const secondary = chroma * (1 - Math.abs((segment % 2) - 1))
|
|
44
|
+
|
|
45
|
+
if (segment >= 0 && segment < 1) {
|
|
46
|
+
return { red: chroma, green: secondary, blue: 0 }
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (segment >= 1 && segment < 2) {
|
|
50
|
+
return { red: secondary, green: chroma, blue: 0 }
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (segment >= 2 && segment < 3) {
|
|
54
|
+
return { red: 0, green: chroma, blue: secondary }
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (segment >= 3 && segment < 4) {
|
|
58
|
+
return { red: 0, green: secondary, blue: chroma }
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (segment >= 4 && segment < 5) {
|
|
62
|
+
return { red: secondary, green: 0, blue: chroma }
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return { red: chroma, green: 0, blue: secondary }
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* 将 Linear RGB 颜色值转换为 sRGB 颜色值。
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* ```
|
|
73
|
+
* // Expect: { red: 255, green: 0, blue: 0, alpha: 1 }
|
|
74
|
+
* const example1 = linearRgbColorValueToSrgbColorValue({ red: 1, green: 0, blue: 0, alpha: 1 })
|
|
75
|
+
*
|
|
76
|
+
* // Expect: { red: 188, green: 188, blue: 188, alpha: 0.5 }
|
|
77
|
+
* const example2 = linearRgbColorValueToSrgbColorValue({ red: 0.5, green: 0.5, blue: 0.5, alpha: 0.5 })
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
export const linearRgbColorValueToSrgbColorValue = (color: LinearRgbColorValue): SrgbColorValue => {
|
|
81
|
+
const normalizedColor = internalNormalizeLinearRgbColorValue(color)
|
|
82
|
+
|
|
83
|
+
return internalNormalizeSrgbColorValue({
|
|
84
|
+
red: internalGetSrgbChannelByLinearRgbChannel(normalizedColor.red, "red"),
|
|
85
|
+
green: internalGetSrgbChannelByLinearRgbChannel(normalizedColor.green, "green"),
|
|
86
|
+
blue: internalGetSrgbChannelByLinearRgbChannel(normalizedColor.blue, "blue"),
|
|
87
|
+
alpha: normalizedColor.alpha,
|
|
88
|
+
})
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* 将 sRGB 颜色值转换为 Linear RGB 颜色值。
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* ```
|
|
96
|
+
* // Expect: { red: 1, green: 0, blue: 0, alpha: 1 }
|
|
97
|
+
* const example1 = srgbColorValueToLinearRgbColorValue({ red: 255, green: 0, blue: 0, alpha: 1 })
|
|
98
|
+
*
|
|
99
|
+
* // Expect: { red: 0.215861, green: 0.215861, blue: 0.215861, alpha: 0.5 }
|
|
100
|
+
* const example2 = srgbColorValueToLinearRgbColorValue({ red: 128, green: 128, blue: 128, alpha: 0.5 })
|
|
101
|
+
* ```
|
|
102
|
+
*/
|
|
103
|
+
export const srgbColorValueToLinearRgbColorValue = (color: SrgbColorValue): LinearRgbColorValue => {
|
|
104
|
+
const normalizedColor = internalNormalizeSrgbColorValue(color)
|
|
105
|
+
|
|
106
|
+
return internalNormalizeLinearRgbColorValue({
|
|
107
|
+
red: internalGetLinearRgbChannelBySrgbChannel(normalizedColor.red),
|
|
108
|
+
green: internalGetLinearRgbChannelBySrgbChannel(normalizedColor.green),
|
|
109
|
+
blue: internalGetLinearRgbChannelBySrgbChannel(normalizedColor.blue),
|
|
110
|
+
alpha: normalizedColor.alpha,
|
|
111
|
+
})
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* 将 sRGB 颜色值转换为 HSL 颜色值。
|
|
116
|
+
*
|
|
117
|
+
* @example
|
|
118
|
+
* ```
|
|
119
|
+
* // Expect: { hue: 210, saturation: 0.5, lightness: 0.4, alpha: 1 }
|
|
120
|
+
* const example1 = srgbColorValueToHslColorValue({ red: 51, green: 102, blue: 153, alpha: 1 })
|
|
121
|
+
*
|
|
122
|
+
* // Expect: { hue: 0, saturation: 0, lightness: 0.501961, alpha: 1 }
|
|
123
|
+
* const example2 = srgbColorValueToHslColorValue({ red: 128, green: 128, blue: 128, alpha: 1 })
|
|
124
|
+
* ```
|
|
125
|
+
*/
|
|
126
|
+
export const srgbColorValueToHslColorValue = (color: SrgbColorValue): HslColorValue => {
|
|
127
|
+
const normalizedColor = internalNormalizeSrgbColorValue(color)
|
|
128
|
+
const red = normalizedColor.red / 255
|
|
129
|
+
const green = normalizedColor.green / 255
|
|
130
|
+
const blue = normalizedColor.blue / 255
|
|
131
|
+
const max = Math.max(red, green, blue)
|
|
132
|
+
const min = Math.min(red, green, blue)
|
|
133
|
+
const delta = max - min
|
|
134
|
+
const lightness = (max + min) / 2
|
|
135
|
+
const saturation = delta === 0 ? 0 : delta / (1 - Math.abs((2 * lightness) - 1))
|
|
136
|
+
const hue = internalGetHueByNormalizedRgbChannels(red, green, blue, delta, max)
|
|
137
|
+
|
|
138
|
+
return internalNormalizeHslColorValue({
|
|
139
|
+
hue: internalRoundColorFloat(hue),
|
|
140
|
+
saturation: internalRoundColorFloat(saturation),
|
|
141
|
+
lightness: internalRoundColorFloat(lightness),
|
|
142
|
+
alpha: normalizedColor.alpha,
|
|
143
|
+
})
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* 将 HSL 颜色值转换为 sRGB 颜色值。
|
|
148
|
+
*
|
|
149
|
+
* @example
|
|
150
|
+
* ```
|
|
151
|
+
* // Expect: { red: 51, green: 102, blue: 153, alpha: 1 }
|
|
152
|
+
* const example1 = hslColorValueToSrgbColorValue({ hue: 210, saturation: 0.5, lightness: 0.4, alpha: 1 })
|
|
153
|
+
*
|
|
154
|
+
* // Expect: { red: 128, green: 128, blue: 128, alpha: 1 }
|
|
155
|
+
* const example2 = hslColorValueToSrgbColorValue({ hue: 0, saturation: 0, lightness: 0.501961, alpha: 1 })
|
|
156
|
+
* ```
|
|
157
|
+
*/
|
|
158
|
+
export const hslColorValueToSrgbColorValue = (color: HslColorValue): SrgbColorValue => {
|
|
159
|
+
const normalizedColor = internalNormalizeHslColorValue(color)
|
|
160
|
+
const chroma = (1 - Math.abs((2 * normalizedColor.lightness) - 1)) * normalizedColor.saturation
|
|
161
|
+
const channels = internalGetNormalizedRgbChannelsByHue(normalizedColor.hue, chroma)
|
|
162
|
+
const match = normalizedColor.lightness - (chroma / 2)
|
|
163
|
+
|
|
164
|
+
return internalNormalizeSrgbColorValue({
|
|
165
|
+
red: Math.round((channels.red + match) * 255),
|
|
166
|
+
green: Math.round((channels.green + match) * 255),
|
|
167
|
+
blue: Math.round((channels.blue + match) * 255),
|
|
168
|
+
alpha: normalizedColor.alpha,
|
|
169
|
+
})
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* 将 sRGB 颜色值转换为 HSV 颜色值。
|
|
174
|
+
*
|
|
175
|
+
* @example
|
|
176
|
+
* ```
|
|
177
|
+
* // Expect: { hue: 210, saturation: 0.666667, value: 0.6, alpha: 1 }
|
|
178
|
+
* const example1 = srgbColorValueToHsvColorValue({ red: 51, green: 102, blue: 153, alpha: 1 })
|
|
179
|
+
*
|
|
180
|
+
* // Expect: { hue: 0, saturation: 0, value: 0.501961, alpha: 1 }
|
|
181
|
+
* const example2 = srgbColorValueToHsvColorValue({ red: 128, green: 128, blue: 128, alpha: 1 })
|
|
182
|
+
* ```
|
|
183
|
+
*/
|
|
184
|
+
export const srgbColorValueToHsvColorValue = (color: SrgbColorValue): HsvColorValue => {
|
|
185
|
+
const normalizedColor = internalNormalizeSrgbColorValue(color)
|
|
186
|
+
const red = normalizedColor.red / 255
|
|
187
|
+
const green = normalizedColor.green / 255
|
|
188
|
+
const blue = normalizedColor.blue / 255
|
|
189
|
+
const max = Math.max(red, green, blue)
|
|
190
|
+
const min = Math.min(red, green, blue)
|
|
191
|
+
const delta = max - min
|
|
192
|
+
const saturation = max === 0 ? 0 : delta / max
|
|
193
|
+
const hue = internalGetHueByNormalizedRgbChannels(red, green, blue, delta, max)
|
|
194
|
+
|
|
195
|
+
return internalNormalizeHsvColorValue({
|
|
196
|
+
hue: internalRoundColorFloat(hue),
|
|
197
|
+
saturation: internalRoundColorFloat(saturation),
|
|
198
|
+
value: internalRoundColorFloat(max),
|
|
199
|
+
alpha: normalizedColor.alpha,
|
|
200
|
+
})
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* 将 HSV 颜色值转换为 sRGB 颜色值。
|
|
205
|
+
*
|
|
206
|
+
* @example
|
|
207
|
+
* ```
|
|
208
|
+
* // Expect: { red: 51, green: 102, blue: 153, alpha: 1 }
|
|
209
|
+
* const example1 = hsvColorValueToSrgbColorValue({ hue: 210, saturation: 0.666667, value: 0.6, alpha: 1 })
|
|
210
|
+
*
|
|
211
|
+
* // Expect: { red: 128, green: 128, blue: 128, alpha: 1 }
|
|
212
|
+
* const example2 = hsvColorValueToSrgbColorValue({ hue: 0, saturation: 0, value: 0.501961, alpha: 1 })
|
|
213
|
+
* ```
|
|
214
|
+
*/
|
|
215
|
+
export const hsvColorValueToSrgbColorValue = (color: HsvColorValue): SrgbColorValue => {
|
|
216
|
+
const normalizedColor = internalNormalizeHsvColorValue(color)
|
|
217
|
+
const chroma = normalizedColor.value * normalizedColor.saturation
|
|
218
|
+
const channels = internalGetNormalizedRgbChannelsByHue(normalizedColor.hue, chroma)
|
|
219
|
+
const match = normalizedColor.value - chroma
|
|
220
|
+
|
|
221
|
+
return internalNormalizeSrgbColorValue({
|
|
222
|
+
red: Math.round((channels.red + match) * 255),
|
|
223
|
+
green: Math.round((channels.green + match) * 255),
|
|
224
|
+
blue: Math.round((channels.blue + match) * 255),
|
|
225
|
+
alpha: normalizedColor.alpha,
|
|
226
|
+
})
|
|
227
|
+
}
|