pixel-data-js 0.3.0 → 0.5.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/dist/index.dev.cjs +1405 -70
- package/dist/index.dev.cjs.map +1 -1
- package/dist/index.dev.js +1355 -68
- package/dist/index.dev.js.map +1 -1
- package/dist/index.prod.cjs +1405 -70
- package/dist/index.prod.cjs.map +1 -1
- package/dist/index.prod.d.ts +581 -64
- package/dist/index.prod.js +1355 -68
- package/dist/index.prod.js.map +1 -1
- package/package.json +14 -3
- package/src/Algorithm/floodFillSelection.ts +229 -0
- package/src/Canvas/PixelCanvas.ts +31 -0
- package/src/Canvas/ReusableCanvas.ts +44 -0
- package/src/Canvas/_constants.ts +2 -0
- package/src/Clipboard/getImageDataFromClipboard.ts +42 -0
- package/src/Clipboard/writeImageDataToClipboard.ts +25 -0
- package/src/Clipboard/writeImgBlobToClipboard.ts +13 -0
- package/src/ImageData/{extractImageData.ts → extractImageDataPixels.ts} +21 -3
- package/src/ImageData/imageDataToAlphaMask.ts +35 -0
- package/src/ImageData/imageDataToDataUrl.ts +27 -0
- package/src/ImageData/imageDataToImgBlob.ts +31 -0
- package/src/ImageData/imgBlobToImageData.ts +52 -0
- package/src/ImageData/invertImageData.ts +10 -0
- package/src/ImageData/resizeImageData.ts +75 -0
- package/src/ImageData/{writeImageData.ts → writeImageDataPixels.ts} +22 -3
- package/src/Input/fileInputChangeToImageData.ts +37 -0
- package/src/Input/fileToImageData.ts +75 -0
- package/src/Input/getSupportedRasterFormats.ts +74 -0
- package/src/Mask/extractMask.ts +86 -0
- package/src/Mask/mergeMasks.ts +1 -6
- package/src/PixelData/blendColorPixelData.ts +9 -9
- package/src/PixelData/fillPixelData.ts +51 -12
- package/src/PixelData/invertPixelData.ts +16 -0
- package/src/PixelData/pixelDataToAlphaMask.ts +28 -0
- package/src/Rect/trimRectBounds.ts +118 -0
- package/src/_types.ts +37 -20
- package/src/blend-modes.ts +506 -66
- package/src/color.ts +6 -6
- package/src/globals.d.ts +2 -0
- package/src/index.ts +37 -1
package/src/blend-modes.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { BlendColor32, Color32 } from './_types'
|
|
2
2
|
|
|
3
|
+
export const overwriteColor32: BlendColor32 = (src, dst) => src
|
|
4
|
+
|
|
3
5
|
export const sourceOverColor32: BlendColor32 = (src, dst) => {
|
|
4
6
|
const a = (src >>> 24) & 0xFF
|
|
5
7
|
if (a === 255) return src
|
|
@@ -25,9 +27,165 @@ export const sourceOverColor32: BlendColor32 = (src, dst) => {
|
|
|
25
27
|
return ((outA << 24) | outRB | outG) >>> 0 as Color32
|
|
26
28
|
}
|
|
27
29
|
|
|
30
|
+
/** Math.min(src, dst) */
|
|
31
|
+
export const darkenColor32: BlendColor32 = (src, dst) => {
|
|
32
|
+
const sa = (src >>> 24) & 0xFF
|
|
33
|
+
if (sa === 0) return dst
|
|
34
|
+
const br = Math.min(src & 0xFF, dst & 0xFF)
|
|
35
|
+
const bg = Math.min((src >> 8) & 0xFF, (dst >> 8) & 0xFF)
|
|
36
|
+
const bb = Math.min((src >> 16) & 0xFF, (dst >> 16) & 0xFF)
|
|
37
|
+
|
|
38
|
+
if (sa === 255) return (0xFF000000 | (bb << 16) | (bg << 8) | br) >>> 0 as Color32
|
|
39
|
+
|
|
40
|
+
const dr = dst & 0xFF
|
|
41
|
+
const dg = (dst >> 8) & 0xFF
|
|
42
|
+
const db = (dst >> 16) & 0xFF
|
|
43
|
+
|
|
44
|
+
// Alpha Lerp inlined
|
|
45
|
+
const invA = 255 - sa
|
|
46
|
+
const r = (br * sa + dr * invA) >> 8
|
|
47
|
+
const g = (bg * sa + dg * invA) >> 8
|
|
48
|
+
const b = (bb * sa + db * invA) >> 8
|
|
49
|
+
const a = (255 * sa + ((dst >>> 24) & 0xFF) * invA) >> 8
|
|
50
|
+
|
|
51
|
+
return ((a << 24) | (b << 16) | (g << 8) | r) >>> 0 as Color32
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** (src * dst) / 255 */
|
|
55
|
+
export const multiplyColor32: BlendColor32 = (src, dst) => {
|
|
56
|
+
const sa = (src >>> 24) & 0xFF
|
|
57
|
+
if (sa === 0) return dst
|
|
58
|
+
|
|
59
|
+
const dr = dst & 0xFF, dg = (dst >> 8) & 0xFF, db = (dst >> 16) & 0xFF
|
|
60
|
+
|
|
61
|
+
const br = ((src & 0xFF) * dr + 128) >> 8
|
|
62
|
+
const bg = (((src >> 8) & 0xFF) * dg) >> 8
|
|
63
|
+
const bb = (((src >> 16) & 0xFF) * db) >> 8
|
|
64
|
+
|
|
65
|
+
if (sa === 255) return (0xFF000000 | (bb << 16) | (bg << 8) | br) >>> 0 as Color32
|
|
66
|
+
|
|
67
|
+
// Alpha Lerp inlined
|
|
68
|
+
const invA = 255 - sa
|
|
69
|
+
const r = (br * sa + dr * invA) >> 8
|
|
70
|
+
const g = (bg * sa + dg * invA) >> 8
|
|
71
|
+
const b = (bb * sa + db * invA) >> 8
|
|
72
|
+
const a = (255 * sa + ((dst >>> 24) & 0xFF) * invA) >> 8
|
|
73
|
+
|
|
74
|
+
return ((a << 24) | (b << 16) | (g << 8) | r) >>> 0 as Color32
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** 255 - (255-src)/dst */
|
|
78
|
+
export const colorBurnColor32: BlendColor32 = (src, dst) => {
|
|
79
|
+
const sa = (src >>> 24) & 0xFF
|
|
80
|
+
if (sa === 0) return dst
|
|
81
|
+
|
|
82
|
+
const sr = src & 0xFF, sg = (src >> 8) & 0xFF, sb = (src >> 16) & 0xFF
|
|
83
|
+
const dr = dst & 0xFF, dg = (dst >> 8) & 0xFF, db = (dst >> 16) & 0xFF
|
|
84
|
+
|
|
85
|
+
const br = dr === 255 ? 255 : Math.max(0, 255 - ((255 - dr) << 8) / (sr || 1))
|
|
86
|
+
const bg = dg === 255 ? 255 : Math.max(0, 255 - ((255 - dg) << 8) / (sg || 1))
|
|
87
|
+
const bb = db === 255 ? 255 : Math.max(0, 255 - ((255 - db) << 8) / (sb || 1))
|
|
88
|
+
|
|
89
|
+
if (sa === 255) return (0xFF000000 | (bb << 16) | (bg << 8) | br) >>> 0 as Color32
|
|
90
|
+
|
|
91
|
+
// Alpha Lerp inlined
|
|
92
|
+
const invA = 255 - sa
|
|
93
|
+
const r = (br * sa + dr * invA) >> 8
|
|
94
|
+
const g = (bg * sa + dg * invA) >> 8
|
|
95
|
+
const b = (bb * sa + db * invA) >> 8
|
|
96
|
+
const a = (255 * sa + ((dst >>> 24) & 0xFF) * invA) >> 8
|
|
97
|
+
|
|
98
|
+
return ((a << 24) | (b << 16) | (g << 8) | r) >>> 0 as Color32
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** src + dst - 255 */
|
|
102
|
+
export const linearBurnColor32: BlendColor32 = (src, dst) => {
|
|
103
|
+
const sa = (src >>> 24) & 0xFF
|
|
104
|
+
if (sa === 0) return dst
|
|
105
|
+
|
|
106
|
+
const dr = dst & 0xFF, dg = (dst >> 8) & 0xFF, db = (dst >> 16) & 0xFF
|
|
107
|
+
const sr = src & 0xFF, sg = (src >> 8) & 0xFF, sb = (src >> 16) & 0xFF
|
|
108
|
+
|
|
109
|
+
// Math: Base + Blend - 255 (clamped to 0)
|
|
110
|
+
const br = Math.max(0, dr + sr - 255)
|
|
111
|
+
const bg = Math.max(0, dg + sg - 255)
|
|
112
|
+
const bb = Math.max(0, db + sb - 255)
|
|
113
|
+
|
|
114
|
+
if (sa === 255) return (0xFF000000 | (bb << 16) | (bg << 8) | br) >>> 0 as Color32
|
|
115
|
+
|
|
116
|
+
// Alpha Lerp inlined
|
|
117
|
+
const invA = 255 - sa
|
|
118
|
+
const r = (br * sa + dr * invA) >> 8
|
|
119
|
+
const g = (bg * sa + dg * invA) >> 8
|
|
120
|
+
const b = (bb * sa + db * invA) >> 8
|
|
121
|
+
const a = (255 * sa + ((dst >>> 24) & 0xFF) * invA) >> 8
|
|
122
|
+
|
|
123
|
+
return ((a << 24) | (b << 16) | (g << 8) | r) >>> 0 as Color32
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export const darkerColor32: BlendColor32 = (src, dst) => {
|
|
127
|
+
const sa = (src >>> 24) & 0xFF
|
|
128
|
+
if (sa === 0) return dst
|
|
129
|
+
|
|
130
|
+
const dr = dst & 0xFF, dg = (dst >> 8) & 0xFF, db = (dst >> 16) & 0xFF
|
|
131
|
+
const sr = src & 0xFF, sg = (src >> 8) & 0xFF, sb = (src >> 16) & 0xFF
|
|
132
|
+
|
|
133
|
+
// 1. Calculate Luminosity (Photoshop Weights: R:0.3, G:0.59, B:0.11)
|
|
134
|
+
// Scaled by 256 for integer math: 77, 151, 28
|
|
135
|
+
const lumSrc = (sr * 77 + sg * 151 + sb * 28)
|
|
136
|
+
const lumDst = (dr * 77 + dg * 151 + db * 28)
|
|
137
|
+
|
|
138
|
+
// 2. Selection Logic
|
|
139
|
+
// Pick the perceptually darker pixel
|
|
140
|
+
let br, bg, bb
|
|
141
|
+
if (lumSrc < lumDst) {
|
|
142
|
+
br = sr
|
|
143
|
+
bg = sg
|
|
144
|
+
bb = sb
|
|
145
|
+
} else {
|
|
146
|
+
br = dr
|
|
147
|
+
bg = dg
|
|
148
|
+
bb = db
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (sa === 255) return (0xFF000000 | (bb << 16) | (bg << 8) | br) >>> 0 as Color32
|
|
152
|
+
|
|
153
|
+
// 3. Alpha Lerp inlined
|
|
154
|
+
const invA = 255 - sa
|
|
155
|
+
const r = (br * sa + dr * invA) >> 8
|
|
156
|
+
const g = (bg * sa + dg * invA) >> 8
|
|
157
|
+
const b = (bb * sa + db * invA) >> 8
|
|
158
|
+
const a = (255 * sa + ((dst >>> 24) & 0xFF) * invA) >> 8
|
|
159
|
+
|
|
160
|
+
return ((a << 24) | (b << 16) | (g << 8) | r) >>> 0 as Color32
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/** Math.max(src, dst) */
|
|
164
|
+
export const lightenColor32: BlendColor32 = (src, dst) => {
|
|
165
|
+
const sa = (src >>> 24) & 0xFF
|
|
166
|
+
if (sa === 0) return dst
|
|
167
|
+
const br = Math.max(src & 0xFF, dst & 0xFF)
|
|
168
|
+
const bg = Math.max((src >> 8) & 0xFF, (dst >> 8) & 0xFF)
|
|
169
|
+
const bb = Math.max((src >> 16) & 0xFF, (dst >> 16) & 0xFF)
|
|
170
|
+
|
|
171
|
+
if (sa === 255) return (0xFF000000 | (bb << 16) | (bg << 8) | br) >>> 0 as Color32
|
|
172
|
+
|
|
173
|
+
const dr = dst & 0xFF
|
|
174
|
+
const dg = (dst >> 8) & 0xFF
|
|
175
|
+
const db = (dst >> 16) & 0xFF
|
|
176
|
+
|
|
177
|
+
// Alpha Lerp inlined
|
|
178
|
+
const invA = 255 - sa
|
|
179
|
+
const r = (br * sa + dr * invA) >> 8
|
|
180
|
+
const g = (bg * sa + dg * invA) >> 8
|
|
181
|
+
const b = (bb * sa + db * invA) >> 8
|
|
182
|
+
const a = (255 * sa + ((dst >>> 24) & 0xFF) * invA) >> 8
|
|
183
|
+
|
|
184
|
+
return ((a << 24) | (b << 16) | (g << 8) | r) >>> 0 as Color32
|
|
185
|
+
}
|
|
186
|
+
|
|
28
187
|
/**
|
|
29
|
-
*
|
|
30
|
-
* Result = 1 - ((1 - Src) * (1 - Dst))
|
|
188
|
+
* 255 - ((255 - src) * (255 - dst))
|
|
31
189
|
*/
|
|
32
190
|
export const screenColor32: BlendColor32 = (src, dst) => {
|
|
33
191
|
const sa = (src >>> 24) & 0xFF
|
|
@@ -35,14 +193,13 @@ export const screenColor32: BlendColor32 = (src, dst) => {
|
|
|
35
193
|
|
|
36
194
|
const dr = dst & 0xFF, dg = (dst >> 8) & 0xFF, db = (dst >> 16) & 0xFF
|
|
37
195
|
|
|
38
|
-
// 1. Core Math
|
|
39
196
|
const br = 255 - (((255 - (src & 0xFF)) * (255 - dr)) >> 8)
|
|
40
197
|
const bg = 255 - (((255 - ((src >> 8) & 0xFF)) * (255 - dg)) >> 8)
|
|
41
198
|
const bb = 255 - (((255 - ((src >> 16) & 0xFF)) * (255 - db)) >> 8)
|
|
42
199
|
|
|
43
200
|
if (sa === 255) return (0xFF000000 | (bb << 16) | (bg << 8) | br) >>> 0 as Color32
|
|
44
201
|
|
|
45
|
-
//
|
|
202
|
+
// Alpha Lerp inlined
|
|
46
203
|
const invA = 255 - sa
|
|
47
204
|
const r = (br * sa + dr * invA) >> 8
|
|
48
205
|
const g = (bg * sa + dg * invA) >> 8
|
|
@@ -52,24 +209,44 @@ export const screenColor32: BlendColor32 = (src, dst) => {
|
|
|
52
209
|
return ((a << 24) | (b << 16) | (g << 8) | r) >>> 0 as Color32
|
|
53
210
|
}
|
|
54
211
|
|
|
55
|
-
/**
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
212
|
+
/** src === 255 ? 255 : Math.min(255, (dst << 8) / (255 - src)) */
|
|
213
|
+
export const colorDodgeColor32: BlendColor32 = (src, dst) => {
|
|
214
|
+
const sa = (src >>> 24) & 0xFF
|
|
215
|
+
if (sa === 0) return dst
|
|
216
|
+
|
|
217
|
+
const dr = dst & 0xFF, dg = (dst >> 8) & 0xFF, db = (dst >> 16) & 0xFF
|
|
218
|
+
const sr = src & 0xFF, sg = (src >> 8) & 0xFF, sb = (src >> 16) & 0xFF
|
|
219
|
+
|
|
220
|
+
const br = sr === 255 ? 255 : Math.min(255, (dr << 8) / (255 - sr))
|
|
221
|
+
const bg = sg === 255 ? 255 : Math.min(255, (dg << 8) / (255 - sg))
|
|
222
|
+
const bb = sb === 255 ? 255 : Math.min(255, (db << 8) / (255 - sb))
|
|
223
|
+
|
|
224
|
+
if (sa === 255) return (0xFF000000 | (bb << 16) | (bg << 8) | br) >>> 0 as Color32
|
|
225
|
+
|
|
226
|
+
// Alpha Lerp inlined
|
|
227
|
+
const invA = 255 - sa
|
|
228
|
+
const r = (br * sa + dr * invA) >> 8
|
|
229
|
+
const g = (bg * sa + dg * invA) >> 8
|
|
230
|
+
const b = (bb * sa + db * invA) >> 8
|
|
231
|
+
const a = (255 * sa + ((dst >>> 24) & 0xFF) * invA) >> 8
|
|
232
|
+
|
|
233
|
+
return ((a << 24) | (b << 16) | (g << 8) | r) >>> 0 as Color32
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/** src + dst */
|
|
59
237
|
export const linearDodgeColor32: BlendColor32 = (src, dst) => {
|
|
60
238
|
const sa = (src >>> 24) & 0xFF
|
|
61
239
|
if (sa === 0) return dst
|
|
62
240
|
|
|
63
241
|
const dr = dst & 0xFF, dg = (dst >> 8) & 0xFF, db = (dst >> 16) & 0xFF
|
|
64
242
|
|
|
65
|
-
// 1. Core Math (Additive with clamping)
|
|
66
243
|
const br = Math.min(255, (src & 0xFF) + dr)
|
|
67
244
|
const bg = Math.min(255, ((src >> 8) & 0xFF) + dg)
|
|
68
245
|
const bb = Math.min(255, ((src >> 16) & 0xFF) + db)
|
|
69
246
|
|
|
70
247
|
if (sa === 255) return (0xFF000000 | (bb << 16) | (bg << 8) | br) >>> 0 as Color32
|
|
71
248
|
|
|
72
|
-
//
|
|
249
|
+
// Alpha Lerp inlined
|
|
73
250
|
const invA = 255 - sa
|
|
74
251
|
const r = (br * sa + dr * invA) >> 8
|
|
75
252
|
const g = (bg * sa + dg * invA) >> 8
|
|
@@ -79,24 +256,105 @@ export const linearDodgeColor32: BlendColor32 = (src, dst) => {
|
|
|
79
256
|
return ((a << 24) | (b << 16) | (g << 8) | r) >>> 0 as Color32
|
|
80
257
|
}
|
|
81
258
|
|
|
82
|
-
|
|
83
|
-
* Multiply: Darkens the destination based on the source color.
|
|
84
|
-
* Result = (Src * Dst) / 255
|
|
85
|
-
*/
|
|
86
|
-
export const multiplyColor32: BlendColor32 = (src, dst) => {
|
|
259
|
+
export const lighterColor32: BlendColor32 = (src, dst) => {
|
|
87
260
|
const sa = (src >>> 24) & 0xFF
|
|
88
261
|
if (sa === 0) return dst
|
|
89
262
|
|
|
90
263
|
const dr = dst & 0xFF, dg = (dst >> 8) & 0xFF, db = (dst >> 16) & 0xFF
|
|
264
|
+
const sr = src & 0xFF, sg = (src >> 8) & 0xFF, sb = (src >> 16) & 0xFF
|
|
91
265
|
|
|
92
|
-
//
|
|
93
|
-
|
|
94
|
-
const
|
|
95
|
-
const
|
|
266
|
+
// Calculate Luminosity (Photoshop uses Weights: R:0.3, G:0.59, B:0.11)
|
|
267
|
+
// We use integer math (scaled by 256) for speed.
|
|
268
|
+
const lumSrc = (sr * 77 + sg * 151 + sb * 28)
|
|
269
|
+
const lumDst = (dr * 77 + dg * 151 + db * 28)
|
|
270
|
+
|
|
271
|
+
// Selection Logic (Base result)
|
|
272
|
+
let br, bg, bb
|
|
273
|
+
if (lumSrc > lumDst) {
|
|
274
|
+
br = sr
|
|
275
|
+
bg = sg
|
|
276
|
+
bb = sb
|
|
277
|
+
} else {
|
|
278
|
+
br = dr
|
|
279
|
+
bg = dg
|
|
280
|
+
bb = db
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
if (sa === 255) return (0xFF000000 | (bb << 16) | (bg << 8) | br) >>> 0 as Color32
|
|
284
|
+
|
|
285
|
+
// Alpha Lerp
|
|
286
|
+
const invA = 255 - sa
|
|
287
|
+
const r = (br * sa + dr * invA) >> 8
|
|
288
|
+
const g = (bg * sa + dg * invA) >> 8
|
|
289
|
+
const b = (bb * sa + db * invA) >> 8
|
|
290
|
+
const a = (255 * sa + ((dst >>> 24) & 0xFF) * invA) >> 8
|
|
291
|
+
|
|
292
|
+
return ((a << 24) | (b << 16) | (g << 8) | r) >>> 0 as Color32
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/** src < 128 ? (2 * src * dst) : (255 - 2 * (255 - src) * (255 - dst)) */
|
|
296
|
+
export const overlayColor32: BlendColor32 = (src, dst) => {
|
|
297
|
+
const sa = (src >>> 24) & 0xFF
|
|
298
|
+
if (sa === 0) return dst
|
|
299
|
+
|
|
300
|
+
const sr = src & 0xFF, sg = (src >> 8) & 0xFF, sb = (src >> 16) & 0xFF
|
|
301
|
+
const dr = dst & 0xFF, dg = (dst >> 8) & 0xFF, db = (dst >> 16) & 0xFF
|
|
302
|
+
|
|
303
|
+
const br = dr < 128 ? (2 * sr * dr) >> 8 : 255 - (2 * (255 - sr) * (255 - dr) >> 8)
|
|
304
|
+
const bg = dg < 128 ? (2 * sg * dg) >> 8 : 255 - (2 * (255 - sg) * (255 - dg) >> 8)
|
|
305
|
+
const bb = db < 128 ? (2 * sb * db) >> 8 : 255 - (2 * (255 - sb) * (255 - db) >> 8)
|
|
306
|
+
|
|
307
|
+
if (sa === 255) return (0xFF000000 | (bb << 16) | (bg << 8) | br) >>> 0 as Color32
|
|
308
|
+
|
|
309
|
+
// Alpha Lerp inlined
|
|
310
|
+
const invA = 255 - sa
|
|
311
|
+
const r = (br * sa + dr * invA) >> 8
|
|
312
|
+
const g = (bg * sa + dg * invA) >> 8
|
|
313
|
+
const b = (bb * sa + db * invA) >> 8
|
|
314
|
+
const a = (255 * sa + ((dst >>> 24) & 0xFF) * invA) >> 8
|
|
315
|
+
|
|
316
|
+
return ((a << 24) | (b << 16) | (g << 8) | r) >>> 0 as Color32
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/** ((255 - dst) * ((src * dst) >> 8) + dst * (255 - (((255 - src) * (255 - dst)) >> 8))) >> 8 */
|
|
320
|
+
export const softLightColor32: BlendColor32 = (src, dst) => {
|
|
321
|
+
const sa = (src >>> 24) & 0xFF
|
|
322
|
+
if (sa === 0) return dst
|
|
323
|
+
|
|
324
|
+
const dr = dst & 0xFF, dg = (dst >> 8) & 0xFF, db = (dst >> 16) & 0xFF
|
|
325
|
+
const sr = src & 0xFF, sg = (src >> 8) & 0xFF, sb = (src >> 16) & 0xFF
|
|
326
|
+
|
|
327
|
+
const br = ((255 - dr) * ((sr * dr) >> 8) + dr * (255 - (((255 - sr) * (255 - dr)) >> 8))) >> 8
|
|
328
|
+
const bg = ((255 - dg) * ((sg * dg) >> 8) + dg * (255 - (((255 - sg) * (255 - dg)) >> 8))) >> 8
|
|
329
|
+
const bb = ((255 - db) * ((sb * db) >> 8) + db * (255 - (((255 - sb) * (255 - db)) >> 8))) >> 8
|
|
96
330
|
|
|
97
331
|
if (sa === 255) return (0xFF000000 | (bb << 16) | (bg << 8) | br) >>> 0 as Color32
|
|
98
332
|
|
|
99
|
-
//
|
|
333
|
+
// Alpha Lerp inlined
|
|
334
|
+
const invA = 255 - sa
|
|
335
|
+
const r = (br * sa + dr * invA) >> 8
|
|
336
|
+
const g = (bg * sa + dg * invA) >> 8
|
|
337
|
+
const b = (bb * sa + db * invA) >> 8
|
|
338
|
+
const a = (255 * sa + ((dst >>> 24) & 0xFF) * invA) >> 8
|
|
339
|
+
|
|
340
|
+
return ((a << 24) | (b << 16) | (g << 8) | r) >>> 0 as Color32
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
/** If src < 128 (50% gray), Multiply; otherwise, Screen */
|
|
344
|
+
export const hardLightColor32: BlendColor32 = (src, dst) => {
|
|
345
|
+
const sa = (src >>> 24) & 0xFF
|
|
346
|
+
if (sa === 0) return dst
|
|
347
|
+
|
|
348
|
+
const dr = dst & 0xFF, dg = (dst >> 8) & 0xFF, db = (dst >> 16) & 0xFF
|
|
349
|
+
const sr = src & 0xFF, sg = (src >> 8) & 0xFF, sb = (src >> 16) & 0xFF
|
|
350
|
+
|
|
351
|
+
const br = sr < 128 ? (2 * sr * dr) >> 8 : 255 - ((2 * (255 - sr) * (255 - dr)) >> 8)
|
|
352
|
+
const bg = sg < 128 ? (2 * sg * dg) >> 8 : 255 - ((2 * (255 - sg) * (255 - dg)) >> 8)
|
|
353
|
+
const bb = sb < 128 ? (2 * sb * db) >> 8 : 255 - ((2 * (255 - sb) * (255 - db)) >> 8)
|
|
354
|
+
|
|
355
|
+
if (sa === 255) return (0xFF000000 | (bb << 16) | (bg << 8) | br) >>> 0 as Color32
|
|
356
|
+
|
|
357
|
+
// Alpha Lerp inlined
|
|
100
358
|
const invA = 255 - sa
|
|
101
359
|
const r = (br * sa + dr * invA) >> 8
|
|
102
360
|
const g = (bg * sa + dg * invA) >> 8
|
|
@@ -107,23 +365,134 @@ export const multiplyColor32: BlendColor32 = (src, dst) => {
|
|
|
107
365
|
}
|
|
108
366
|
|
|
109
367
|
/**
|
|
110
|
-
*
|
|
111
|
-
*
|
|
368
|
+
* If src < 128: Burn(dst, 2 * src)
|
|
369
|
+
* If src >= 128: Dodge(dst, 2 * (src - 128))
|
|
112
370
|
*/
|
|
371
|
+
export const vividLightColor32: BlendColor32 = (src, dst) => {
|
|
372
|
+
const sa = (src >>> 24) & 0xFF
|
|
373
|
+
if (sa === 0) return dst
|
|
374
|
+
|
|
375
|
+
const dr = dst & 0xFF, dg = (dst >> 8) & 0xFF, db = (dst >> 16) & 0xFF
|
|
376
|
+
const sr = src & 0xFF, sg = (src >> 8) & 0xFF, sb = (src >> 16) & 0xFF
|
|
377
|
+
|
|
378
|
+
const br = sr < 128
|
|
379
|
+
? (sr === 0 ? 0 : Math.max(0, 255 - (((255 - dr) << 8) / (2 * sr))))
|
|
380
|
+
: (sr === 255 ? 255 : Math.min(255, (dr << 8) / (2 * (255 - sr))))
|
|
381
|
+
|
|
382
|
+
const bg = sg < 128
|
|
383
|
+
? (sg === 0 ? 0 : Math.max(0, 255 - (((255 - dg) << 8) / (2 * sg))))
|
|
384
|
+
: (sg === 255 ? 255 : Math.min(255, (dg << 8) / (2 * (255 - sg))))
|
|
385
|
+
|
|
386
|
+
const bb = sb < 128
|
|
387
|
+
? (sb === 0 ? 0 : Math.max(0, 255 - (((255 - db) << 8) / (2 * sb))))
|
|
388
|
+
: (sb === 255 ? 255 : Math.min(255, (db << 8) / (2 * (255 - sb))))
|
|
389
|
+
|
|
390
|
+
if (sa === 255) return (0xFF000000 | (bb << 16) | (bg << 8) | br) >>> 0 as Color32
|
|
391
|
+
|
|
392
|
+
// Alpha Lerp inlined
|
|
393
|
+
const invA = 255 - sa
|
|
394
|
+
const r = (br * sa + dr * invA) >> 8
|
|
395
|
+
const g = (bg * sa + dg * invA) >> 8
|
|
396
|
+
const b = (bb * sa + db * invA) >> 8
|
|
397
|
+
const a = (255 * sa + ((dst >>> 24) & 0xFF) * invA) >> 8
|
|
398
|
+
|
|
399
|
+
return ((a << 24) | (b << 16) | (g << 8) | r) >>> 0 as Color32
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
/** dst + 2 * src - 255 (Clamped to 0-255) */
|
|
403
|
+
export const linearLightColor32: BlendColor32 = (src, dst) => {
|
|
404
|
+
const sa = (src >>> 24) & 0xFF
|
|
405
|
+
if (sa === 0) return dst
|
|
406
|
+
|
|
407
|
+
const dr = dst & 0xFF, dg = (dst >> 8) & 0xFF, db = (dst >> 16) & 0xFF
|
|
408
|
+
const sr = src & 0xFF, sg = (src >> 8) & 0xFF, sb = (src >> 16) & 0xFF
|
|
409
|
+
|
|
410
|
+
const br = Math.max(0, Math.min(255, dr + 2 * sr - 255))
|
|
411
|
+
const bg = Math.max(0, Math.min(255, dg + 2 * sg - 255))
|
|
412
|
+
const bb = Math.max(0, Math.min(255, db + 2 * sb - 255))
|
|
413
|
+
|
|
414
|
+
if (sa === 255) return (0xFF000000 | (bb << 16) | (bg << 8) | br) >>> 0 as Color32
|
|
415
|
+
|
|
416
|
+
// Alpha Lerp inlined
|
|
417
|
+
const invA = 255 - sa
|
|
418
|
+
const r = (br * sa + dr * invA) >> 8
|
|
419
|
+
const g = (bg * sa + dg * invA) >> 8
|
|
420
|
+
const b = (bb * sa + db * invA) >> 8
|
|
421
|
+
const a = (255 * sa + ((dst >>> 24) & 0xFF) * invA) >> 8
|
|
422
|
+
|
|
423
|
+
return ((a << 24) | (b << 16) | (g << 8) | r) >>> 0 as Color32
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
/** src < 128 ? min(dst, 2 * src) : max(dst, 2 * (src - 128)) */
|
|
427
|
+
export const pinLightColor32: BlendColor32 = (src, dst) => {
|
|
428
|
+
const sa = (src >>> 24) & 0xFF
|
|
429
|
+
if (sa === 0) return dst
|
|
430
|
+
|
|
431
|
+
const dr = dst & 0xFF, dg = (dst >> 8) & 0xFF, db = (dst >> 16) & 0xFF
|
|
432
|
+
const sr = src & 0xFF, sg = (src >> 8) & 0xFF, sb = (src >> 16) & 0xFF
|
|
433
|
+
|
|
434
|
+
const br = sr < 128 ? Math.min(dr, 2 * sr) : Math.max(dr, 2 * (sr - 128))
|
|
435
|
+
const bg = sg < 128 ? Math.min(dg, 2 * sg) : Math.max(dg, 2 * (sg - 128))
|
|
436
|
+
const bb = sb < 128 ? Math.min(db, 2 * sb) : Math.max(db, 2 * (sb - 128))
|
|
437
|
+
|
|
438
|
+
if (sa === 255) return (0xFF000000 | (bb << 16) | (bg << 8) | br) >>> 0 as Color32
|
|
439
|
+
|
|
440
|
+
// Alpha Lerp inlined
|
|
441
|
+
const invA = 255 - sa
|
|
442
|
+
const r = (br * sa + dr * invA) >> 8
|
|
443
|
+
const g = (bg * sa + dg * invA) >> 8
|
|
444
|
+
const b = (bb * sa + db * invA) >> 8
|
|
445
|
+
const a = (255 * sa + ((dst >>> 24) & 0xFF) * invA) >> 8
|
|
446
|
+
|
|
447
|
+
return ((a << 24) | (b << 16) | (g << 8) | r) >>> 0 as Color32
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
/** (Vivid Light logic forced to 0 or 255) */
|
|
451
|
+
export const hardMixColor32: BlendColor32 = (src, dst) => {
|
|
452
|
+
const sa = (src >>> 24) & 0xFF
|
|
453
|
+
if (sa === 0) return dst
|
|
454
|
+
|
|
455
|
+
const dr = dst & 0xFF, dg = (dst >> 8) & 0xFF, db = (dst >> 16) & 0xFF
|
|
456
|
+
const sr = src & 0xFF, sg = (src >> 8) & 0xFF, sb = (src >> 16) & 0xFF
|
|
457
|
+
|
|
458
|
+
const br = (sr < 128
|
|
459
|
+
? (sr === 0 ? 0 : Math.max(0, 255 - (((255 - dr) << 8) / (2 * sr))))
|
|
460
|
+
: (sr === 255 ? 255 : Math.min(255, (dr << 8) / (2 * (255 - sr))))) < 128 ? 0 : 255
|
|
461
|
+
|
|
462
|
+
const bg = (sg < 128
|
|
463
|
+
? (sg === 0 ? 0 : Math.max(0, 255 - (((255 - dg) << 8) / (2 * sg))))
|
|
464
|
+
: (sg === 255 ? 255 : Math.min(255, (dg << 8) / (2 * (255 - sg))))) < 128 ? 0 : 255
|
|
465
|
+
|
|
466
|
+
const bb = (sb < 128
|
|
467
|
+
? (sb === 0 ? 0 : Math.max(0, 255 - (((255 - db) << 8) / (2 * sb))))
|
|
468
|
+
: (sb === 255 ? 255 : Math.min(255, (db << 8) / (2 * (255 - sb))))) < 128 ? 0 : 255
|
|
469
|
+
|
|
470
|
+
if (sa === 255) return (0xFF000000 | (bb << 16) | (bg << 8) | br) >>> 0 as Color32
|
|
471
|
+
|
|
472
|
+
// Alpha Lerp inlined
|
|
473
|
+
const invA = 255 - sa
|
|
474
|
+
const r = (br * sa + dr * invA) >> 8
|
|
475
|
+
const g = (bg * sa + dg * invA) >> 8
|
|
476
|
+
const b = (bb * sa + db * invA) >> 8
|
|
477
|
+
const a = (255 * sa + ((dst >>> 24) & 0xFF) * invA) >> 8
|
|
478
|
+
|
|
479
|
+
return ((a << 24) | (b << 16) | (g << 8) | r) >>> 0 as Color32
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
/** Math.abs(src - dst) */
|
|
113
483
|
export const differenceColor32: BlendColor32 = (src, dst) => {
|
|
114
484
|
const sa = (src >>> 24) & 0xFF
|
|
115
485
|
if (sa === 0) return dst
|
|
116
486
|
|
|
117
487
|
const dr = dst & 0xFF, dg = (dst >> 8) & 0xFF, db = (dst >> 16) & 0xFF
|
|
118
488
|
|
|
119
|
-
// 1. Core Math
|
|
120
489
|
const br = Math.abs((src & 0xFF) - dr)
|
|
121
490
|
const bg = Math.abs(((src >> 8) & 0xFF) - dg)
|
|
122
491
|
const bb = Math.abs(((src >> 16) & 0xFF) - db)
|
|
123
492
|
|
|
124
493
|
if (sa === 255) return (0xFF000000 | (bb << 16) | (bg << 8) | br) >>> 0 as Color32
|
|
125
494
|
|
|
126
|
-
//
|
|
495
|
+
// Alpha Lerp inlined
|
|
127
496
|
const invA = 255 - sa
|
|
128
497
|
const r = (br * sa + dr * invA) >> 8
|
|
129
498
|
const g = (bg * sa + dg * invA) >> 8
|
|
@@ -133,25 +502,21 @@ export const differenceColor32: BlendColor32 = (src, dst) => {
|
|
|
133
502
|
return ((a << 24) | (b << 16) | (g << 8) | r) >>> 0 as Color32
|
|
134
503
|
}
|
|
135
504
|
|
|
136
|
-
/**
|
|
137
|
-
|
|
138
|
-
* Acts like a harsh spotlight.
|
|
139
|
-
*/
|
|
140
|
-
export const hardLightColor32: BlendColor32 = (src, dst) => {
|
|
505
|
+
/** dst + src - ((dst * src) >> 7) */
|
|
506
|
+
export const exclusionColor32: BlendColor32 = (src, dst) => {
|
|
141
507
|
const sa = (src >>> 24) & 0xFF
|
|
142
508
|
if (sa === 0) return dst
|
|
143
509
|
|
|
144
|
-
const sr = src & 0xFF, sg = (src >> 8) & 0xFF, sb = (src >> 16) & 0xFF
|
|
145
510
|
const dr = dst & 0xFF, dg = (dst >> 8) & 0xFF, db = (dst >> 16) & 0xFF
|
|
511
|
+
const sr = src & 0xFF, sg = (src >> 8) & 0xFF, sb = (src >> 16) & 0xFF
|
|
146
512
|
|
|
147
|
-
|
|
148
|
-
const
|
|
149
|
-
const
|
|
150
|
-
const bb = sb < 128 ? (2 * sb * db) >> 8 : 255 - (2 * (255 - sb) * (255 - db) >> 8)
|
|
513
|
+
const br = dr + sr - ((dr * sr) >> 7)
|
|
514
|
+
const bg = dg + sg - ((dg * sg) >> 7)
|
|
515
|
+
const bb = db + sb - ((db * sb) >> 7)
|
|
151
516
|
|
|
152
517
|
if (sa === 255) return (0xFF000000 | (bb << 16) | (bg << 8) | br) >>> 0 as Color32
|
|
153
518
|
|
|
154
|
-
//
|
|
519
|
+
// Alpha Lerp inlined
|
|
155
520
|
const invA = 255 - sa
|
|
156
521
|
const r = (br * sa + dr * invA) >> 8
|
|
157
522
|
const g = (bg * sa + dg * invA) >> 8
|
|
@@ -161,25 +526,21 @@ export const hardLightColor32: BlendColor32 = (src, dst) => {
|
|
|
161
526
|
return ((a << 24) | (b << 16) | (g << 8) | r) >>> 0 as Color32
|
|
162
527
|
}
|
|
163
528
|
|
|
164
|
-
/**
|
|
165
|
-
|
|
166
|
-
* Intense saturation in the darks.
|
|
167
|
-
*/
|
|
168
|
-
export const colorBurnColor32: BlendColor32 = (src, dst) => {
|
|
529
|
+
/** Math.max(0, dst - src) */
|
|
530
|
+
export const subtractColor32: BlendColor32 = (src, dst) => {
|
|
169
531
|
const sa = (src >>> 24) & 0xFF
|
|
170
532
|
if (sa === 0) return dst
|
|
171
533
|
|
|
172
|
-
const sr = src & 0xFF, sg = (src >> 8) & 0xFF, sb = (src >> 16) & 0xFF
|
|
173
534
|
const dr = dst & 0xFF, dg = (dst >> 8) & 0xFF, db = (dst >> 16) & 0xFF
|
|
535
|
+
const sr = src & 0xFF, sg = (src >> 8) & 0xFF, sb = (src >> 16) & 0xFF
|
|
174
536
|
|
|
175
|
-
|
|
176
|
-
const
|
|
177
|
-
const
|
|
178
|
-
const bb = db === 255 ? 255 : Math.max(0, 255 - ((255 - db) << 8) / (sb || 1))
|
|
537
|
+
const br = Math.max(0, dr - sr)
|
|
538
|
+
const bg = Math.max(0, dg - sg)
|
|
539
|
+
const bb = Math.max(0, db - sb)
|
|
179
540
|
|
|
180
541
|
if (sa === 255) return (0xFF000000 | (bb << 16) | (bg << 8) | br) >>> 0 as Color32
|
|
181
542
|
|
|
182
|
-
//
|
|
543
|
+
// Alpha Lerp inlined
|
|
183
544
|
const invA = 255 - sa
|
|
184
545
|
const r = (br * sa + dr * invA) >> 8
|
|
185
546
|
const g = (bg * sa + dg * invA) >> 8
|
|
@@ -188,25 +549,22 @@ export const colorBurnColor32: BlendColor32 = (src, dst) => {
|
|
|
188
549
|
|
|
189
550
|
return ((a << 24) | (b << 16) | (g << 8) | r) >>> 0 as Color32
|
|
190
551
|
}
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
*/
|
|
195
|
-
export const overlayColor32: BlendColor32 = (src, dst) => {
|
|
552
|
+
|
|
553
|
+
/** sr === 0 ? 255 : Math.min(255, (dr << 8) / sr) */
|
|
554
|
+
export const divideColor32: BlendColor32 = (src, dst) => {
|
|
196
555
|
const sa = (src >>> 24) & 0xFF
|
|
197
556
|
if (sa === 0) return dst
|
|
198
557
|
|
|
199
|
-
const sr = src & 0xFF, sg = (src >> 8) & 0xFF, sb = (src >> 16) & 0xFF
|
|
200
558
|
const dr = dst & 0xFF, dg = (dst >> 8) & 0xFF, db = (dst >> 16) & 0xFF
|
|
559
|
+
const sr = src & 0xFF, sg = (src >> 8) & 0xFF, sb = (src >> 16) & 0xFF
|
|
201
560
|
|
|
202
|
-
|
|
203
|
-
const
|
|
204
|
-
const
|
|
205
|
-
const bb = db < 128 ? (2 * sb * db) >> 8 : 255 - (2 * (255 - sb) * (255 - db) >> 8)
|
|
561
|
+
const br = sr === 0 ? 255 : Math.min(255, (dr << 8) / sr)
|
|
562
|
+
const bg = sg === 0 ? 255 : Math.min(255, (dg << 8) / sg)
|
|
563
|
+
const bb = sb === 0 ? 255 : Math.min(255, (db << 8) / sb)
|
|
206
564
|
|
|
207
565
|
if (sa === 255) return (0xFF000000 | (bb << 16) | (bg << 8) | br) >>> 0 as Color32
|
|
208
566
|
|
|
209
|
-
//
|
|
567
|
+
// Alpha Lerp inlined
|
|
210
568
|
const invA = 255 - sa
|
|
211
569
|
const r = (br * sa + dr * invA) >> 8
|
|
212
570
|
const g = (bg * sa + dg * invA) >> 8
|
|
@@ -216,13 +574,95 @@ export const overlayColor32: BlendColor32 = (src, dst) => {
|
|
|
216
574
|
return ((a << 24) | (b << 16) | (g << 8) | r) >>> 0 as Color32
|
|
217
575
|
}
|
|
218
576
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
colorBurn
|
|
577
|
+
// The enum index IS the permanent ID.
|
|
578
|
+
// do not change the order, Adding to it is ok.
|
|
579
|
+
export enum BlendMode {
|
|
580
|
+
overwrite,
|
|
581
|
+
sourceOver,
|
|
582
|
+
|
|
583
|
+
darken,
|
|
584
|
+
multiply,
|
|
585
|
+
colorBurn,
|
|
586
|
+
linearBurn,
|
|
587
|
+
darkerColor,
|
|
588
|
+
|
|
589
|
+
lighten,
|
|
590
|
+
screen,
|
|
591
|
+
colorDodge,
|
|
592
|
+
linearDodge,
|
|
593
|
+
lighterColor,
|
|
594
|
+
|
|
595
|
+
overlay,
|
|
596
|
+
softLight,
|
|
597
|
+
hardLight,
|
|
598
|
+
vividLight,
|
|
599
|
+
linearLight,
|
|
600
|
+
pinLight,
|
|
601
|
+
hardMix,
|
|
602
|
+
|
|
603
|
+
difference,
|
|
604
|
+
exclusion,
|
|
605
|
+
subtract,
|
|
606
|
+
divide,
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
const BLENDER_REGISTRY = [
|
|
610
|
+
[BlendMode.overwrite, overwriteColor32],
|
|
611
|
+
[BlendMode.sourceOver, sourceOverColor32],
|
|
612
|
+
|
|
613
|
+
[BlendMode.darken, darkenColor32],
|
|
614
|
+
[BlendMode.multiply, multiplyColor32],
|
|
615
|
+
[BlendMode.colorBurn, colorBurnColor32],
|
|
616
|
+
[BlendMode.linearBurn, linearBurnColor32],
|
|
617
|
+
[BlendMode.darkerColor, darkerColor32],
|
|
618
|
+
|
|
619
|
+
[BlendMode.lighten, lightenColor32],
|
|
620
|
+
[BlendMode.screen, screenColor32],
|
|
621
|
+
[BlendMode.colorDodge, colorDodgeColor32],
|
|
622
|
+
[BlendMode.linearDodge, linearDodgeColor32],
|
|
623
|
+
[BlendMode.lighterColor, lighterColor32],
|
|
624
|
+
|
|
625
|
+
[BlendMode.overlay, overlayColor32],
|
|
626
|
+
[BlendMode.softLight, softLightColor32],
|
|
627
|
+
[BlendMode.hardLight, hardLightColor32],
|
|
628
|
+
[BlendMode.vividLight, vividLightColor32],
|
|
629
|
+
[BlendMode.linearLight, linearLightColor32],
|
|
630
|
+
[BlendMode.pinLight, pinLightColor32],
|
|
631
|
+
[BlendMode.hardMix, hardMixColor32],
|
|
632
|
+
|
|
633
|
+
[BlendMode.difference, differenceColor32],
|
|
634
|
+
[BlendMode.exclusion, exclusionColor32],
|
|
635
|
+
[BlendMode.subtract, subtractColor32],
|
|
636
|
+
[BlendMode.divide, divideColor32],
|
|
637
|
+
] as const
|
|
638
|
+
|
|
639
|
+
export type RegisteredBlender = typeof BLENDER_REGISTRY[number][1]
|
|
640
|
+
export type BlendModeIndex = number & { readonly __brandBlendModeIndex: unique symbol }
|
|
641
|
+
|
|
642
|
+
export const COLOR_32_BLEND_MODES: BlendColor32[] = []
|
|
643
|
+
|
|
644
|
+
for (const [index, blend] of BLENDER_REGISTRY) {
|
|
645
|
+
COLOR_32_BLEND_MODES[index as BlendModeIndex] = blend
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
export const COLOR_32_BLEND_TO_INDEX = new Map<RegisteredBlender, BlendModeIndex>(
|
|
649
|
+
BLENDER_REGISTRY.map((entry, index) => {
|
|
650
|
+
return [
|
|
651
|
+
entry[1],
|
|
652
|
+
index as BlendModeIndex,
|
|
653
|
+
]
|
|
654
|
+
}),
|
|
655
|
+
) as {
|
|
656
|
+
get: (blend: RegisteredBlender) => BlendModeIndex
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
export const INDEX_TO_COLOR_32_BLEND = new Map<BlendModeIndex, RegisteredBlender>(
|
|
660
|
+
BLENDER_REGISTRY.map((entry, index) => {
|
|
661
|
+
return [
|
|
662
|
+
index as BlendModeIndex,
|
|
663
|
+
entry[1],
|
|
664
|
+
]
|
|
665
|
+
}),
|
|
666
|
+
) as {
|
|
667
|
+
get: (index: BlendModeIndex) => RegisteredBlender
|
|
228
668
|
}
|