@eightshift/ui-components 5.5.0 → 5.6.1
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/assets/style-admin.css +2 -8286
- package/dist/assets/style-editor.css +2 -8286
- package/dist/assets/style.css +2 -8292
- package/dist/assets/wp-font-enhancements.css +2 -8
- package/dist/assets/wp-ui-enhancements.css +2 -387
- package/dist/components/button/button.js +1 -1
- package/dist/components/color-pickers/color-picker.js +1 -1
- package/dist/components/color-pickers/color-swatch.js +1 -1
- package/dist/components/color-pickers/gradient-editor.js +1 -1
- package/dist/components/color-pickers/solid-color-picker.js +1 -1
- package/dist/components/component-toggle/component-toggle.js +1 -1
- package/dist/components/draggable/draggable-handle.js +1 -1
- package/dist/components/draggable/draggable.js +1 -1
- package/dist/components/draggable-list/draggable-list-item.js +1 -1
- package/dist/components/draggable-list/draggable-list.js +1 -1
- package/dist/components/expandable/expandable.js +1 -1
- package/dist/components/item-collection/item-collection.js +1 -1
- package/dist/components/link-input/link-input.js +1 -1
- package/dist/components/matrix-align/matrix-align.js +1 -1
- package/dist/components/menu/menu.js +1 -1
- package/dist/components/modal/modal.js +1 -1
- package/dist/components/number-picker/number-picker.js +1 -1
- package/dist/components/option-select/option-select.js +1 -1
- package/dist/components/placeholders/file-picker-shell.js +12 -8
- package/dist/components/placeholders/file-placeholder.js +1 -1
- package/dist/components/popover/popover.js +1 -1
- package/dist/components/repeater/repeater-item.js +1 -1
- package/dist/components/repeater/repeater.js +1 -1
- package/dist/components/responsive/mini-responsive.js +1 -1
- package/dist/components/responsive/responsive-legacy.js +1 -1
- package/dist/components/responsive/responsive.js +1 -1
- package/dist/components/responsive-preview/responsive-preview.js +1 -1
- package/dist/components/select/v2/async-multi-select.js +1 -1
- package/dist/components/select/v2/async-select.js +1 -1
- package/dist/components/select/v2/multi-select.js +1 -1
- package/dist/components/select/v2/single-select.js +1 -1
- package/dist/components/slider/column-config-slider.js +1 -1
- package/dist/components/slider/utils.js +1 -1
- package/dist/components/smart-image/smart-image.js +49 -7
- package/dist/components/smart-image/worker-inline.js +4 -0
- package/dist/components/tabs/tabs.js +1 -1
- package/dist/{default-i18n-CN_q3KUs.js → default-i18n-DBm-GqWM.js} +167 -50
- package/dist/general-Ck8IV7xJ.js +4371 -0
- package/dist/icons/index.js +2 -0
- package/dist/icons/spinner.js +18 -0
- package/dist/utilities/general.js +8 -4140
- package/dist/utilities/hash.js +30 -0
- package/dist/utilities/index.js +12 -7
- package/dist/utilities/web-workers.js +50 -0
- package/dist/workers/image-analysis.worker.js +52 -0
- package/package.json +16 -14
|
@@ -1,4142 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
Lane2[Lane2["BLUE"] = 1] = "BLUE";
|
|
4
|
-
Lane2[Lane2["GREEN"] = 2] = "GREEN";
|
|
5
|
-
Lane2[Lane2["RED"] = 3] = "RED";
|
|
6
|
-
return Lane2;
|
|
7
|
-
})(Lane || {});
|
|
8
|
-
const ROT_IDS = ["rotateCW", "rotate180", "rotateCCW"];
|
|
9
|
-
const adaptiveCanvas2d = (width, height = width, parent, opts = {}) => {
|
|
10
|
-
const canvas = document.createElement("canvas");
|
|
11
|
-
adaptDPI(canvas, width, height, opts.dpr);
|
|
12
|
-
opts.pixelated && (canvas.style.imageRendering = "pixelated");
|
|
13
|
-
return {
|
|
14
|
-
canvas,
|
|
15
|
-
ctx: canvas.getContext("2d", opts.ctx)
|
|
16
|
-
};
|
|
17
|
-
};
|
|
18
|
-
const canvas2d = (width, height = width, parent, opts) => adaptiveCanvas2d(width, height, parent, { dpr: 1, ...opts });
|
|
19
|
-
const adaptDPI = (canvas, width, height, dpr = window.devicePixelRatio || 1) => {
|
|
20
|
-
if (dpr !== 1) {
|
|
21
|
-
canvas.style.width = `${width}px`;
|
|
22
|
-
canvas.style.height = `${height}px`;
|
|
23
|
-
}
|
|
24
|
-
canvas.width = width * dpr;
|
|
25
|
-
canvas.height = height * dpr;
|
|
26
|
-
return dpr;
|
|
27
|
-
};
|
|
28
|
-
const isNumber = (x) => typeof x === "number";
|
|
29
|
-
function canvasPixels(width, height, parent, opts) {
|
|
30
|
-
let canvas;
|
|
31
|
-
let ctx;
|
|
32
|
-
if (isNumber(width)) {
|
|
33
|
-
const c2 = canvas2d(width, height, parent, opts);
|
|
34
|
-
canvas = c2.canvas;
|
|
35
|
-
ctx = c2.ctx;
|
|
36
|
-
} else {
|
|
37
|
-
canvas = width;
|
|
38
|
-
ctx = canvas.getContext("2d");
|
|
39
|
-
}
|
|
40
|
-
const img = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
|
41
|
-
const data = new Uint32Array(img.data.buffer);
|
|
42
|
-
return {
|
|
43
|
-
canvas,
|
|
44
|
-
ctx,
|
|
45
|
-
img,
|
|
46
|
-
data
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
const nomixin = (_, __, descriptor) => {
|
|
50
|
-
descriptor.configurable = false;
|
|
51
|
-
};
|
|
52
|
-
const mixin = (behaviour, sharedBehaviour = {}) => {
|
|
53
|
-
const instanceKeys = Reflect.ownKeys(behaviour);
|
|
54
|
-
const sharedKeys = Reflect.ownKeys(sharedBehaviour);
|
|
55
|
-
const typeTag = Symbol("isa");
|
|
56
|
-
function _mixin(clazz) {
|
|
57
|
-
for (let key of instanceKeys) {
|
|
58
|
-
const existing = Object.getOwnPropertyDescriptor(
|
|
59
|
-
clazz.prototype,
|
|
60
|
-
key
|
|
61
|
-
);
|
|
62
|
-
if (!existing || existing.configurable) {
|
|
63
|
-
Object.defineProperty(clazz.prototype, key, {
|
|
64
|
-
value: behaviour[key],
|
|
65
|
-
writable: true
|
|
66
|
-
});
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
Object.defineProperty(clazz.prototype, typeTag, { value: true });
|
|
70
|
-
return clazz;
|
|
71
|
-
}
|
|
72
|
-
for (let key of sharedKeys) {
|
|
73
|
-
Object.defineProperty(_mixin, key, {
|
|
74
|
-
value: sharedBehaviour[key],
|
|
75
|
-
enumerable: sharedBehaviour.propertyIsEnumerable(key)
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
Object.defineProperty(_mixin, Symbol.hasInstance, {
|
|
79
|
-
value: (x) => !!x[typeTag]
|
|
80
|
-
});
|
|
81
|
-
return _mixin;
|
|
82
|
-
};
|
|
83
|
-
mixin({
|
|
84
|
-
order() {
|
|
85
|
-
return [0];
|
|
86
|
-
},
|
|
87
|
-
includes(x) {
|
|
88
|
-
return x >= 0 && x < this.size[0];
|
|
89
|
-
},
|
|
90
|
-
indexAt(x) {
|
|
91
|
-
return this.includes(x) ? this.indexAtUnsafe(x) : -1;
|
|
92
|
-
},
|
|
93
|
-
indexAtUnsafe(x) {
|
|
94
|
-
return this.offset + (x | 0) * this.stride[0];
|
|
95
|
-
},
|
|
96
|
-
getAt(x) {
|
|
97
|
-
return this.includes(x) ? this.data[this.indexAtUnsafe(x)] : 0;
|
|
98
|
-
},
|
|
99
|
-
getAtUnsafe(x) {
|
|
100
|
-
return this.data[this.indexAtUnsafe(x)];
|
|
101
|
-
},
|
|
102
|
-
setAt(x, val) {
|
|
103
|
-
return this.includes(x) ? (this.data[this.indexAtUnsafe(x)] = val, true) : false;
|
|
104
|
-
},
|
|
105
|
-
setAtUnsafe(x, val) {
|
|
106
|
-
this.data[this.indexAtUnsafe(x)] = val;
|
|
107
|
-
return true;
|
|
108
|
-
}
|
|
109
|
-
});
|
|
110
|
-
const IGrid2DMixin = mixin({
|
|
111
|
-
order() {
|
|
112
|
-
return Math.abs(this.stride[1]) > Math.abs(this.stride[0]) ? [1, 0] : [0, 1];
|
|
113
|
-
},
|
|
114
|
-
includes(x, y) {
|
|
115
|
-
const size = this.size;
|
|
116
|
-
return x >= 0 && x < size[0] && y >= 0 && y < size[1];
|
|
117
|
-
},
|
|
118
|
-
indexAt(x, y) {
|
|
119
|
-
return this.includes(x, y) ? this.indexAtUnsafe(x, y) : -1;
|
|
120
|
-
},
|
|
121
|
-
indexAtUnsafe(x, y) {
|
|
122
|
-
return this.offset + (x | 0) * this.stride[0] + (y | 0) * this.stride[1];
|
|
123
|
-
},
|
|
124
|
-
getAt(x, y) {
|
|
125
|
-
return this.includes(x, y) ? this.data[this.indexAtUnsafe(x, y)] : 0;
|
|
126
|
-
},
|
|
127
|
-
getAtUnsafe(x, y) {
|
|
128
|
-
return this.data[this.indexAtUnsafe(x, y)];
|
|
129
|
-
},
|
|
130
|
-
setAt(x, y, val) {
|
|
131
|
-
return this.includes(x, y) ? (this.data[this.indexAtUnsafe(x, y)] = val, true) : false;
|
|
132
|
-
},
|
|
133
|
-
setAtUnsafe(x, y, val) {
|
|
134
|
-
this.data[this.indexAtUnsafe(x, y)] = val;
|
|
135
|
-
return true;
|
|
136
|
-
}
|
|
137
|
-
});
|
|
138
|
-
mixin({
|
|
139
|
-
order() {
|
|
140
|
-
return __strideOrder(this.stride);
|
|
141
|
-
},
|
|
142
|
-
includes(x, y, z) {
|
|
143
|
-
const size = this.size;
|
|
144
|
-
return x >= 0 && x < size[0] && y >= 0 && y < size[1] && z >= 0 && z < size[2];
|
|
145
|
-
},
|
|
146
|
-
indexAt(x, y, z) {
|
|
147
|
-
return this.includes(x, y, z) ? this.indexAtUnsafe(x, y, z) : -1;
|
|
148
|
-
},
|
|
149
|
-
indexAtUnsafe(x, y, z) {
|
|
150
|
-
const stride = this.stride;
|
|
151
|
-
return this.offset + (x | 0) * stride[0] + (y | 0) * stride[1] + (z | 0) * stride[2];
|
|
152
|
-
},
|
|
153
|
-
getAt(x, y, z) {
|
|
154
|
-
return this.includes(x, y, z) ? this.data[this.indexAtUnsafe(x, y, z)] : 0;
|
|
155
|
-
},
|
|
156
|
-
getAtUnsafe(x, y, z) {
|
|
157
|
-
return this.data[this.indexAtUnsafe(x, y, z)];
|
|
158
|
-
},
|
|
159
|
-
setAt(x, y, z, val) {
|
|
160
|
-
return this.includes(x, y, z) ? (this.data[this.indexAtUnsafe(x, y, z)] = val, true) : false;
|
|
161
|
-
},
|
|
162
|
-
setAtUnsafe(x, y, z, val) {
|
|
163
|
-
this.data[this.indexAtUnsafe(x, y, z)] = val;
|
|
164
|
-
return true;
|
|
165
|
-
}
|
|
166
|
-
});
|
|
167
|
-
mixin({
|
|
168
|
-
order() {
|
|
169
|
-
return __strideOrder(this.stride);
|
|
170
|
-
},
|
|
171
|
-
includes(x, y, z, w) {
|
|
172
|
-
const size = this.size;
|
|
173
|
-
return x >= 0 && x < size[0] && y >= 0 && y < size[1] && z >= 0 && z < size[2] && w >= 0 && w < size[3];
|
|
174
|
-
},
|
|
175
|
-
indexAt(x, y, z, w) {
|
|
176
|
-
return this.includes(x, y, z, w) ? this.indexAtUnsafe(x, y, z, w) : -1;
|
|
177
|
-
},
|
|
178
|
-
indexAtUnsafe(x, y, z, w) {
|
|
179
|
-
const stride = this.stride;
|
|
180
|
-
return this.offset + (x | 0) * stride[0] + (y | 0) * stride[1] + (z | 0) * stride[2] + (w | 0) * stride[3];
|
|
181
|
-
},
|
|
182
|
-
getAt(x, y, z, w) {
|
|
183
|
-
return this.includes(x, y, z, w) ? this.data[this.indexAtUnsafe(x, y, z, w)] : 0;
|
|
184
|
-
},
|
|
185
|
-
getAtUnsafe(x, y, z, w) {
|
|
186
|
-
return this.data[this.indexAtUnsafe(x, y, z, w)];
|
|
187
|
-
},
|
|
188
|
-
setAt(x, y, z, w, val) {
|
|
189
|
-
return this.includes(x, y, z, w) ? (this.data[this.indexAtUnsafe(x, y, z, w)] = val, true) : false;
|
|
190
|
-
},
|
|
191
|
-
setAtUnsafe(x, y, z, w, val) {
|
|
192
|
-
this.data[this.indexAtUnsafe(x, y, z, w)] = val;
|
|
193
|
-
return true;
|
|
194
|
-
}
|
|
195
|
-
});
|
|
196
|
-
const __strideOrder = (strides) => [...strides].map((x, i) => [x, i]).sort((a2, b2) => Math.abs(b2[0]) - Math.abs(a2[0])).map((x) => x[1]);
|
|
197
|
-
const isString = (x) => typeof x === "string";
|
|
198
|
-
const defError = (prefix, suffix = (msg) => msg !== void 0 ? ": " + msg : "") => class extends Error {
|
|
199
|
-
origMessage;
|
|
200
|
-
constructor(msg) {
|
|
201
|
-
super(prefix(msg) + suffix(msg));
|
|
202
|
-
this.origMessage = msg !== void 0 ? String(msg) : "";
|
|
203
|
-
}
|
|
204
|
-
};
|
|
205
|
-
const __vite_import_meta_env__ = {};
|
|
206
|
-
const AssertionError = defError(() => "Assertion failed");
|
|
207
|
-
const assert = (typeof process !== "undefined" && process.env !== void 0 ? process.env.NODE_ENV !== "production" || !!process.env.UMBRELLA_ASSERTS : __vite_import_meta_env__ ? false : true) ? (test, msg) => {
|
|
208
|
-
if (typeof test === "function" && !test() || !test) {
|
|
209
|
-
throw new AssertionError(
|
|
210
|
-
typeof msg === "function" ? msg() : msg
|
|
211
|
-
);
|
|
212
|
-
}
|
|
213
|
-
} : () => {
|
|
214
|
-
};
|
|
215
|
-
const clamp$1 = (x, min2, max2) => x < min2 ? min2 : x > max2 ? max2 : x;
|
|
216
|
-
const clamp01 = (x) => x < 0 ? 0 : x > 1 ? 1 : x;
|
|
217
|
-
const setC4$1 = (out, a2, b2, c2, d2) => (out[0] = a2, out[1] = b2, out[2] = c2, out[3] = d2, out);
|
|
218
|
-
const premultiply = (out, src) => {
|
|
219
|
-
const a2 = src[3];
|
|
220
|
-
return setC4$1(src, src[0] * a2, src[1] * a2, src[2] * a2, a2);
|
|
221
|
-
};
|
|
222
|
-
const premultiplyInt = (src) => {
|
|
223
|
-
const a2 = (src >>> 24) / 255;
|
|
224
|
-
return src & 4278190080 | (src >>> 16 & 255) * a2 << 16 | (src >>> 8 & 255) * a2 << 8 | (src & 255) * a2;
|
|
225
|
-
};
|
|
226
|
-
const postmultiply = (out, src) => {
|
|
227
|
-
const a2 = src[3];
|
|
228
|
-
return a2 > 0 ? setC4$1(src, src[0] / a2, src[1] / a2, src[2] / a2, a2) : src;
|
|
229
|
-
};
|
|
230
|
-
const postmultiplyInt = (src) => {
|
|
231
|
-
const a2 = (src >>> 24) / 255;
|
|
232
|
-
return a2 > 0 ? (src & 4278190080 | Math.min(255, (src >>> 16 & 255) / a2) << 16 | Math.min(255, (src >>> 8 & 255) / a2) << 8 | Math.min(255, (src & 255) / a2)) >>> 0 : src;
|
|
233
|
-
};
|
|
234
|
-
const isPremultiplied = (src) => {
|
|
235
|
-
const a2 = src[3];
|
|
236
|
-
return src[0] <= a2 && src[1] <= a2 || src[2] <= a2;
|
|
237
|
-
};
|
|
238
|
-
const isPremultipliedInt = (src) => {
|
|
239
|
-
const a2 = src >>> 24;
|
|
240
|
-
return (src >>> 16 & 255) <= a2 && (src >>> 8 & 255) <= a2 && (src & 255) <= a2;
|
|
241
|
-
};
|
|
242
|
-
const ensureSize = (data, width, height, stride = 1) => assert(data.length >= width * height * stride, "pixel buffer too small");
|
|
243
|
-
const ensureImageData = (data, width, height) => data ? (ensureImageDataSize(data, width, height), data) : new ImageData(width, height);
|
|
244
|
-
const ensureImageDataSize = (data, width, height) => assert(
|
|
245
|
-
data.width === width && data.height === height,
|
|
246
|
-
"imagedata has wrong dimensions"
|
|
247
|
-
);
|
|
248
|
-
const ensureChannel = (fmt, id) => {
|
|
249
|
-
const chan = fmt.channels[id];
|
|
250
|
-
assert(chan != null, `invalid channel ID: ${id}`);
|
|
251
|
-
return chan;
|
|
252
|
-
};
|
|
253
|
-
const ensureAlpha = (fmt) => assert(!!fmt.alpha, "missing alpha channel");
|
|
254
|
-
const identity$1 = (x) => x;
|
|
255
|
-
const __luminanceABGR = (c2) => ((c2 >>> 16 & 255) * 29 + (c2 >>> 8 & 255) * 150 + (c2 & 255) * 76) / 255;
|
|
256
|
-
const __clampRegion = (sx, sy, w, h, maxw, maxh, dx = 0, dy = 0) => {
|
|
257
|
-
sx |= 0;
|
|
258
|
-
sy |= 0;
|
|
259
|
-
w |= 0;
|
|
260
|
-
h |= 0;
|
|
261
|
-
sx < 0 && (w += sx, dx -= sx, sx = 0);
|
|
262
|
-
sy < 0 && (h += sy, dy -= sy, sy = 0);
|
|
263
|
-
return [sx, sy, clamp$1(w, 0, maxw - sx), clamp$1(h, 0, maxh - sy), dx, dy];
|
|
264
|
-
};
|
|
265
|
-
const __prepRegions = (src, dest, opts = {}) => {
|
|
266
|
-
const sw = src.width;
|
|
267
|
-
const dw = dest.width;
|
|
268
|
-
let sx, sy;
|
|
269
|
-
let dx, dy;
|
|
270
|
-
let rw, rh;
|
|
271
|
-
[sx, sy, rw, rh] = __clampRegion(
|
|
272
|
-
opts.sx || 0,
|
|
273
|
-
opts.sy || 0,
|
|
274
|
-
opts.w || sw,
|
|
275
|
-
opts.h || src.height,
|
|
276
|
-
sw,
|
|
277
|
-
src.height
|
|
278
|
-
);
|
|
279
|
-
[dx, dy, rw, rh, sx, sy] = __clampRegion(
|
|
280
|
-
opts.dx || 0,
|
|
281
|
-
opts.dy || 0,
|
|
282
|
-
rw,
|
|
283
|
-
rh,
|
|
284
|
-
dw,
|
|
285
|
-
dest.height,
|
|
286
|
-
sx,
|
|
287
|
-
sy
|
|
288
|
-
);
|
|
289
|
-
return { sx, sy, dx, dy, rw, rh };
|
|
290
|
-
};
|
|
291
|
-
const __setChannelUni = (dbuf, src, set5) => {
|
|
292
|
-
for (let i = dbuf.length; i-- > 0; ) {
|
|
293
|
-
dbuf[i] = set5(dbuf[i], src);
|
|
294
|
-
}
|
|
295
|
-
};
|
|
296
|
-
const __setChannelSame = (dbuf, sbuf, get, set5) => {
|
|
297
|
-
for (let i = dbuf.length; i-- > 0; ) {
|
|
298
|
-
dbuf[i] = set5(dbuf[i], get(sbuf[i]));
|
|
299
|
-
}
|
|
300
|
-
};
|
|
301
|
-
const __setChannelConvert = (dbuf, sbuf, from, sto, mask) => {
|
|
302
|
-
const invMask = ~mask;
|
|
303
|
-
for (let i = dbuf.length; i-- > 0; ) {
|
|
304
|
-
dbuf[i] = dbuf[i] & invMask | from(sto(sbuf[i])) & mask;
|
|
305
|
-
}
|
|
306
|
-
};
|
|
307
|
-
const __transformABGR = (pix, format, fn) => {
|
|
308
|
-
const from = format.fromABGR;
|
|
309
|
-
const to = format.toABGR;
|
|
310
|
-
for (let i = pix.length; i-- > 0; ) {
|
|
311
|
-
pix[i] = from(fn(to(pix[i])));
|
|
312
|
-
}
|
|
313
|
-
};
|
|
314
|
-
const __blitCanvas = (buf, canvas, opts = {}) => (canvas instanceof HTMLCanvasElement || canvas instanceof OffscreenCanvas ? canvas.getContext("2d") : canvas).putImageData(buf.toImageData(opts.data), opts.x || 0, opts.y || 0);
|
|
315
|
-
const defFloatFormat = (fmt) => {
|
|
316
|
-
const chan = fmt.channels;
|
|
317
|
-
const chanShift = chan.reduce(
|
|
318
|
-
(acc, ch) => (acc[ch] = 3 - ch << 3, acc),
|
|
319
|
-
{}
|
|
320
|
-
);
|
|
321
|
-
const res = {
|
|
322
|
-
...fmt,
|
|
323
|
-
__float: true,
|
|
324
|
-
size: chan.length,
|
|
325
|
-
shift: chanShift,
|
|
326
|
-
range: [0, 1],
|
|
327
|
-
normalized: clamp01,
|
|
328
|
-
fromNormalized: identity$1
|
|
329
|
-
};
|
|
330
|
-
if (fmt.convert) {
|
|
331
|
-
Object.assign(res, fmt.convert);
|
|
332
|
-
return res;
|
|
333
|
-
}
|
|
334
|
-
const to = (col, i) => (clamp01(col[i]) * 255 + 0.5 | 0) << chanShift[chan[i]];
|
|
335
|
-
const from = (col, i) => (col >>> chanShift[chan[i]] & 255) / 255;
|
|
336
|
-
switch (chan.length) {
|
|
337
|
-
case 1:
|
|
338
|
-
fmt.gray ? __defConvert1Gray(res) : __defConvert1(res, from, to);
|
|
339
|
-
break;
|
|
340
|
-
case 2:
|
|
341
|
-
fmt.gray ? __defConvert2Gray(res, from) : __defConvert2(res, from, to);
|
|
342
|
-
break;
|
|
343
|
-
case 3:
|
|
344
|
-
__defConvert3(res, from, to);
|
|
345
|
-
break;
|
|
346
|
-
case 4:
|
|
347
|
-
__defConvert4(res, from, to);
|
|
348
|
-
break;
|
|
349
|
-
}
|
|
350
|
-
return res;
|
|
351
|
-
};
|
|
352
|
-
const __defConvert1 = (res, from, to) => {
|
|
353
|
-
res.toABGR = (col) => {
|
|
354
|
-
let out = res.alpha ? 0 : 4278190080;
|
|
355
|
-
out |= to(col, 0);
|
|
356
|
-
return out >>> 0;
|
|
357
|
-
};
|
|
358
|
-
res.fromABGR = (col, out = []) => {
|
|
359
|
-
out[0] = from(col, 0);
|
|
360
|
-
return out;
|
|
361
|
-
};
|
|
362
|
-
};
|
|
363
|
-
const __defConvert1Gray = (res) => {
|
|
364
|
-
res.toABGR = (col) => ((clamp01(col[0]) * 255 + 0.5 | 0) * 65793 | 4278190080) >>> 0;
|
|
365
|
-
res.fromABGR = (col, out = []) => (out[0] = __luminanceABGR(col) / 255, out);
|
|
366
|
-
};
|
|
367
|
-
const __defConvert2 = (res, from, to) => {
|
|
368
|
-
res.toABGR = (col) => {
|
|
369
|
-
let out = res.alpha ? 0 : 4278190080;
|
|
370
|
-
out |= to(col, 0);
|
|
371
|
-
out |= to(col, 1);
|
|
372
|
-
return out >>> 0;
|
|
373
|
-
};
|
|
374
|
-
res.fromABGR = (col, out = []) => {
|
|
375
|
-
out[0] = from(col, 0);
|
|
376
|
-
out[1] = from(col, 1);
|
|
377
|
-
return out;
|
|
378
|
-
};
|
|
379
|
-
};
|
|
380
|
-
const __defConvert2Gray = (res, from) => {
|
|
381
|
-
const gray = ~~(res.channels[0] === Lane.ALPHA);
|
|
382
|
-
const alpha = gray ^ 1;
|
|
383
|
-
res.toABGR = (col) => {
|
|
384
|
-
let out = (clamp01(col[gray]) * 255 + 0.5 | 0) * 65793;
|
|
385
|
-
out |= (col[alpha] * 255 + 0.5 | 0) << 24;
|
|
386
|
-
return out >>> 0;
|
|
387
|
-
};
|
|
388
|
-
res.fromABGR = (col, out = []) => {
|
|
389
|
-
out[gray] = __luminanceABGR(col) / 255;
|
|
390
|
-
out[alpha] = from(col, alpha);
|
|
391
|
-
return out;
|
|
392
|
-
};
|
|
393
|
-
};
|
|
394
|
-
const __defConvert3 = (res, from, to) => {
|
|
395
|
-
res.toABGR = (col) => {
|
|
396
|
-
let out = res.alpha ? 0 : 4278190080;
|
|
397
|
-
out |= to(col, 0);
|
|
398
|
-
out |= to(col, 1);
|
|
399
|
-
out |= to(col, 2);
|
|
400
|
-
return out >>> 0;
|
|
401
|
-
};
|
|
402
|
-
res.fromABGR = (col, out = []) => {
|
|
403
|
-
out[0] = from(col, 0);
|
|
404
|
-
out[1] = from(col, 1);
|
|
405
|
-
out[2] = from(col, 2);
|
|
406
|
-
return out;
|
|
407
|
-
};
|
|
408
|
-
};
|
|
409
|
-
const __defConvert4 = (res, from, to) => {
|
|
410
|
-
res.toABGR = (col) => {
|
|
411
|
-
let out = res.alpha ? 0 : 4278190080;
|
|
412
|
-
out |= to(col, 0);
|
|
413
|
-
out |= to(col, 1);
|
|
414
|
-
out |= to(col, 2);
|
|
415
|
-
out |= to(col, 3);
|
|
416
|
-
return out >>> 0;
|
|
417
|
-
};
|
|
418
|
-
res.fromABGR = (col, out = []) => {
|
|
419
|
-
out[0] = from(col, 0);
|
|
420
|
-
out[1] = from(col, 1);
|
|
421
|
-
out[2] = from(col, 2);
|
|
422
|
-
out[3] = from(col, 3);
|
|
423
|
-
return out;
|
|
424
|
-
};
|
|
425
|
-
};
|
|
426
|
-
const FLOAT_GRAY = defFloatFormat({
|
|
427
|
-
gray: true,
|
|
428
|
-
channels: [Lane.RED]
|
|
429
|
-
});
|
|
430
|
-
const GL2TYPE = {
|
|
431
|
-
[
|
|
432
|
-
5120
|
|
433
|
-
/* I8 */
|
|
434
|
-
]: "i8",
|
|
435
|
-
[
|
|
436
|
-
5121
|
|
437
|
-
/* U8 */
|
|
438
|
-
]: "u8",
|
|
439
|
-
[
|
|
440
|
-
5122
|
|
441
|
-
/* I16 */
|
|
442
|
-
]: "i16",
|
|
443
|
-
[
|
|
444
|
-
5123
|
|
445
|
-
/* U16 */
|
|
446
|
-
]: "u16",
|
|
447
|
-
[
|
|
448
|
-
5124
|
|
449
|
-
/* I32 */
|
|
450
|
-
]: "i32",
|
|
451
|
-
[
|
|
452
|
-
5125
|
|
453
|
-
/* U32 */
|
|
454
|
-
]: "u32",
|
|
455
|
-
[
|
|
456
|
-
5126
|
|
457
|
-
/* F32 */
|
|
458
|
-
]: "f32"
|
|
459
|
-
};
|
|
460
|
-
const FLOAT_ARRAY_CTORS = {
|
|
461
|
-
f32: Float32Array,
|
|
462
|
-
f64: Float64Array
|
|
463
|
-
};
|
|
464
|
-
const INT_ARRAY_CTORS = {
|
|
465
|
-
i8: Int8Array,
|
|
466
|
-
i16: Int16Array,
|
|
467
|
-
i32: Int32Array
|
|
468
|
-
};
|
|
469
|
-
const UINT_ARRAY_CTORS = {
|
|
470
|
-
u8: Uint8Array,
|
|
471
|
-
u8c: Uint8ClampedArray,
|
|
472
|
-
u16: Uint16Array,
|
|
473
|
-
u32: Uint32Array
|
|
474
|
-
};
|
|
475
|
-
const BIGINT_ARRAY_CTORS = {
|
|
476
|
-
i64: BigInt64Array,
|
|
477
|
-
u64: BigUint64Array
|
|
478
|
-
};
|
|
479
|
-
const TYPEDARRAY_CTORS = {
|
|
480
|
-
...FLOAT_ARRAY_CTORS,
|
|
481
|
-
...INT_ARRAY_CTORS,
|
|
482
|
-
...UINT_ARRAY_CTORS
|
|
483
|
-
};
|
|
484
|
-
const asNativeType = (type) => {
|
|
485
|
-
const t = GL2TYPE[type];
|
|
486
|
-
return t !== void 0 ? t : type;
|
|
487
|
-
};
|
|
488
|
-
function typedArray(type, ...args) {
|
|
489
|
-
const ctor = BIGINT_ARRAY_CTORS[type];
|
|
490
|
-
return new (ctor || TYPEDARRAY_CTORS[asNativeType(type)])(...args);
|
|
491
|
-
}
|
|
492
|
-
const uintTypeForBits = (x) => x > 16 ? "u32" : x > 8 ? "u16" : "u8";
|
|
493
|
-
const __compileLShift = (x, shift) => shift > 0 ? `(${x} << ${shift})` : shift < 0 ? `(${x} >>> ${-shift})` : `${x}`;
|
|
494
|
-
const __compileRShift = (x, shift) => __compileLShift(x, -shift);
|
|
495
|
-
const __hex = (x) => `0x${x.toString(16)}`;
|
|
496
|
-
const __compileGrayFromABGR = (size) => {
|
|
497
|
-
const shift = 8 - size;
|
|
498
|
-
const mask = (1 << size) - 1;
|
|
499
|
-
return new Function(
|
|
500
|
-
"luma",
|
|
501
|
-
`return (x) => ${__compileRShift("luma(x)", shift)} & ${mask};`
|
|
502
|
-
)(__luminanceABGR);
|
|
503
|
-
};
|
|
504
|
-
const __compileGrayToABGR = (size) => {
|
|
505
|
-
let body;
|
|
506
|
-
if (size !== 8) {
|
|
507
|
-
const mask = (1 << size) - 1;
|
|
508
|
-
const scale = 255 / mask;
|
|
509
|
-
body = `(((x & ${mask}) * ${scale}) | 0)`;
|
|
510
|
-
} else {
|
|
511
|
-
body = "x";
|
|
512
|
-
}
|
|
513
|
-
return new Function("x", `return 0xff000000 | (${body} * 0x010101);`);
|
|
514
|
-
};
|
|
515
|
-
const __compileFromABGR = (chans) => new Function(
|
|
516
|
-
"x",
|
|
517
|
-
"return (" + chans.map((ch) => {
|
|
518
|
-
const shift = ch.abgrShift + (8 - ch.size);
|
|
519
|
-
return `(${__compileRShift("x", shift)} & ${__hex(
|
|
520
|
-
ch.maskA
|
|
521
|
-
)})`;
|
|
522
|
-
}).join(" | ") + ") >>> 0;"
|
|
523
|
-
);
|
|
524
|
-
const __compileToABGR = (chans, hasAlpha) => {
|
|
525
|
-
const body = chans.map((ch) => {
|
|
526
|
-
if (ch.size !== 8) {
|
|
527
|
-
const mask = ch.mask0;
|
|
528
|
-
const scale = 255 / mask;
|
|
529
|
-
const inner = __compileRShift("x", ch.shift);
|
|
530
|
-
return __compileLShift(
|
|
531
|
-
`((${inner} & ${mask}) * ${scale})`,
|
|
532
|
-
24 - ch.lane * 8
|
|
533
|
-
);
|
|
534
|
-
} else {
|
|
535
|
-
return __compileLShift(
|
|
536
|
-
`(x & ${__hex(ch.maskA)})`,
|
|
537
|
-
ch.abgrShift
|
|
538
|
-
);
|
|
539
|
-
}
|
|
540
|
-
}).join(" | ");
|
|
541
|
-
const alpha = !hasAlpha ? `0xff000000 | ` : "";
|
|
542
|
-
return new Function("x", `return (${alpha}${body}) >>> 0;`);
|
|
543
|
-
};
|
|
544
|
-
const __defChannel = (ch, idx, shift) => {
|
|
545
|
-
const num = 1 << ch.size;
|
|
546
|
-
const mask0 = num - 1;
|
|
547
|
-
const maskA = mask0 << shift >>> 0;
|
|
548
|
-
const invMask = ~maskA >>> 0;
|
|
549
|
-
const lane = ch.lane != null ? ch.lane : idx;
|
|
550
|
-
const int = (x) => x >>> shift & mask0;
|
|
551
|
-
const setInt = (src, x) => src & invMask | (x & mask0) << shift;
|
|
552
|
-
return {
|
|
553
|
-
size: ch.size,
|
|
554
|
-
num,
|
|
555
|
-
abgrShift: 24 - lane * 8 - shift,
|
|
556
|
-
lane,
|
|
557
|
-
shift,
|
|
558
|
-
mask0,
|
|
559
|
-
maskA,
|
|
560
|
-
int,
|
|
561
|
-
setInt,
|
|
562
|
-
float: (x) => int(x) / mask0,
|
|
563
|
-
setFloat: (src, x) => setInt(src, clamp01(x) * mask0)
|
|
564
|
-
};
|
|
565
|
-
};
|
|
566
|
-
const defIntFormat = (fmt) => {
|
|
567
|
-
assert(fmt.channels.length > 0, "no channel specs given");
|
|
568
|
-
const channels = fmt.channels.reduce(
|
|
569
|
-
([defs, shift], ch, i) => {
|
|
570
|
-
shift -= ch.size;
|
|
571
|
-
defs.push(__defChannel(ch, i, shift));
|
|
572
|
-
return [defs, shift];
|
|
573
|
-
},
|
|
574
|
-
[[], fmt.size]
|
|
575
|
-
)[0];
|
|
576
|
-
return {
|
|
577
|
-
__packed: true,
|
|
578
|
-
type: fmt.type,
|
|
579
|
-
size: fmt.size,
|
|
580
|
-
alpha: fmt.alpha || 0,
|
|
581
|
-
channels,
|
|
582
|
-
fromABGR: fmt.fromABGR || __compileFromABGR(channels),
|
|
583
|
-
toABGR: fmt.toABGR || __compileToABGR(channels, !!fmt.alpha)
|
|
584
|
-
};
|
|
585
|
-
};
|
|
586
|
-
const ABGR8888 = defIntFormat({
|
|
587
|
-
type: "u32",
|
|
588
|
-
size: 32,
|
|
589
|
-
alpha: 8,
|
|
590
|
-
channels: [
|
|
591
|
-
{ size: 8, lane: Lane.ALPHA },
|
|
592
|
-
{ size: 8, lane: Lane.BLUE },
|
|
593
|
-
{ size: 8, lane: Lane.GREEN },
|
|
594
|
-
{ size: 8, lane: Lane.RED }
|
|
595
|
-
],
|
|
596
|
-
fromABGR: identity$1,
|
|
597
|
-
toABGR: identity$1
|
|
598
|
-
});
|
|
599
|
-
const PI = Math.PI;
|
|
600
|
-
const TAU = PI * 2;
|
|
601
|
-
const INV_TAU = 1 / TAU;
|
|
602
|
-
let EPS = 1e-6;
|
|
603
|
-
const mixBilinear = (a2, b2, c2, d2, u, v) => {
|
|
604
|
-
const iu = 1 - u;
|
|
605
|
-
const iv = 1 - v;
|
|
606
|
-
return a2 * iu * iv + b2 * u * iv + c2 * iu * v + d2 * u * v;
|
|
607
|
-
};
|
|
608
|
-
const mixCubicHermiteFromPoints = (a2, b2, c2, d2, t) => {
|
|
609
|
-
d2 *= 0.5;
|
|
610
|
-
const aa = -0.5 * a2 + 1.5 * b2 - 1.5 * c2 + d2;
|
|
611
|
-
const bb = a2 - 2.5 * b2 + 2 * c2 - d2;
|
|
612
|
-
const cc = -0.5 * a2 + 0.5 * c2;
|
|
613
|
-
const dd = b2;
|
|
614
|
-
const t2 = t * t;
|
|
615
|
-
return t * t2 * aa + t2 * bb + t * cc + dd;
|
|
616
|
-
};
|
|
617
|
-
const mixBicubic = (s00, s01, s02, s03, s10, s11, s12, s13, s20, s21, s22, s23, s30, s31, s32, s33, u, v) => mixCubicHermiteFromPoints(
|
|
618
|
-
mixCubicHermiteFromPoints(s00, s01, s02, s03, u),
|
|
619
|
-
mixCubicHermiteFromPoints(s10, s11, s12, s13, u),
|
|
620
|
-
mixCubicHermiteFromPoints(s20, s21, s22, s23, u),
|
|
621
|
-
mixCubicHermiteFromPoints(s30, s31, s32, s33, u),
|
|
622
|
-
v
|
|
623
|
-
);
|
|
624
|
-
const mod = (a2, b2) => a2 - b2 * Math.floor(a2 / b2);
|
|
625
|
-
const fract = (x) => x - Math.floor(x);
|
|
626
|
-
const roundTo = (x, prec = 1) => Math.round(x / prec) * prec;
|
|
627
|
-
function defSampler(src, filter = "linear", wrap = "clamp") {
|
|
628
|
-
const isFloat = !!src.format.__float;
|
|
629
|
-
const suffix = src.format.channels.length === 1 ? "1" : "";
|
|
630
|
-
const id = `${filter[0]}${wrap[0]}${suffix}`;
|
|
631
|
-
const impl = (isFloat ? {
|
|
632
|
-
nc1: __sampleFNC,
|
|
633
|
-
nw1: __sampleFNW,
|
|
634
|
-
nr1: __sampleFNR,
|
|
635
|
-
nc: __sampleFNC,
|
|
636
|
-
nw: __sampleFNW,
|
|
637
|
-
nr: __sampleFNR,
|
|
638
|
-
lc1: (src2) => __bilinearGrayF(__sampleINC(src2)),
|
|
639
|
-
lw1: (src2) => __bilinearGrayF(__sampleINW(src2)),
|
|
640
|
-
lr1: (src2) => __bilinearGrayF(__sampleINR(src2)),
|
|
641
|
-
lc: (src2) => __bilinearFloat(src2, __sampleFNC(src2)),
|
|
642
|
-
lw: (src2) => __bilinearFloat(src2, __sampleFNW(src2)),
|
|
643
|
-
lr: (src2) => __bilinearFloat(src2, __sampleFNR(src2)),
|
|
644
|
-
cc1: (src2) => __bicubicGrayF(__sampleINC(src2)),
|
|
645
|
-
cw1: (src2) => __bicubicGrayF(__sampleINW(src2)),
|
|
646
|
-
cr1: (src2) => __bicubicGrayF(__sampleINR(src2)),
|
|
647
|
-
cc: (src2) => __bicubicFloat(src2, __sampleFNC(src2)),
|
|
648
|
-
cw: (src2) => __bicubicFloat(src2, __sampleFNW(src2)),
|
|
649
|
-
cr: (src2) => __bicubicFloat(src2, __sampleFNR(src2))
|
|
650
|
-
} : {
|
|
651
|
-
nc1: __sampleINC,
|
|
652
|
-
nw1: __sampleINW,
|
|
653
|
-
nr1: __sampleINR,
|
|
654
|
-
nc: __sampleINC,
|
|
655
|
-
nw: __sampleINW,
|
|
656
|
-
nr: __sampleINR,
|
|
657
|
-
lc1: (src2) => __bilinearGray(__sampleINC(src2)),
|
|
658
|
-
lw1: (src2) => __bilinearGray(__sampleINW(src2)),
|
|
659
|
-
lr1: (src2) => __bilinearGray(__sampleINR(src2)),
|
|
660
|
-
lc: (src2) => __bilinearABGR(src2, __sampleINC(src2)),
|
|
661
|
-
lw: (src2) => __bilinearABGR(src2, __sampleINW(src2)),
|
|
662
|
-
lr: (src2) => __bilinearABGR(src2, __sampleINR(src2)),
|
|
663
|
-
cc1: (src2) => __bicubicGrayI(src2, __sampleINC(src2)),
|
|
664
|
-
cw1: (src2) => __bicubicGrayI(src2, __sampleINW(src2)),
|
|
665
|
-
cr1: (src2) => __bicubicGrayI(src2, __sampleINR(src2)),
|
|
666
|
-
cc: (src2) => __bicubicABGR(src2, __sampleINC(src2)),
|
|
667
|
-
cw: (src2) => __bicubicABGR(src2, __sampleINW(src2)),
|
|
668
|
-
cr: (src2) => __bicubicABGR(src2, __sampleINR(src2))
|
|
669
|
-
})[id];
|
|
670
|
-
assert(!!impl, `missing impl for ${id}`);
|
|
671
|
-
return impl(src);
|
|
672
|
-
}
|
|
673
|
-
const __sampleINC = ({ data, width, height }) => (x, y) => x >= 0 && x < width && y >= 0 && y < height ? data[(y | 0) * width + (x | 0)] : 0;
|
|
674
|
-
const __sampleINW = ({ data, width, height }) => (x, y) => data[mod(y | 0, height) * width + mod(x | 0, width)];
|
|
675
|
-
const __sampleINR = ({ data, width, height }) => {
|
|
676
|
-
const w1 = width - 1;
|
|
677
|
-
const h1 = height - 1;
|
|
678
|
-
return (x, y) => data[clamp$1(y | 0, 0, h1) * width + clamp$1(x | 0, 0, w1)];
|
|
679
|
-
};
|
|
680
|
-
const __sampleFNC = ({
|
|
681
|
-
data,
|
|
682
|
-
width,
|
|
683
|
-
height,
|
|
684
|
-
stride: [stride, rowStride]
|
|
685
|
-
}) => (x, y) => {
|
|
686
|
-
let i;
|
|
687
|
-
return x >= 0 && x < width && y >= 0 && y < height ? (i = (y | 0) * rowStride + (x | 0) * stride, data.slice(i, i + stride)) : [0];
|
|
688
|
-
};
|
|
689
|
-
const __sampleFNW = ({
|
|
690
|
-
data,
|
|
691
|
-
width,
|
|
692
|
-
height,
|
|
693
|
-
stride: [stride, rowStride]
|
|
694
|
-
}) => (x, y) => {
|
|
695
|
-
let i = mod(y | 0, height) * rowStride + mod(x | 0, width) * stride;
|
|
696
|
-
return data.slice(i, i + stride);
|
|
697
|
-
};
|
|
698
|
-
const __sampleFNR = ({
|
|
699
|
-
data,
|
|
700
|
-
width,
|
|
701
|
-
height,
|
|
702
|
-
stride: [stride, rowStride]
|
|
703
|
-
}) => {
|
|
704
|
-
const w1 = width - 1;
|
|
705
|
-
const h1 = height - 1;
|
|
706
|
-
return (x, y) => {
|
|
707
|
-
let i = clamp$1(y | 0, 0, h1) * rowStride + clamp$1(x | 0, 0, w1) * stride;
|
|
708
|
-
return data.slice(i, i + stride);
|
|
709
|
-
};
|
|
710
|
-
};
|
|
711
|
-
const __mixBilinearChan = (buf, u, v, i, s = 4) => mixBilinear(buf[i], buf[i + s], buf[i + 2 * s], buf[i + 3 * s], u, v);
|
|
712
|
-
const __bilinearGray = (sample) => (x, y) => {
|
|
713
|
-
x -= 0.5;
|
|
714
|
-
y -= 0.5;
|
|
715
|
-
return mixBilinear(
|
|
716
|
-
sample(x, y),
|
|
717
|
-
sample(x + 1, y),
|
|
718
|
-
sample(x, y + 1),
|
|
719
|
-
sample(x + 1, y + 1),
|
|
720
|
-
fract(x),
|
|
721
|
-
fract(y)
|
|
722
|
-
);
|
|
723
|
-
};
|
|
724
|
-
const __bilinearGrayF = (sample) => {
|
|
725
|
-
sample = __bilinearGray(sample);
|
|
726
|
-
return (x, y) => [sample(x, y)];
|
|
727
|
-
};
|
|
728
|
-
const __bilinearABGR = (src, sample1) => {
|
|
729
|
-
const { fromABGR, toABGR } = src.format;
|
|
730
|
-
const u32 = new Uint32Array(4);
|
|
731
|
-
const u8 = new Uint8Array(u32.buffer);
|
|
732
|
-
return (x, y) => {
|
|
733
|
-
x -= 0.5;
|
|
734
|
-
y -= 0.5;
|
|
735
|
-
u32[0] = toABGR(sample1(x, y));
|
|
736
|
-
u32[1] = toABGR(sample1(x + 1, y));
|
|
737
|
-
u32[2] = toABGR(sample1(x, y + 1));
|
|
738
|
-
u32[3] = toABGR(sample1(x + 1, y + 1));
|
|
739
|
-
const u = fract(x);
|
|
740
|
-
const v = fract(y);
|
|
741
|
-
return fromABGR(
|
|
742
|
-
__mixBilinearChan(u8, u, v, 0) | __mixBilinearChan(u8, u, v, 1) << 8 | __mixBilinearChan(u8, u, v, 2) << 16 | __mixBilinearChan(u8, u, v, 3) << 24
|
|
743
|
-
) >>> 0;
|
|
744
|
-
};
|
|
745
|
-
};
|
|
746
|
-
const __bilinearFloat = ({ stride: [stride] }, sample1) => {
|
|
747
|
-
const f32 = new Float32Array(stride * 4);
|
|
748
|
-
return (x, y) => {
|
|
749
|
-
x -= 0.5;
|
|
750
|
-
y -= 0.5;
|
|
751
|
-
f32.set(sample1(x, y), 0);
|
|
752
|
-
f32.set(sample1(x + 1, y), stride);
|
|
753
|
-
f32.set(sample1(x, y + 1), stride * 2);
|
|
754
|
-
f32.set(sample1(x + 1, y + 1), stride * 3);
|
|
755
|
-
const u = fract(x);
|
|
756
|
-
const v = fract(y);
|
|
757
|
-
let res = [];
|
|
758
|
-
for (let i = 0; i < stride; i++) {
|
|
759
|
-
res.push(__mixBilinearChan(f32, u, v, i, stride));
|
|
760
|
-
}
|
|
761
|
-
return res;
|
|
762
|
-
};
|
|
763
|
-
};
|
|
764
|
-
const __bicubicGray = (sample) => (x, y) => {
|
|
765
|
-
x -= 0.5;
|
|
766
|
-
y -= 0.5;
|
|
767
|
-
const x1 = x - 1;
|
|
768
|
-
const x2 = x + 1;
|
|
769
|
-
const x3 = x + 2;
|
|
770
|
-
const y1 = y - 1;
|
|
771
|
-
const y2 = y + 1;
|
|
772
|
-
const y3 = y + 2;
|
|
773
|
-
return mixBicubic(
|
|
774
|
-
sample(x1, y1),
|
|
775
|
-
sample(x, y1),
|
|
776
|
-
sample(x2, y1),
|
|
777
|
-
sample(x3, y1),
|
|
778
|
-
sample(x1, y),
|
|
779
|
-
sample(x, y),
|
|
780
|
-
sample(x2, y),
|
|
781
|
-
sample(x3, y),
|
|
782
|
-
sample(x1, y2),
|
|
783
|
-
sample(x, y2),
|
|
784
|
-
sample(x2, y2),
|
|
785
|
-
sample(x3, y2),
|
|
786
|
-
sample(x1, y3),
|
|
787
|
-
sample(x, y3),
|
|
788
|
-
sample(x2, y3),
|
|
789
|
-
sample(x3, y3),
|
|
790
|
-
fract(x),
|
|
791
|
-
fract(y)
|
|
792
|
-
);
|
|
793
|
-
};
|
|
794
|
-
const __bicubicGrayI = (src, sample) => {
|
|
795
|
-
const max2 = src.format.channels[0].mask0;
|
|
796
|
-
sample = __bicubicGray(sample);
|
|
797
|
-
return (x, y) => clamp$1(sample(x, y), 0, max2);
|
|
798
|
-
};
|
|
799
|
-
const __bicubicGrayF = (sample) => {
|
|
800
|
-
sample = __bicubicGray(sample);
|
|
801
|
-
return (x, y) => [sample(x, y)];
|
|
802
|
-
};
|
|
803
|
-
const __mixBicubicChan = (buf, u, v, i, s = 4) => mixBicubic(
|
|
804
|
-
buf[i],
|
|
805
|
-
buf[i + s],
|
|
806
|
-
buf[i + 2 * s],
|
|
807
|
-
buf[i + 3 * s],
|
|
808
|
-
buf[i + 4 * s],
|
|
809
|
-
buf[i + 5 * s],
|
|
810
|
-
buf[i + 6 * s],
|
|
811
|
-
buf[i + 7 * s],
|
|
812
|
-
buf[i + 8 * s],
|
|
813
|
-
buf[i + 9 * s],
|
|
814
|
-
buf[i + 10 * s],
|
|
815
|
-
buf[i + 11 * s],
|
|
816
|
-
buf[i + 12 * s],
|
|
817
|
-
buf[i + 13 * s],
|
|
818
|
-
buf[i + 14 * s],
|
|
819
|
-
buf[i + 15 * s],
|
|
820
|
-
u,
|
|
821
|
-
v
|
|
822
|
-
);
|
|
823
|
-
const __mixBicubicChanClamped = (buf, u, v, i, s = 4) => clamp$1(__mixBicubicChan(buf, u, v, i, s), 0, 255);
|
|
824
|
-
const __bicubicABGR = (src, sample) => {
|
|
825
|
-
const { fromABGR, toABGR } = src.format;
|
|
826
|
-
const u32 = new Uint32Array(16);
|
|
827
|
-
const u8 = new Uint8Array(u32.buffer);
|
|
828
|
-
return (x, y) => {
|
|
829
|
-
x -= 0.5;
|
|
830
|
-
y -= 0.5;
|
|
831
|
-
const x1 = x - 1;
|
|
832
|
-
const x2 = x + 1;
|
|
833
|
-
const x3 = x + 2;
|
|
834
|
-
const y1 = y - 1;
|
|
835
|
-
const y2 = y + 1;
|
|
836
|
-
const y3 = y + 2;
|
|
837
|
-
const u = fract(x);
|
|
838
|
-
const v = fract(y);
|
|
839
|
-
u32[0] = toABGR(sample(x1, y1));
|
|
840
|
-
u32[1] = toABGR(sample(x, y1));
|
|
841
|
-
u32[2] = toABGR(sample(x2, y1));
|
|
842
|
-
u32[3] = toABGR(sample(x3, y1));
|
|
843
|
-
u32[4] = toABGR(sample(x1, y));
|
|
844
|
-
u32[5] = toABGR(sample(x, y));
|
|
845
|
-
u32[6] = toABGR(sample(x2, y));
|
|
846
|
-
u32[7] = toABGR(sample(x3, y));
|
|
847
|
-
u32[8] = toABGR(sample(x1, y2));
|
|
848
|
-
u32[9] = toABGR(sample(x, y2));
|
|
849
|
-
u32[10] = toABGR(sample(x2, y2));
|
|
850
|
-
u32[11] = toABGR(sample(x3, y2));
|
|
851
|
-
u32[12] = toABGR(sample(x1, y3));
|
|
852
|
-
u32[13] = toABGR(sample(x, y3));
|
|
853
|
-
u32[14] = toABGR(sample(x2, y3));
|
|
854
|
-
u32[15] = toABGR(sample(x3, y3));
|
|
855
|
-
return fromABGR(
|
|
856
|
-
__mixBicubicChanClamped(u8, u, v, 0) | __mixBicubicChanClamped(u8, u, v, 1) << 8 | __mixBicubicChanClamped(u8, u, v, 2) << 16 | __mixBicubicChanClamped(u8, u, v, 3) << 24
|
|
857
|
-
) >>> 0;
|
|
858
|
-
};
|
|
859
|
-
};
|
|
860
|
-
const __bicubicFloat = ({ stride: [stride] }, sample) => {
|
|
861
|
-
const f32 = new Float32Array(stride * 16);
|
|
862
|
-
return (x, y) => {
|
|
863
|
-
x -= 0.5;
|
|
864
|
-
y -= 0.5;
|
|
865
|
-
const x1 = x - 1;
|
|
866
|
-
const x2 = x + 1;
|
|
867
|
-
const x3 = x + 2;
|
|
868
|
-
const y1 = y - 1;
|
|
869
|
-
const y2 = y + 1;
|
|
870
|
-
const y3 = y + 2;
|
|
871
|
-
const u = fract(x);
|
|
872
|
-
const v = fract(y);
|
|
873
|
-
f32.set(sample(x1, y1), 0);
|
|
874
|
-
f32.set(sample(x, y1), stride);
|
|
875
|
-
f32.set(sample(x2, y1), 2 * stride);
|
|
876
|
-
f32.set(sample(x3, y1), 3 * stride);
|
|
877
|
-
f32.set(sample(x1, y), 4 * stride);
|
|
878
|
-
f32.set(sample(x, y), 5 * stride);
|
|
879
|
-
f32.set(sample(x2, y), 6 * stride);
|
|
880
|
-
f32.set(sample(x3, y), 7 * stride);
|
|
881
|
-
f32.set(sample(x1, y2), 8 * stride);
|
|
882
|
-
f32.set(sample(x, y2), 9 * stride);
|
|
883
|
-
f32.set(sample(x2, y2), 10 * stride);
|
|
884
|
-
f32.set(sample(x3, y2), 11 * stride);
|
|
885
|
-
f32.set(sample(x1, y3), 12 * stride);
|
|
886
|
-
f32.set(sample(x, y3), 13 * stride);
|
|
887
|
-
f32.set(sample(x2, y3), 14 * stride);
|
|
888
|
-
f32.set(sample(x3, y3), 15 * stride);
|
|
889
|
-
let res = [];
|
|
890
|
-
for (let i = 0; i < stride; i++) {
|
|
891
|
-
res.push(__mixBicubicChan(f32, u, v, i, stride));
|
|
892
|
-
}
|
|
893
|
-
return res;
|
|
894
|
-
};
|
|
895
|
-
};
|
|
896
|
-
var __getOwnPropDesc$1 = Object.getOwnPropertyDescriptor;
|
|
897
|
-
var __decorateClass$1 = (decorators, target, key, kind) => {
|
|
898
|
-
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$1(target, key) : target;
|
|
899
|
-
for (var i = decorators.length - 1, decorator; i >= 0; i--)
|
|
900
|
-
if (decorator = decorators[i])
|
|
901
|
-
result = decorator(result) || result;
|
|
902
|
-
return result;
|
|
903
|
-
};
|
|
904
|
-
function intBuffer(...args) {
|
|
905
|
-
return args[0] instanceof IntBuffer ? args[0].as(args[1]) : (
|
|
906
|
-
// @ts-ignore
|
|
907
|
-
new IntBuffer(...args)
|
|
908
|
-
);
|
|
909
|
-
}
|
|
910
|
-
const intBufferFromCanvas = (canvas, fmt = ABGR8888) => {
|
|
911
|
-
const { data } = canvasPixels(canvas);
|
|
912
|
-
const w = canvas.width;
|
|
913
|
-
const h = canvas.height;
|
|
914
|
-
let dest;
|
|
915
|
-
if (fmt === ABGR8888) {
|
|
916
|
-
dest = data;
|
|
917
|
-
} else {
|
|
918
|
-
dest = typedArray(fmt.type, w * h);
|
|
919
|
-
const src = data;
|
|
920
|
-
const from = fmt.fromABGR;
|
|
921
|
-
for (let i = dest.length; i-- > 0; ) {
|
|
922
|
-
dest[i] = from(src[i]);
|
|
923
|
-
}
|
|
924
|
-
}
|
|
925
|
-
return new IntBuffer(w, h, fmt, dest);
|
|
926
|
-
};
|
|
927
|
-
let IntBuffer = class {
|
|
928
|
-
size;
|
|
929
|
-
stride;
|
|
930
|
-
format;
|
|
931
|
-
data;
|
|
932
|
-
constructor(w, h, fmt = ABGR8888, data) {
|
|
933
|
-
this.size = [w, h];
|
|
934
|
-
this.stride = [1, w];
|
|
935
|
-
this.format = fmt.__packed ? fmt : defIntFormat(fmt);
|
|
936
|
-
this.data = data || typedArray(fmt.type, w * h);
|
|
937
|
-
}
|
|
938
|
-
/** @deprecated use `.data` instead */
|
|
939
|
-
get pixels() {
|
|
940
|
-
return this.data;
|
|
941
|
-
}
|
|
942
|
-
get width() {
|
|
943
|
-
return this.size[0];
|
|
944
|
-
}
|
|
945
|
-
get height() {
|
|
946
|
-
return this.size[1];
|
|
947
|
-
}
|
|
948
|
-
// TODO support custom offsets (via ctor arg)
|
|
949
|
-
get offset() {
|
|
950
|
-
return 0;
|
|
951
|
-
}
|
|
952
|
-
get dim() {
|
|
953
|
-
return 2;
|
|
954
|
-
}
|
|
955
|
-
*[Symbol.iterator]() {
|
|
956
|
-
yield* this.data;
|
|
957
|
-
}
|
|
958
|
-
as(fmt) {
|
|
959
|
-
if (!fmt.__float)
|
|
960
|
-
return this.getRegion(
|
|
961
|
-
0,
|
|
962
|
-
0,
|
|
963
|
-
this.width,
|
|
964
|
-
this.height,
|
|
965
|
-
fmt
|
|
966
|
-
);
|
|
967
|
-
const dest = new FloatBuffer(this.width, this.height, fmt);
|
|
968
|
-
const {
|
|
969
|
-
data: dbuf,
|
|
970
|
-
format: dfmt,
|
|
971
|
-
stride: [stride]
|
|
972
|
-
} = dest;
|
|
973
|
-
const { data: sbuf, format: sfmt } = this;
|
|
974
|
-
for (let i = sbuf.length; i-- > 0; ) {
|
|
975
|
-
dbuf.set(dfmt.fromABGR(sfmt.toABGR(sbuf[i])), i * stride);
|
|
976
|
-
}
|
|
977
|
-
return dest;
|
|
978
|
-
}
|
|
979
|
-
copy() {
|
|
980
|
-
const dest = this.empty();
|
|
981
|
-
dest.data.set(this.data);
|
|
982
|
-
return dest;
|
|
983
|
-
}
|
|
984
|
-
empty() {
|
|
985
|
-
return new IntBuffer(this.width, this.height, this.format);
|
|
986
|
-
}
|
|
987
|
-
// @ts-ignore mixin
|
|
988
|
-
order() {
|
|
989
|
-
}
|
|
990
|
-
// @ts-ignore mixin
|
|
991
|
-
includes(x, y) {
|
|
992
|
-
}
|
|
993
|
-
// @ts-ignore mixin
|
|
994
|
-
indexAt(x, y) {
|
|
995
|
-
}
|
|
996
|
-
// @ts-ignore mixin
|
|
997
|
-
indexAtUnsafe(x, y) {
|
|
998
|
-
}
|
|
999
|
-
// @ts-ignore mixin
|
|
1000
|
-
getAt(x, y) {
|
|
1001
|
-
}
|
|
1002
|
-
// @ts-ignore mixin
|
|
1003
|
-
getAtUnsafe(x, y) {
|
|
1004
|
-
}
|
|
1005
|
-
// @ts-ignore mixin
|
|
1006
|
-
setAt(x, y, col) {
|
|
1007
|
-
}
|
|
1008
|
-
// @ts-ignore mixin
|
|
1009
|
-
setAtUnsafe(x, y, col) {
|
|
1010
|
-
}
|
|
1011
|
-
getChannelAt(x, y, id, normalized = false) {
|
|
1012
|
-
const chan = ensureChannel(this.format, id);
|
|
1013
|
-
const col = this.getAt(x, y);
|
|
1014
|
-
return normalized ? chan.float(col) : chan.int(col);
|
|
1015
|
-
}
|
|
1016
|
-
setChannelAt(x, y, id, col, normalized = false) {
|
|
1017
|
-
const chan = ensureChannel(this.format, id);
|
|
1018
|
-
const src = this.getAt(x, y);
|
|
1019
|
-
normalized ? chan.setFloat(src, col) : chan.setInt(src, col);
|
|
1020
|
-
return this;
|
|
1021
|
-
}
|
|
1022
|
-
blend(op, dest, opts) {
|
|
1023
|
-
let sw = this.width;
|
|
1024
|
-
let dw = dest.width;
|
|
1025
|
-
const { sx, sy, dx, dy, rw, rh } = __prepRegions(this, dest, opts);
|
|
1026
|
-
if (rw < 1 || rh < 1) return dest;
|
|
1027
|
-
const sbuf = this.data;
|
|
1028
|
-
const dbuf = dest.data;
|
|
1029
|
-
const sf = this.format.toABGR;
|
|
1030
|
-
const df1 = dest.format.toABGR;
|
|
1031
|
-
const df2 = dest.format.fromABGR;
|
|
1032
|
-
for (let si = (sx | 0) + (sy | 0) * sw, di = (dx | 0) + (dy | 0) * dw, yy = 0; yy < rh; yy++, si += sw, di += dw) {
|
|
1033
|
-
for (let xx = 0; xx < rw; xx++) {
|
|
1034
|
-
dbuf[di + xx] = df2(op(sf(sbuf[si + xx]), df1(dbuf[di + xx])));
|
|
1035
|
-
}
|
|
1036
|
-
}
|
|
1037
|
-
return dest;
|
|
1038
|
-
}
|
|
1039
|
-
blit(dest, opts) {
|
|
1040
|
-
let sw = this.width;
|
|
1041
|
-
let dw = dest.width;
|
|
1042
|
-
const { sx, sy, dx, dy, rw, rh } = __prepRegions(this, dest, opts);
|
|
1043
|
-
if (rw < 1 || rh < 1) return dest;
|
|
1044
|
-
const sbuf = this.data;
|
|
1045
|
-
const dbuf = dest.data;
|
|
1046
|
-
const sf = this.format.toABGR;
|
|
1047
|
-
const df = dest.format.fromABGR;
|
|
1048
|
-
const blitRow = this.format !== dest.format ? (si, di) => {
|
|
1049
|
-
for (let xx = 0; xx < rw; xx++) {
|
|
1050
|
-
dbuf[di + xx] = df(sf(sbuf[si + xx]));
|
|
1051
|
-
}
|
|
1052
|
-
} : (si, di) => dbuf.set(sbuf.subarray(si, si + rw), di);
|
|
1053
|
-
for (let si = (sx | 0) + (sy | 0) * sw, di = (dx | 0) + (dy | 0) * dw, yy = 0; yy < rh; yy++, si += sw, di += dw) {
|
|
1054
|
-
blitRow(si, di);
|
|
1055
|
-
}
|
|
1056
|
-
return dest;
|
|
1057
|
-
}
|
|
1058
|
-
blitCanvas(canvas, opts = {}) {
|
|
1059
|
-
__blitCanvas(this, canvas, opts);
|
|
1060
|
-
}
|
|
1061
|
-
setImageData(idata) {
|
|
1062
|
-
ensureImageDataSize(idata, this.width, this.height);
|
|
1063
|
-
const src = new Uint32Array(idata.data.buffer);
|
|
1064
|
-
const dest = this.data;
|
|
1065
|
-
const fmt = this.format.fromABGR;
|
|
1066
|
-
for (let i = src.length; i-- > 0; ) {
|
|
1067
|
-
dest[i] = fmt(src[i]);
|
|
1068
|
-
}
|
|
1069
|
-
return this;
|
|
1070
|
-
}
|
|
1071
|
-
toImageData(idata) {
|
|
1072
|
-
idata = ensureImageData(idata, this.width, this.height);
|
|
1073
|
-
const dest = new Uint32Array(idata.data.buffer);
|
|
1074
|
-
const src = this.data;
|
|
1075
|
-
const fmt = this.format.toABGR;
|
|
1076
|
-
for (let i = dest.length; i-- > 0; ) {
|
|
1077
|
-
dest[i] = fmt(src[i]);
|
|
1078
|
-
}
|
|
1079
|
-
return idata;
|
|
1080
|
-
}
|
|
1081
|
-
getRegion(x, y, width, height, fmt) {
|
|
1082
|
-
const [sx, sy, w, h] = __clampRegion(
|
|
1083
|
-
x,
|
|
1084
|
-
y,
|
|
1085
|
-
width,
|
|
1086
|
-
height,
|
|
1087
|
-
this.width,
|
|
1088
|
-
this.height
|
|
1089
|
-
);
|
|
1090
|
-
if (w < 1 || h < 1) return;
|
|
1091
|
-
return this.blit(new IntBuffer(w, h, fmt || this.format), {
|
|
1092
|
-
sx,
|
|
1093
|
-
sy,
|
|
1094
|
-
w,
|
|
1095
|
-
h
|
|
1096
|
-
});
|
|
1097
|
-
}
|
|
1098
|
-
getChannel(id) {
|
|
1099
|
-
const chan = ensureChannel(this.format, id);
|
|
1100
|
-
const buf = new IntBuffer(this.width, this.height, {
|
|
1101
|
-
type: uintTypeForBits(chan.size),
|
|
1102
|
-
size: chan.size,
|
|
1103
|
-
channels: [{ size: chan.size, lane: Lane.RED }],
|
|
1104
|
-
fromABGR: __compileGrayFromABGR(chan.size),
|
|
1105
|
-
toABGR: __compileGrayToABGR(chan.size)
|
|
1106
|
-
});
|
|
1107
|
-
const src = this.data;
|
|
1108
|
-
const dest = buf.data;
|
|
1109
|
-
const get = chan.int;
|
|
1110
|
-
for (let i = src.length; i-- > 0; ) {
|
|
1111
|
-
dest[i] = get(src[i]);
|
|
1112
|
-
}
|
|
1113
|
-
return buf;
|
|
1114
|
-
}
|
|
1115
|
-
setChannel(id, src) {
|
|
1116
|
-
const chan = ensureChannel(this.format, id);
|
|
1117
|
-
const dbuf = this.data;
|
|
1118
|
-
const set5 = chan.setInt;
|
|
1119
|
-
if (isNumber(src)) {
|
|
1120
|
-
__setChannelUni(dbuf, src, set5);
|
|
1121
|
-
} else {
|
|
1122
|
-
const sbuf = src.data;
|
|
1123
|
-
const schan = src.format.channels[0];
|
|
1124
|
-
ensureSize(sbuf, this.width, this.height);
|
|
1125
|
-
if (chan.size === schan.size) {
|
|
1126
|
-
__setChannelSame(dbuf, sbuf, schan.int, set5);
|
|
1127
|
-
} else {
|
|
1128
|
-
__setChannelConvert(
|
|
1129
|
-
dbuf,
|
|
1130
|
-
sbuf,
|
|
1131
|
-
this.format.fromABGR,
|
|
1132
|
-
src.format.toABGR,
|
|
1133
|
-
chan.maskA
|
|
1134
|
-
);
|
|
1135
|
-
}
|
|
1136
|
-
}
|
|
1137
|
-
return this;
|
|
1138
|
-
}
|
|
1139
|
-
invert() {
|
|
1140
|
-
const { data, format } = this;
|
|
1141
|
-
const mask = Math.pow(2, format.size - format.alpha) - 1;
|
|
1142
|
-
for (let i = data.length; i-- > 0; ) {
|
|
1143
|
-
data[i] ^= mask;
|
|
1144
|
-
}
|
|
1145
|
-
return this;
|
|
1146
|
-
}
|
|
1147
|
-
premultiply() {
|
|
1148
|
-
ensureAlpha(this.format);
|
|
1149
|
-
__transformABGR(this.data, this.format, premultiplyInt);
|
|
1150
|
-
return this;
|
|
1151
|
-
}
|
|
1152
|
-
postmultiply() {
|
|
1153
|
-
__transformABGR(this.data, this.format, postmultiplyInt);
|
|
1154
|
-
return this;
|
|
1155
|
-
}
|
|
1156
|
-
isPremultiplied() {
|
|
1157
|
-
const pix = this.data;
|
|
1158
|
-
const to = this.format.toABGR;
|
|
1159
|
-
for (let i = pix.length; i-- > 0; ) {
|
|
1160
|
-
if (!isPremultipliedInt(to(pix[i]))) {
|
|
1161
|
-
return false;
|
|
1162
|
-
}
|
|
1163
|
-
}
|
|
1164
|
-
return true;
|
|
1165
|
-
}
|
|
1166
|
-
forEach(f) {
|
|
1167
|
-
const pix = this.data;
|
|
1168
|
-
for (let i = pix.length; i-- > 0; ) {
|
|
1169
|
-
pix[i] = f(pix[i], i);
|
|
1170
|
-
}
|
|
1171
|
-
return this;
|
|
1172
|
-
}
|
|
1173
|
-
fill(x) {
|
|
1174
|
-
this.data.fill(x);
|
|
1175
|
-
}
|
|
1176
|
-
/**
|
|
1177
|
-
* Flips image horizontally.
|
|
1178
|
-
*/
|
|
1179
|
-
flipX() {
|
|
1180
|
-
const { data, width } = this;
|
|
1181
|
-
for (let i = 0; i < data.length; i += width) {
|
|
1182
|
-
data.subarray(i, i + width).reverse();
|
|
1183
|
-
}
|
|
1184
|
-
return this;
|
|
1185
|
-
}
|
|
1186
|
-
/**
|
|
1187
|
-
* Flips image vertically.
|
|
1188
|
-
*/
|
|
1189
|
-
flipY() {
|
|
1190
|
-
const { data, width } = this;
|
|
1191
|
-
const tmp = typedArray(this.format.type, width);
|
|
1192
|
-
for (let i = 0, j = data.length - width; i < j; i += width, j -= width) {
|
|
1193
|
-
tmp.set(data.subarray(i, i + width));
|
|
1194
|
-
data.copyWithin(i, j, j + width);
|
|
1195
|
-
data.set(tmp, j);
|
|
1196
|
-
}
|
|
1197
|
-
return this;
|
|
1198
|
-
}
|
|
1199
|
-
rotateByID(id) {
|
|
1200
|
-
return id > 0 ? this[ROT_IDS[id - 1]]() : this;
|
|
1201
|
-
}
|
|
1202
|
-
rotateCW() {
|
|
1203
|
-
const { width, height } = this;
|
|
1204
|
-
const h1 = height - 1;
|
|
1205
|
-
this._rotate((x, y) => x * height + h1 - y);
|
|
1206
|
-
this.size[0] = height;
|
|
1207
|
-
this.size[1] = width;
|
|
1208
|
-
return this;
|
|
1209
|
-
}
|
|
1210
|
-
rotateCCW() {
|
|
1211
|
-
const { width, height } = this;
|
|
1212
|
-
const w1 = width - 1;
|
|
1213
|
-
this._rotate((x, y) => (w1 - x) * height + y);
|
|
1214
|
-
this.size[0] = height;
|
|
1215
|
-
this.size[1] = width;
|
|
1216
|
-
return this;
|
|
1217
|
-
}
|
|
1218
|
-
rotate180() {
|
|
1219
|
-
const { width, height } = this;
|
|
1220
|
-
const w1 = width - 1;
|
|
1221
|
-
const h1 = height - 1;
|
|
1222
|
-
this._rotate((x, y) => (h1 - y) * width + w1 - x);
|
|
1223
|
-
return this;
|
|
1224
|
-
}
|
|
1225
|
-
/**
|
|
1226
|
-
* Returns scaled version of this buffer using given sampler or filter
|
|
1227
|
-
* (default: `"linear"`) for interpolation. Syntax sugar for
|
|
1228
|
-
* {@link IntBuffer.resize}.
|
|
1229
|
-
*
|
|
1230
|
-
* @param scale -
|
|
1231
|
-
*/
|
|
1232
|
-
scale(scale, sampler = "linear") {
|
|
1233
|
-
assert(scale > 0, `scale must be > 0`);
|
|
1234
|
-
return this.resize(this.width * scale, this.height * scale, sampler);
|
|
1235
|
-
}
|
|
1236
|
-
resize(w, h, sampler = "linear") {
|
|
1237
|
-
w |= 0;
|
|
1238
|
-
h |= 0;
|
|
1239
|
-
assert(w > 0 && h > 0, `target width & height must be > 0`);
|
|
1240
|
-
const dest = intBuffer(w, h, this.format);
|
|
1241
|
-
const dpix = dest.data;
|
|
1242
|
-
const scaleX = w > 0 ? this.width / w : 0;
|
|
1243
|
-
const scaleY = h > 0 ? this.height / h : 0;
|
|
1244
|
-
sampler = isString(sampler) ? defSampler(this, sampler, "repeat") : sampler;
|
|
1245
|
-
for (let y = 0, i = 0; y < h; y++) {
|
|
1246
|
-
const yy = y * scaleY;
|
|
1247
|
-
for (let x = 0; x < w; x++, i++) {
|
|
1248
|
-
dpix[i] = sampler(x * scaleX, yy);
|
|
1249
|
-
}
|
|
1250
|
-
}
|
|
1251
|
-
return dest;
|
|
1252
|
-
}
|
|
1253
|
-
upsize() {
|
|
1254
|
-
const { width, height, data } = this;
|
|
1255
|
-
const dest = new IntBuffer(width * 2, height * 2, this.format);
|
|
1256
|
-
const dpix = dest.data;
|
|
1257
|
-
for (let y = 0, si = 0; y < height; y++) {
|
|
1258
|
-
for (let x = 0, di = y * width * 4; x < width; x++, si++, di += 2) {
|
|
1259
|
-
dpix[di] = data[si];
|
|
1260
|
-
}
|
|
1261
|
-
}
|
|
1262
|
-
return dest;
|
|
1263
|
-
}
|
|
1264
|
-
_rotate(idxFn) {
|
|
1265
|
-
const { data, format, width, height } = this;
|
|
1266
|
-
const tmp = typedArray(format.type, width * height);
|
|
1267
|
-
for (let y = 0; y < height; y++) {
|
|
1268
|
-
for (let x = 0; x < width; x++) {
|
|
1269
|
-
tmp[idxFn(x, y)] = data[y * width + x];
|
|
1270
|
-
}
|
|
1271
|
-
}
|
|
1272
|
-
this.data = tmp;
|
|
1273
|
-
}
|
|
1274
|
-
};
|
|
1275
|
-
IntBuffer = __decorateClass$1([
|
|
1276
|
-
IGrid2DMixin
|
|
1277
|
-
], IntBuffer);
|
|
1278
|
-
var __defProp = Object.defineProperty;
|
|
1279
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
1280
|
-
var __decorateClass = (decorators, target, key, kind) => {
|
|
1281
|
-
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
|
|
1282
|
-
for (var i = decorators.length - 1, decorator; i >= 0; i--)
|
|
1283
|
-
if (decorator = decorators[i])
|
|
1284
|
-
result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
1285
|
-
if (kind && result) __defProp(target, key, result);
|
|
1286
|
-
return result;
|
|
1287
|
-
};
|
|
1288
|
-
function floatBuffer(...args) {
|
|
1289
|
-
return args[0] instanceof IntBuffer ? (
|
|
1290
|
-
// @ts-ignore
|
|
1291
|
-
floatBufferFromInt(...args)
|
|
1292
|
-
) : (
|
|
1293
|
-
// @ts-ignore
|
|
1294
|
-
new FloatBuffer(...args)
|
|
1295
|
-
);
|
|
1296
|
-
}
|
|
1297
|
-
const floatBufferFromInt = (src, fmt) => {
|
|
1298
|
-
const dest = new FloatBuffer(src.width, src.height, fmt);
|
|
1299
|
-
const {
|
|
1300
|
-
data: dbuf,
|
|
1301
|
-
format: dfmt,
|
|
1302
|
-
stride: [stride]
|
|
1303
|
-
} = dest;
|
|
1304
|
-
const { data: sbuf, format: sfmt } = src;
|
|
1305
|
-
for (let i = sbuf.length; i-- > 0; ) {
|
|
1306
|
-
dbuf.set(dfmt.fromABGR(sfmt.toABGR(sbuf[i])), i * stride);
|
|
1307
|
-
}
|
|
1308
|
-
return dest;
|
|
1309
|
-
};
|
|
1310
|
-
const floatBufferFromCanvas = (canvas, fmt = FLOAT_RGBA) => intBufferFromCanvas(canvas).as(fmt);
|
|
1311
|
-
let FloatBuffer = class {
|
|
1312
|
-
size;
|
|
1313
|
-
stride;
|
|
1314
|
-
format;
|
|
1315
|
-
data;
|
|
1316
|
-
__empty;
|
|
1317
|
-
constructor(w, h, fmt = FLOAT_RGBA, data) {
|
|
1318
|
-
this.size = [w, h];
|
|
1319
|
-
this.format = fmt.__float ? fmt : defFloatFormat(fmt);
|
|
1320
|
-
const stride = this.format.channels.length;
|
|
1321
|
-
this.stride = [stride, w * stride];
|
|
1322
|
-
this.data = data || new Float32Array(w * h * stride);
|
|
1323
|
-
this.__empty = Object.freeze(new Array(stride).fill(0));
|
|
1324
|
-
}
|
|
1325
|
-
/** @deprecated use `.data` instead */
|
|
1326
|
-
get pixels() {
|
|
1327
|
-
return this.data;
|
|
1328
|
-
}
|
|
1329
|
-
get width() {
|
|
1330
|
-
return this.size[0];
|
|
1331
|
-
}
|
|
1332
|
-
get height() {
|
|
1333
|
-
return this.size[1];
|
|
1334
|
-
}
|
|
1335
|
-
// TODO support custom offsets (via ctor arg)
|
|
1336
|
-
get offset() {
|
|
1337
|
-
return 0;
|
|
1338
|
-
}
|
|
1339
|
-
get dim() {
|
|
1340
|
-
return 2;
|
|
1341
|
-
}
|
|
1342
|
-
*[Symbol.iterator]() {
|
|
1343
|
-
const {
|
|
1344
|
-
data,
|
|
1345
|
-
stride: [stride]
|
|
1346
|
-
} = this;
|
|
1347
|
-
for (let i = 0, n = data.length; i < n; i += stride) {
|
|
1348
|
-
yield data.subarray(i, i + stride);
|
|
1349
|
-
}
|
|
1350
|
-
}
|
|
1351
|
-
as(fmt) {
|
|
1352
|
-
const {
|
|
1353
|
-
width,
|
|
1354
|
-
height,
|
|
1355
|
-
stride: [stride],
|
|
1356
|
-
data,
|
|
1357
|
-
format: { size, normalized: getNormalized, toABGR }
|
|
1358
|
-
} = this;
|
|
1359
|
-
let i = 0, j = 0, n = data.length;
|
|
1360
|
-
if (fmt.__float) {
|
|
1361
|
-
const $fmt = fmt;
|
|
1362
|
-
const dest = new FloatBuffer(width, height, $fmt);
|
|
1363
|
-
const {
|
|
1364
|
-
data: dpixels,
|
|
1365
|
-
stride: [dstride]
|
|
1366
|
-
} = dest;
|
|
1367
|
-
if (size === 1 && $fmt.channels.length === 1) {
|
|
1368
|
-
const setNormalized = $fmt.fromNormalized;
|
|
1369
|
-
for (; i < n; i += stride, j += dstride) {
|
|
1370
|
-
dpixels[j] = setNormalized(getNormalized(data[i]));
|
|
1371
|
-
}
|
|
1372
|
-
} else {
|
|
1373
|
-
for (; i < n; i += stride, j += dstride) {
|
|
1374
|
-
dpixels.set(
|
|
1375
|
-
$fmt.fromABGR(toABGR(data.subarray(i, i + stride))),
|
|
1376
|
-
j
|
|
1377
|
-
);
|
|
1378
|
-
}
|
|
1379
|
-
}
|
|
1380
|
-
return dest;
|
|
1381
|
-
} else {
|
|
1382
|
-
const $fmt = fmt;
|
|
1383
|
-
const dest = new IntBuffer(width, height, $fmt);
|
|
1384
|
-
const dpixels = dest.data;
|
|
1385
|
-
if (size === 1 && $fmt.channels.length === 1) {
|
|
1386
|
-
const setFloat = $fmt.channels[0].setFloat;
|
|
1387
|
-
for (; i < n; i += stride, j++) {
|
|
1388
|
-
dpixels[j] = setFloat(0, getNormalized(data[i]));
|
|
1389
|
-
}
|
|
1390
|
-
} else {
|
|
1391
|
-
for (; i < n; i += stride, j++) {
|
|
1392
|
-
dpixels[j] = $fmt.fromABGR(
|
|
1393
|
-
toABGR(data.subarray(i, i + stride))
|
|
1394
|
-
);
|
|
1395
|
-
}
|
|
1396
|
-
}
|
|
1397
|
-
return dest;
|
|
1398
|
-
}
|
|
1399
|
-
}
|
|
1400
|
-
copy() {
|
|
1401
|
-
const dest = this.empty();
|
|
1402
|
-
dest.data.set(this.data);
|
|
1403
|
-
return dest;
|
|
1404
|
-
}
|
|
1405
|
-
empty() {
|
|
1406
|
-
return new FloatBuffer(this.width, this.height, this.format);
|
|
1407
|
-
}
|
|
1408
|
-
// @ts-ignore mixin
|
|
1409
|
-
order() {
|
|
1410
|
-
}
|
|
1411
|
-
// @ts-ignore mixin
|
|
1412
|
-
includes(x, y) {
|
|
1413
|
-
}
|
|
1414
|
-
// @ts-ignore mixin
|
|
1415
|
-
indexAt(x, y) {
|
|
1416
|
-
}
|
|
1417
|
-
// @ts-ignore mixin
|
|
1418
|
-
indexAtUnsafe(x, y) {
|
|
1419
|
-
}
|
|
1420
|
-
getAt(x, y) {
|
|
1421
|
-
return this.includes(x, y) ? this.getAtUnsafe(x, y) : this.__empty;
|
|
1422
|
-
}
|
|
1423
|
-
getAtUnsafe(x, y) {
|
|
1424
|
-
const idx = this.indexAtUnsafe(x, y);
|
|
1425
|
-
return this.data.subarray(idx, idx + this.stride[0]);
|
|
1426
|
-
}
|
|
1427
|
-
setAt(x, y, col) {
|
|
1428
|
-
return this.includes(x, y) ? (this.data.set(col, this.indexAtUnsafe(x, y)), true) : false;
|
|
1429
|
-
}
|
|
1430
|
-
setAtUnsafe(x, y, col) {
|
|
1431
|
-
this.data.set(col, this.indexAtUnsafe(x, y));
|
|
1432
|
-
return true;
|
|
1433
|
-
}
|
|
1434
|
-
getChannelAt(x, y, id) {
|
|
1435
|
-
ensureChannel(this.format, id);
|
|
1436
|
-
return this.includes(x, y) ? this.data[this.indexAtUnsafe(x, y) + id] : void 0;
|
|
1437
|
-
}
|
|
1438
|
-
setChannelAt(x, y, id, col) {
|
|
1439
|
-
ensureChannel(this.format, id);
|
|
1440
|
-
this.includes(x, y) && (this.data[this.indexAtUnsafe(x, y) + id] = col);
|
|
1441
|
-
return this;
|
|
1442
|
-
}
|
|
1443
|
-
getChannel(id) {
|
|
1444
|
-
ensureChannel(this.format, id);
|
|
1445
|
-
const {
|
|
1446
|
-
data,
|
|
1447
|
-
stride: [stride]
|
|
1448
|
-
} = this;
|
|
1449
|
-
const [min2, max2] = this.format.range;
|
|
1450
|
-
const dest = new Float32Array(this.width * this.height);
|
|
1451
|
-
for (let i = id, j = 0, n = data.length; i < n; i += stride, j++) {
|
|
1452
|
-
dest[j] = clamp$1(data[i], min2, max2);
|
|
1453
|
-
}
|
|
1454
|
-
return new FloatBuffer(this.width, this.height, FLOAT_GRAY, dest);
|
|
1455
|
-
}
|
|
1456
|
-
setChannel(id, src) {
|
|
1457
|
-
ensureChannel(this.format, id);
|
|
1458
|
-
const {
|
|
1459
|
-
data: dest,
|
|
1460
|
-
stride: [stride]
|
|
1461
|
-
} = this;
|
|
1462
|
-
if (isNumber(src)) {
|
|
1463
|
-
for (let i = id, n = dest.length; i < n; i += stride) {
|
|
1464
|
-
dest[i] = src;
|
|
1465
|
-
}
|
|
1466
|
-
} else {
|
|
1467
|
-
const {
|
|
1468
|
-
data: sbuf,
|
|
1469
|
-
stride: [sstride]
|
|
1470
|
-
} = src;
|
|
1471
|
-
ensureSize(sbuf, this.width, this.height, sstride);
|
|
1472
|
-
for (let i = id, j = 0, n = dest.length; i < n; i += stride, j += sstride) {
|
|
1473
|
-
dest[i] = sbuf[j];
|
|
1474
|
-
}
|
|
1475
|
-
}
|
|
1476
|
-
return this;
|
|
1477
|
-
}
|
|
1478
|
-
blend(op, dest, opts) {
|
|
1479
|
-
this.ensureFormat(dest);
|
|
1480
|
-
const { sx, sy, dx, dy, rw, rh } = __prepRegions(this, dest, opts);
|
|
1481
|
-
if (rw < 1 || rh < 1) return dest;
|
|
1482
|
-
const sbuf = this.data;
|
|
1483
|
-
const dbuf = dest.data;
|
|
1484
|
-
const [stride, sw] = this.stride;
|
|
1485
|
-
const dw = dest.stride[1];
|
|
1486
|
-
for (let si = (sx | 0) * stride + (sy | 0) * sw, di = (dx | 0) * stride + (dy | 0) * dw, yy = 0; yy < rh; yy++, si += sw, di += dw) {
|
|
1487
|
-
for (let xx = rw, sii = si, dii = di; xx-- > 0; sii += stride, dii += stride) {
|
|
1488
|
-
const out = dbuf.subarray(dii, dii + stride);
|
|
1489
|
-
op(out, sbuf.subarray(sii, sii + stride), out);
|
|
1490
|
-
}
|
|
1491
|
-
}
|
|
1492
|
-
return dest;
|
|
1493
|
-
}
|
|
1494
|
-
blit(dest, opts) {
|
|
1495
|
-
this.ensureFormat(dest);
|
|
1496
|
-
const { sx, sy, dx, dy, rw, rh } = __prepRegions(this, dest, opts);
|
|
1497
|
-
if (rw < 1 || rh < 1) return dest;
|
|
1498
|
-
const sbuf = this.data;
|
|
1499
|
-
const dbuf = dest.data;
|
|
1500
|
-
const [stride, sw] = this.stride;
|
|
1501
|
-
const dw = dest.stride[1];
|
|
1502
|
-
const rww = rw * stride;
|
|
1503
|
-
for (let si = (sx | 0) * stride + (sy | 0) * sw, di = (dx | 0) * stride + (dy | 0) * dw, yy = 0; yy < rh; yy++, si += sw, di += dw) {
|
|
1504
|
-
dbuf.set(sbuf.subarray(si, si + rww), di);
|
|
1505
|
-
}
|
|
1506
|
-
return dest;
|
|
1507
|
-
}
|
|
1508
|
-
blitCanvas(canvas, opts = {}) {
|
|
1509
|
-
__blitCanvas(this, canvas, opts);
|
|
1510
|
-
}
|
|
1511
|
-
setImageData(idata) {
|
|
1512
|
-
ensureImageDataSize(idata, this.width, this.height);
|
|
1513
|
-
const src = new Uint32Array(idata.data.buffer);
|
|
1514
|
-
const {
|
|
1515
|
-
data: dest,
|
|
1516
|
-
format: { fromABGR },
|
|
1517
|
-
stride: [stride]
|
|
1518
|
-
} = this;
|
|
1519
|
-
const tmp = [];
|
|
1520
|
-
for (let i = src.length; i-- > 0; ) {
|
|
1521
|
-
dest.set(fromABGR(src[i], tmp), i * stride);
|
|
1522
|
-
}
|
|
1523
|
-
return this;
|
|
1524
|
-
}
|
|
1525
|
-
toImageData(idata) {
|
|
1526
|
-
idata = ensureImageData(idata, this.width, this.height);
|
|
1527
|
-
const dest = new Uint32Array(idata.data.buffer);
|
|
1528
|
-
const {
|
|
1529
|
-
stride: [stride],
|
|
1530
|
-
data,
|
|
1531
|
-
format
|
|
1532
|
-
} = this;
|
|
1533
|
-
for (let i = 0, j = 0, n = data.length; i < n; i += stride, j++) {
|
|
1534
|
-
dest[j] = format.toABGR(data.subarray(i, i + stride));
|
|
1535
|
-
}
|
|
1536
|
-
return idata;
|
|
1537
|
-
}
|
|
1538
|
-
getRegion(x, y, width, height) {
|
|
1539
|
-
const [sx, sy, w, h] = __clampRegion(
|
|
1540
|
-
x,
|
|
1541
|
-
y,
|
|
1542
|
-
width,
|
|
1543
|
-
height,
|
|
1544
|
-
this.width,
|
|
1545
|
-
this.height
|
|
1546
|
-
);
|
|
1547
|
-
if (w < 1 || h < 1) return;
|
|
1548
|
-
return this.blit(new FloatBuffer(w, h, this.format), {
|
|
1549
|
-
sx,
|
|
1550
|
-
sy,
|
|
1551
|
-
w,
|
|
1552
|
-
h
|
|
1553
|
-
});
|
|
1554
|
-
}
|
|
1555
|
-
forEach(f) {
|
|
1556
|
-
const {
|
|
1557
|
-
data,
|
|
1558
|
-
stride: [stride]
|
|
1559
|
-
} = this;
|
|
1560
|
-
for (let i = 0, j = 0, n = data.length; i < n; i += stride, j++) {
|
|
1561
|
-
data.set(f(data.subarray(i, i + stride), j), i);
|
|
1562
|
-
}
|
|
1563
|
-
return this;
|
|
1564
|
-
}
|
|
1565
|
-
fill(x) {
|
|
1566
|
-
assert(
|
|
1567
|
-
x.length <= this.format.channels.length,
|
|
1568
|
-
`fill value has too many channels`
|
|
1569
|
-
);
|
|
1570
|
-
const {
|
|
1571
|
-
data,
|
|
1572
|
-
stride: [stride]
|
|
1573
|
-
} = this;
|
|
1574
|
-
for (let i = 0, n = data.length; i < n; i += stride) {
|
|
1575
|
-
data.set(x, i);
|
|
1576
|
-
}
|
|
1577
|
-
}
|
|
1578
|
-
premultiply() {
|
|
1579
|
-
this.ensureRGBA();
|
|
1580
|
-
const {
|
|
1581
|
-
data,
|
|
1582
|
-
stride: [stride]
|
|
1583
|
-
} = this;
|
|
1584
|
-
for (let i = 0, n = data.length; i < n; i += stride) {
|
|
1585
|
-
premultiply(null, data.subarray(i, i + stride));
|
|
1586
|
-
}
|
|
1587
|
-
return this;
|
|
1588
|
-
}
|
|
1589
|
-
postmultiply() {
|
|
1590
|
-
this.ensureRGBA();
|
|
1591
|
-
const {
|
|
1592
|
-
data,
|
|
1593
|
-
stride: [stride]
|
|
1594
|
-
} = this;
|
|
1595
|
-
for (let i = 0, n = data.length; i < n; i += stride) {
|
|
1596
|
-
postmultiply(null, data.subarray(i, i + stride));
|
|
1597
|
-
}
|
|
1598
|
-
return this;
|
|
1599
|
-
}
|
|
1600
|
-
isPremultiplied() {
|
|
1601
|
-
this.ensureRGBA();
|
|
1602
|
-
const {
|
|
1603
|
-
data,
|
|
1604
|
-
stride: [stride]
|
|
1605
|
-
} = this;
|
|
1606
|
-
for (let i = 0, n = data.length; i < n; i += stride) {
|
|
1607
|
-
if (!isPremultiplied(data.subarray(i, i + stride))) {
|
|
1608
|
-
return false;
|
|
1609
|
-
}
|
|
1610
|
-
}
|
|
1611
|
-
return true;
|
|
1612
|
-
}
|
|
1613
|
-
clamp() {
|
|
1614
|
-
const data = this.data;
|
|
1615
|
-
const [min2, max2] = this.format.range;
|
|
1616
|
-
for (let i = data.length; i-- > 0; ) {
|
|
1617
|
-
data[i] = clamp$1(data[i], min2, max2);
|
|
1618
|
-
}
|
|
1619
|
-
return this;
|
|
1620
|
-
}
|
|
1621
|
-
clampChannel(id) {
|
|
1622
|
-
ensureChannel(this.format, id);
|
|
1623
|
-
const {
|
|
1624
|
-
data,
|
|
1625
|
-
stride: [stride]
|
|
1626
|
-
} = this;
|
|
1627
|
-
const [min2, max2] = this.format.range;
|
|
1628
|
-
for (let i = id, n = data.length; i < n; i += stride) {
|
|
1629
|
-
data[i] = clamp$1(data[i], min2, max2);
|
|
1630
|
-
}
|
|
1631
|
-
}
|
|
1632
|
-
flipX() {
|
|
1633
|
-
const {
|
|
1634
|
-
data,
|
|
1635
|
-
width,
|
|
1636
|
-
height,
|
|
1637
|
-
stride: [sx, sy]
|
|
1638
|
-
} = this;
|
|
1639
|
-
const tmp = new Float32Array(sx);
|
|
1640
|
-
const w1 = width - 1;
|
|
1641
|
-
const w2 = width >>> 1;
|
|
1642
|
-
for (let y = 0; y < height; y++) {
|
|
1643
|
-
for (let x = 0, i = y * sy, j = i + w1 * sx; x < w2; x++, i += sx, j -= sx) {
|
|
1644
|
-
tmp.set(data.subarray(i, i + sx));
|
|
1645
|
-
data.copyWithin(i, j, j + sx);
|
|
1646
|
-
data.set(tmp, j);
|
|
1647
|
-
}
|
|
1648
|
-
}
|
|
1649
|
-
return this;
|
|
1650
|
-
}
|
|
1651
|
-
/**
|
|
1652
|
-
* Flips image vertically.
|
|
1653
|
-
*/
|
|
1654
|
-
flipY() {
|
|
1655
|
-
const data = this.data;
|
|
1656
|
-
const rowStride = this.stride[1];
|
|
1657
|
-
const tmp = new Float32Array(rowStride);
|
|
1658
|
-
for (let i = 0, j = data.length - rowStride; i < j; i += rowStride, j -= rowStride) {
|
|
1659
|
-
tmp.set(data.subarray(i, i + rowStride));
|
|
1660
|
-
data.copyWithin(i, j, j + rowStride);
|
|
1661
|
-
data.set(tmp, j);
|
|
1662
|
-
}
|
|
1663
|
-
return this;
|
|
1664
|
-
}
|
|
1665
|
-
rotateByID(id) {
|
|
1666
|
-
return id > 0 ? this[ROT_IDS[id - 1]]() : this;
|
|
1667
|
-
}
|
|
1668
|
-
rotateCW() {
|
|
1669
|
-
const { width, height } = this;
|
|
1670
|
-
const h1 = height - 1;
|
|
1671
|
-
this._rotate((x, y) => x * height + h1 - y);
|
|
1672
|
-
this.size[0] = height;
|
|
1673
|
-
this.size[1] = width;
|
|
1674
|
-
return this;
|
|
1675
|
-
}
|
|
1676
|
-
rotateCCW() {
|
|
1677
|
-
const { width, height } = this;
|
|
1678
|
-
const w1 = width - 1;
|
|
1679
|
-
this._rotate((x, y) => (w1 - x) * height + y);
|
|
1680
|
-
this.size[0] = height;
|
|
1681
|
-
this.size[1] = width;
|
|
1682
|
-
return this;
|
|
1683
|
-
}
|
|
1684
|
-
rotate180() {
|
|
1685
|
-
const { width, height } = this;
|
|
1686
|
-
const w1 = width - 1;
|
|
1687
|
-
const h1 = height - 1;
|
|
1688
|
-
this._rotate((x, y) => (h1 - y) * width + w1 - x);
|
|
1689
|
-
return this;
|
|
1690
|
-
}
|
|
1691
|
-
invert() {
|
|
1692
|
-
const {
|
|
1693
|
-
data,
|
|
1694
|
-
format,
|
|
1695
|
-
stride: [stride]
|
|
1696
|
-
} = this;
|
|
1697
|
-
for (let i = 0, n = data.length, m = format.alpha ? stride - 1 : stride; i < n; i += stride) {
|
|
1698
|
-
for (let j = 0; j < m; j++) data[i + j] = 1 - data[i + j];
|
|
1699
|
-
}
|
|
1700
|
-
return this;
|
|
1701
|
-
}
|
|
1702
|
-
scale(scale, sampler) {
|
|
1703
|
-
assert(scale > 0, `scale must be > 0`);
|
|
1704
|
-
return this.resize(this.width * scale, this.height * scale, sampler);
|
|
1705
|
-
}
|
|
1706
|
-
resize(w, h, sampler = "linear") {
|
|
1707
|
-
w |= 0;
|
|
1708
|
-
h |= 0;
|
|
1709
|
-
assert(w > 0 && h > 0, `target width & height must be > 0`);
|
|
1710
|
-
const dest = floatBuffer(w, h, this.format);
|
|
1711
|
-
const dpix = dest.data;
|
|
1712
|
-
const scaleX = w > 0 ? this.width / w : 0;
|
|
1713
|
-
const scaleY = h > 0 ? this.height / h : 0;
|
|
1714
|
-
const stride = this.stride[0];
|
|
1715
|
-
sampler = isString(sampler) ? defSampler(this, sampler, "repeat") : sampler;
|
|
1716
|
-
for (let y = 0, i = 0; y < h; y++) {
|
|
1717
|
-
const yy = y * scaleY;
|
|
1718
|
-
for (let x = 0; x < w; x++, i += stride) {
|
|
1719
|
-
dpix.set(sampler(x * scaleX, yy), i);
|
|
1720
|
-
}
|
|
1721
|
-
}
|
|
1722
|
-
return dest;
|
|
1723
|
-
}
|
|
1724
|
-
upsize() {
|
|
1725
|
-
const {
|
|
1726
|
-
width,
|
|
1727
|
-
height,
|
|
1728
|
-
data,
|
|
1729
|
-
stride: [stride, rowStride]
|
|
1730
|
-
} = this;
|
|
1731
|
-
const stride2x = stride * 2;
|
|
1732
|
-
const dest = floatBuffer(width * 2, height * 2, this.format);
|
|
1733
|
-
const dpix = dest.data;
|
|
1734
|
-
for (let y = 0, si = 0; y < height; y++) {
|
|
1735
|
-
for (let x = 0, di = y * rowStride * 4; x < width; x++, si += stride, di += stride2x) {
|
|
1736
|
-
dpix.set(data.subarray(si, si + stride), di);
|
|
1737
|
-
}
|
|
1738
|
-
}
|
|
1739
|
-
return dest;
|
|
1740
|
-
}
|
|
1741
|
-
_rotate(idxFn) {
|
|
1742
|
-
const {
|
|
1743
|
-
data,
|
|
1744
|
-
width,
|
|
1745
|
-
height,
|
|
1746
|
-
stride: [stride]
|
|
1747
|
-
} = this;
|
|
1748
|
-
const tmp = new Float32Array(width * height * stride);
|
|
1749
|
-
for (let y = 0, i = 0; y < height; y++) {
|
|
1750
|
-
for (let x = 0; x < width; x++, i += stride) {
|
|
1751
|
-
tmp.set(data.subarray(i, i + stride), idxFn(x, y) * stride);
|
|
1752
|
-
}
|
|
1753
|
-
}
|
|
1754
|
-
this.data = tmp;
|
|
1755
|
-
}
|
|
1756
|
-
ensureFormat(dest) {
|
|
1757
|
-
assert(
|
|
1758
|
-
dest.format === this.format,
|
|
1759
|
-
`dest buffer format must be same as src`
|
|
1760
|
-
);
|
|
1761
|
-
}
|
|
1762
|
-
ensureRGBA() {
|
|
1763
|
-
assert(this.format === FLOAT_RGBA, "require FLOAT_RGBA format");
|
|
1764
|
-
}
|
|
1765
|
-
};
|
|
1766
|
-
__decorateClass([
|
|
1767
|
-
nomixin
|
|
1768
|
-
], FloatBuffer.prototype, "getAt", 1);
|
|
1769
|
-
__decorateClass([
|
|
1770
|
-
nomixin
|
|
1771
|
-
], FloatBuffer.prototype, "getAtUnsafe", 1);
|
|
1772
|
-
__decorateClass([
|
|
1773
|
-
nomixin
|
|
1774
|
-
], FloatBuffer.prototype, "setAt", 1);
|
|
1775
|
-
__decorateClass([
|
|
1776
|
-
nomixin
|
|
1777
|
-
], FloatBuffer.prototype, "setAtUnsafe", 1);
|
|
1778
|
-
FloatBuffer = __decorateClass([
|
|
1779
|
-
IGrid2DMixin
|
|
1780
|
-
], FloatBuffer);
|
|
1781
|
-
const norm = (x, a2, b2) => (x - a2) / (b2 - a2);
|
|
1782
|
-
const fit = (x, a2, b2, c2, d2) => c2 + (d2 - c2) * norm(x, a2, b2);
|
|
1783
|
-
const abs$1 = Math.abs;
|
|
1784
|
-
const min = Math.min;
|
|
1785
|
-
const FLOAT_HSVA = defFloatFormat({
|
|
1786
|
-
alpha: true,
|
|
1787
|
-
channels: [Lane.RED, Lane.GREEN, Lane.BLUE, Lane.ALPHA],
|
|
1788
|
-
convert: {
|
|
1789
|
-
fromABGR: (x, out = []) => {
|
|
1790
|
-
const a2 = (x >>> 24 & 255) / 255;
|
|
1791
|
-
const b2 = (x >>> 16 & 255) / 255;
|
|
1792
|
-
const g = (x >>> 8 & 255) / 255;
|
|
1793
|
-
const r = (x & 255) / 255;
|
|
1794
|
-
let p0, p1, p2, p3;
|
|
1795
|
-
let q0, q1, q2, q3;
|
|
1796
|
-
if (g < b2) {
|
|
1797
|
-
p0 = b2;
|
|
1798
|
-
p1 = g;
|
|
1799
|
-
p2 = -1;
|
|
1800
|
-
p3 = 2 / 3;
|
|
1801
|
-
} else {
|
|
1802
|
-
p0 = g;
|
|
1803
|
-
p1 = b2;
|
|
1804
|
-
p2 = 0;
|
|
1805
|
-
p3 = -1 / 3;
|
|
1806
|
-
}
|
|
1807
|
-
if (r < p0) {
|
|
1808
|
-
q0 = p0;
|
|
1809
|
-
q1 = p1;
|
|
1810
|
-
q2 = p3;
|
|
1811
|
-
q3 = r;
|
|
1812
|
-
} else {
|
|
1813
|
-
q0 = r;
|
|
1814
|
-
q1 = p1;
|
|
1815
|
-
q2 = p2;
|
|
1816
|
-
q3 = p0;
|
|
1817
|
-
}
|
|
1818
|
-
const c2 = q0 - min(q1, q3);
|
|
1819
|
-
q0 = clamp01(q0);
|
|
1820
|
-
out[0] = clamp01(abs$1((q3 - q1) / (6 * c2 + EPS) + q2));
|
|
1821
|
-
out[1] = clamp01(c2 / (q0 + EPS));
|
|
1822
|
-
out[2] = q0;
|
|
1823
|
-
out[3] = a2;
|
|
1824
|
-
return out;
|
|
1825
|
-
},
|
|
1826
|
-
toABGR: (x) => {
|
|
1827
|
-
const h = x[0] * 6;
|
|
1828
|
-
const s = x[1];
|
|
1829
|
-
const v = x[2] * 255;
|
|
1830
|
-
const a2 = x[3] * 255;
|
|
1831
|
-
const r = ((clamp01(abs$1(h - 3) - 1) - 1) * s + 1) * v;
|
|
1832
|
-
const g = ((clamp01(2 - abs$1(h - 2)) - 1) * s + 1) * v;
|
|
1833
|
-
const b2 = ((clamp01(2 - abs$1(h - 4)) - 1) * s + 1) * v;
|
|
1834
|
-
return (a2 << 24 | b2 << 16 | g << 8 | r) >>> 0;
|
|
1835
|
-
}
|
|
1836
|
-
}
|
|
1837
|
-
});
|
|
1838
|
-
const FLOAT_RGBA = defFloatFormat({
|
|
1839
|
-
alpha: true,
|
|
1840
|
-
channels: [Lane.RED, Lane.GREEN, Lane.BLUE, Lane.ALPHA]
|
|
1841
|
-
});
|
|
1842
|
-
const UnsupportedOperationError = defError(
|
|
1843
|
-
() => "unsupported operation"
|
|
1844
|
-
);
|
|
1845
|
-
const unsupported = (msg) => {
|
|
1846
|
-
throw new UnsupportedOperationError(msg);
|
|
1847
|
-
};
|
|
1848
|
-
const vop = (dispatch = 1, fallback, ...optimized) => {
|
|
1849
|
-
const impls = [, ,].concat(optimized);
|
|
1850
|
-
const fn = (...args) => {
|
|
1851
|
-
const g = impls[args[dispatch].length] || fallback;
|
|
1852
|
-
return g ? g(...args) : unsupported(`no impl for vec size ${args[dispatch].length}`);
|
|
1853
|
-
};
|
|
1854
|
-
fn.add = (dim, fn2) => impls[dim] = fn2;
|
|
1855
|
-
fn.default = (fn2) => fallback = fn2;
|
|
1856
|
-
fn.impl = (dim) => dim != null ? impls[dim] || fallback : fallback;
|
|
1857
|
-
return fn;
|
|
1858
|
-
};
|
|
1859
|
-
const dot2 = (a2, b2) => a2[0] * b2[0] + a2[1] * b2[1];
|
|
1860
|
-
const dot3 = (a2, b2) => a2[0] * b2[0] + a2[1] * b2[1] + a2[2] * b2[2];
|
|
1861
|
-
const dot4 = (a2, b2) => a2[0] * b2[0] + a2[1] * b2[1] + a2[2] * b2[2] + a2[3] * b2[3];
|
|
1862
|
-
const dot = vop(
|
|
1863
|
-
0,
|
|
1864
|
-
(a2, b2) => {
|
|
1865
|
-
let sum5 = 0;
|
|
1866
|
-
for (let i = a2.length; i-- > 0; ) sum5 += a2[i] * b2[i];
|
|
1867
|
-
return sum5;
|
|
1868
|
-
},
|
|
1869
|
-
dot2,
|
|
1870
|
-
dot3,
|
|
1871
|
-
dot4
|
|
1872
|
-
);
|
|
1873
|
-
function memoizeJ(fn, cache = /* @__PURE__ */ Object.create(null)) {
|
|
1874
|
-
return (...args) => {
|
|
1875
|
-
const key = JSON.stringify(args);
|
|
1876
|
-
if (key !== void 0) {
|
|
1877
|
-
return key in cache ? cache[key] : cache[key] = fn.apply(null, args);
|
|
1878
|
-
}
|
|
1879
|
-
return fn.apply(null, args);
|
|
1880
|
-
};
|
|
1881
|
-
}
|
|
1882
|
-
function memoizeO(fn, cache = /* @__PURE__ */ Object.create(null)) {
|
|
1883
|
-
return (...xs) => {
|
|
1884
|
-
const key = xs.join("-");
|
|
1885
|
-
return key in cache ? cache[key] : cache[key] = fn(...xs);
|
|
1886
|
-
};
|
|
1887
|
-
}
|
|
1888
|
-
const repeat$1 = memoizeO((ch, n) => ch.repeat(n));
|
|
1889
|
-
const float = memoizeJ(
|
|
1890
|
-
(prec, special = false) => special ? (x) => __nanOrInf(x) || x.toFixed(prec) : (x) => x.toFixed(prec)
|
|
1891
|
-
);
|
|
1892
|
-
const __nanOrInf = (x) => isNaN(x) ? "NaN" : x === Infinity ? "+∞" : x === -Infinity ? "-∞" : void 0;
|
|
1893
|
-
const percent = (prec = 0) => (x) => (x * 100).toFixed(prec) + "%";
|
|
1894
|
-
const RGB_LUMINANCE_REC601 = [0.299, 0.587, 0.114];
|
|
1895
|
-
const RGB_LUMINANCE_REC709 = [0.2126, 0.7152, 0.0722];
|
|
1896
|
-
const XYZ_RGB_D50 = [
|
|
1897
|
-
3.1338561,
|
|
1898
|
-
-0.9787684,
|
|
1899
|
-
0.0719453,
|
|
1900
|
-
-1.6168667,
|
|
1901
|
-
1.9161415,
|
|
1902
|
-
-0.2289914,
|
|
1903
|
-
-0.4906146,
|
|
1904
|
-
0.033454,
|
|
1905
|
-
1.4052427
|
|
1906
|
-
];
|
|
1907
|
-
const XYZ_RGB_D65 = [
|
|
1908
|
-
3.2404542,
|
|
1909
|
-
-0.969266,
|
|
1910
|
-
0.0556434,
|
|
1911
|
-
-1.5371385,
|
|
1912
|
-
1.8760108,
|
|
1913
|
-
-0.2040259,
|
|
1914
|
-
-0.4985314,
|
|
1915
|
-
0.041556,
|
|
1916
|
-
1.0572252
|
|
1917
|
-
];
|
|
1918
|
-
const D50 = [0.96422, 1, 0.82521];
|
|
1919
|
-
const D65 = [0.95047, 1, 1.08883];
|
|
1920
|
-
const OKLAB_M2 = [
|
|
1921
|
-
0.2104542553,
|
|
1922
|
-
1.9779984951,
|
|
1923
|
-
0.0259040371,
|
|
1924
|
-
0.793617785,
|
|
1925
|
-
-2.428592205,
|
|
1926
|
-
0.7827717662,
|
|
1927
|
-
-0.0040720468,
|
|
1928
|
-
0.4505937099,
|
|
1929
|
-
-0.808675766
|
|
1930
|
-
];
|
|
1931
|
-
let FF = float(3);
|
|
1932
|
-
let PC = percent(3);
|
|
1933
|
-
const INV8BIT = 1 / 255;
|
|
1934
|
-
const luminanceRgb = (rgb2, weights = RGB_LUMINANCE_REC709) => dot3(rgb2, weights);
|
|
1935
|
-
const luminanceSrgb = (rgb2) => dot3(rgb2, RGB_LUMINANCE_REC601);
|
|
1936
|
-
const set2 = (o, a2) => {
|
|
1937
|
-
!o && (o = []);
|
|
1938
|
-
o[0] = a2[0];
|
|
1939
|
-
o[1] = a2[1];
|
|
1940
|
-
return o;
|
|
1941
|
-
};
|
|
1942
|
-
const set3 = (o, a2) => {
|
|
1943
|
-
!o && (o = []);
|
|
1944
|
-
o[0] = a2[0];
|
|
1945
|
-
o[1] = a2[1];
|
|
1946
|
-
o[2] = a2[2];
|
|
1947
|
-
return o;
|
|
1948
|
-
};
|
|
1949
|
-
const set4 = (o, a2) => {
|
|
1950
|
-
!o && (o = []);
|
|
1951
|
-
o[0] = a2[0];
|
|
1952
|
-
o[1] = a2[1];
|
|
1953
|
-
o[2] = a2[2];
|
|
1954
|
-
o[3] = a2[3];
|
|
1955
|
-
return o;
|
|
1956
|
-
};
|
|
1957
|
-
const set = vop(
|
|
1958
|
-
1,
|
|
1959
|
-
(o, a2) => {
|
|
1960
|
-
!o && (o = []);
|
|
1961
|
-
for (let i = a2.length; i-- > 0; ) o[i] = a2[i];
|
|
1962
|
-
return o;
|
|
1963
|
-
},
|
|
1964
|
-
set2,
|
|
1965
|
-
set3,
|
|
1966
|
-
set4
|
|
1967
|
-
);
|
|
1968
|
-
const implementsFunction = (x, fn) => typeof x?.[fn] === "function";
|
|
1969
|
-
const isArrayLike = (x) => x != null && typeof x !== "function" && x.length !== void 0;
|
|
1970
|
-
const IllegalArgumentError = defError(() => "illegal argument(s)");
|
|
1971
|
-
const illegalArgs = (msg) => {
|
|
1972
|
-
throw new IllegalArgumentError(msg);
|
|
1973
|
-
};
|
|
1974
|
-
const vector = memoizeJ(
|
|
1975
|
-
(size, prec = 3, d2 = ",", pre = "[", post = "]") => {
|
|
1976
|
-
const f = typeof prec === "number" ? float(prec) : prec;
|
|
1977
|
-
switch (size) {
|
|
1978
|
-
case 1:
|
|
1979
|
-
return (v) => `${pre}${f(v[0])}${post}`;
|
|
1980
|
-
case 2:
|
|
1981
|
-
return (v) => `${pre}${f(v[0])}${d2}${f(v[1])}${post}`;
|
|
1982
|
-
case 3:
|
|
1983
|
-
return (v) => `${pre}${f(v[0])}${d2}${f(v[1])}${d2}${f(v[2])}${post}`;
|
|
1984
|
-
case 4:
|
|
1985
|
-
return (v) => `${pre}${f(v[0])}${d2}${f(v[1])}${d2}${f(v[2])}${d2}${f(
|
|
1986
|
-
v[3]
|
|
1987
|
-
)}${post}`;
|
|
1988
|
-
default:
|
|
1989
|
-
return (v) => {
|
|
1990
|
-
const res = [];
|
|
1991
|
-
for (let i = 0; i < v.length; i++) {
|
|
1992
|
-
res.push(f(v[i]));
|
|
1993
|
-
}
|
|
1994
|
-
return `${pre}${res.join(d2)}${post}`;
|
|
1995
|
-
};
|
|
1996
|
-
}
|
|
1997
|
-
}
|
|
1998
|
-
);
|
|
1999
|
-
const mapStridedBuffer = (ctor, buf, num, start, cstride, estride) => {
|
|
2000
|
-
const res = [];
|
|
2001
|
-
while (num-- > 0) {
|
|
2002
|
-
res.push(new ctor(buf, start, cstride));
|
|
2003
|
-
start += estride;
|
|
2004
|
-
}
|
|
2005
|
-
return res;
|
|
2006
|
-
};
|
|
2007
|
-
const defOpVVV = (op, dispatch = 1, outA = true) => {
|
|
2008
|
-
const a2 = outA ? (o, a22, b22, c22) => {
|
|
2009
|
-
!o && (o = a22);
|
|
2010
|
-
for (let i = a22.length; i-- > 0; ) o[i] = op(a22[i], b22[i], c22[i]);
|
|
2011
|
-
return o;
|
|
2012
|
-
} : (o, a22, b22, c22) => {
|
|
2013
|
-
!o && (o = c22);
|
|
2014
|
-
for (let i = a22.length; i-- > 0; ) o[i] = op(a22[i], b22[i], c22[i]);
|
|
2015
|
-
return o;
|
|
2016
|
-
};
|
|
2017
|
-
const b2 = outA ? (o, a22, b22, c22) => {
|
|
2018
|
-
!o && (o = a22);
|
|
2019
|
-
o[0] = op(a22[0], b22[0], c22[0]);
|
|
2020
|
-
o[1] = op(a22[1], b22[1], c22[1]);
|
|
2021
|
-
return o;
|
|
2022
|
-
} : (o, a22, b22, c22) => {
|
|
2023
|
-
!o && (o = c22);
|
|
2024
|
-
o[0] = op(a22[0], b22[0], c22[0]);
|
|
2025
|
-
o[1] = op(a22[1], b22[1], c22[1]);
|
|
2026
|
-
return o;
|
|
2027
|
-
};
|
|
2028
|
-
const c2 = outA ? (o, a22, b22, c22) => {
|
|
2029
|
-
!o && (o = a22);
|
|
2030
|
-
o[0] = op(a22[0], b22[0], c22[0]);
|
|
2031
|
-
o[1] = op(a22[1], b22[1], c22[1]);
|
|
2032
|
-
o[2] = op(a22[2], b22[2], c22[2]);
|
|
2033
|
-
return o;
|
|
2034
|
-
} : (o, a22, b22, c22) => {
|
|
2035
|
-
!o && (o = c22);
|
|
2036
|
-
o[0] = op(a22[0], b22[0], c22[0]);
|
|
2037
|
-
o[1] = op(a22[1], b22[1], c22[1]);
|
|
2038
|
-
o[2] = op(a22[2], b22[2], c22[2]);
|
|
2039
|
-
return o;
|
|
2040
|
-
};
|
|
2041
|
-
const d2 = outA ? (o, a22, b22, c22) => {
|
|
2042
|
-
!o && (o = a22);
|
|
2043
|
-
o[0] = op(a22[0], b22[0], c22[0]);
|
|
2044
|
-
o[1] = op(a22[1], b22[1], c22[1]);
|
|
2045
|
-
o[2] = op(a22[2], b22[2], c22[2]);
|
|
2046
|
-
o[3] = op(a22[3], b22[3], c22[3]);
|
|
2047
|
-
return o;
|
|
2048
|
-
} : (o, a22, b22, c22) => {
|
|
2049
|
-
!o && (o = c22);
|
|
2050
|
-
o[0] = op(a22[0], b22[0], c22[0]);
|
|
2051
|
-
o[1] = op(a22[1], b22[1], c22[1]);
|
|
2052
|
-
o[2] = op(a22[2], b22[2], c22[2]);
|
|
2053
|
-
o[3] = op(a22[3], b22[3], c22[3]);
|
|
2054
|
-
return o;
|
|
2055
|
-
};
|
|
2056
|
-
return [
|
|
2057
|
-
vop(dispatch, a2, b2, c2, d2),
|
|
2058
|
-
b2,
|
|
2059
|
-
c2,
|
|
2060
|
-
d2
|
|
2061
|
-
];
|
|
2062
|
-
};
|
|
2063
|
-
const [a$5, b$2, c$1, d] = defOpVVV(clamp$1);
|
|
2064
|
-
const clamp4 = d;
|
|
2065
|
-
const declareIndex = (proto, id, idx, strided = true, defNumeric = true) => {
|
|
2066
|
-
const get = idx > 0 ? strided ? function() {
|
|
2067
|
-
return this.buf[this.offset + idx * this.stride];
|
|
2068
|
-
} : function() {
|
|
2069
|
-
return this.buf[this.offset + idx];
|
|
2070
|
-
} : function() {
|
|
2071
|
-
return this.buf[this.offset];
|
|
2072
|
-
};
|
|
2073
|
-
const set5 = idx > 0 ? strided ? function(n) {
|
|
2074
|
-
this.buf[this.offset + idx * this.stride] = n;
|
|
2075
|
-
} : function(n) {
|
|
2076
|
-
this.buf[this.offset + idx] = n;
|
|
2077
|
-
} : function(n) {
|
|
2078
|
-
this.buf[this.offset] = n;
|
|
2079
|
-
};
|
|
2080
|
-
defNumeric && Object.defineProperty(proto, idx, {
|
|
2081
|
-
get,
|
|
2082
|
-
set: set5,
|
|
2083
|
-
enumerable: true
|
|
2084
|
-
});
|
|
2085
|
-
Object.defineProperty(proto, id, {
|
|
2086
|
-
get,
|
|
2087
|
-
set: set5,
|
|
2088
|
-
enumerable: true
|
|
2089
|
-
});
|
|
2090
|
-
};
|
|
2091
|
-
const declareIndices = (proto, props, strided, defNumeric) => props.forEach((id, i) => declareIndex(proto, id, i, strided, defNumeric));
|
|
2092
|
-
const abs = Math.abs;
|
|
2093
|
-
const eqDelta = (a2, b2, eps = EPS) => abs(a2 - b2) <= eps;
|
|
2094
|
-
const eqDelta2 = (a2, b2, eps = EPS) => {
|
|
2095
|
-
return a2.length === b2.length && eqDelta(a2[0], b2[0], eps) && eqDelta(a2[1], b2[1], eps);
|
|
2096
|
-
};
|
|
2097
|
-
const eqDelta3 = (a2, b2, eps = EPS) => {
|
|
2098
|
-
return a2.length === b2.length && eqDelta(a2[0], b2[0], eps) && eqDelta(a2[1], b2[1], eps) && eqDelta(a2[2], b2[2], eps);
|
|
2099
|
-
};
|
|
2100
|
-
const eqDelta4 = (a2, b2, eps = EPS) => {
|
|
2101
|
-
return a2.length === b2.length && eqDelta(a2[0], b2[0], eps) && eqDelta(a2[1], b2[1], eps) && eqDelta(a2[2], b2[2], eps) && eqDelta(a2[3], b2[3], eps);
|
|
2102
|
-
};
|
|
2103
|
-
vop(
|
|
2104
|
-
0,
|
|
2105
|
-
(v1, v2, eps = EPS) => {
|
|
2106
|
-
if (implementsFunction(v1, "eqDelta")) {
|
|
2107
|
-
return v1.eqDelta(v2, eps);
|
|
2108
|
-
}
|
|
2109
|
-
if (implementsFunction(v2, "eqDelta")) {
|
|
2110
|
-
return v2.eqDelta(v1, eps);
|
|
2111
|
-
}
|
|
2112
|
-
return eqDeltaS(v1, v2, v1.length, eps);
|
|
2113
|
-
},
|
|
2114
|
-
eqDelta2,
|
|
2115
|
-
eqDelta3,
|
|
2116
|
-
eqDelta4
|
|
2117
|
-
);
|
|
2118
|
-
const eqDeltaS = (a2, b2, n, eps = EPS, ia = 0, ib = 0, sa = 1, sb = 1) => {
|
|
2119
|
-
for (; n > 0; n--, ia += sa, ib += sb) {
|
|
2120
|
-
if (!eqDelta(a2[ia], b2[ib], eps)) {
|
|
2121
|
-
return false;
|
|
2122
|
-
}
|
|
2123
|
-
}
|
|
2124
|
-
return true;
|
|
2125
|
-
};
|
|
2126
|
-
function* stridedValues(buf, num, start, stride) {
|
|
2127
|
-
while (num-- > 0) {
|
|
2128
|
-
yield buf[start];
|
|
2129
|
-
start += stride;
|
|
2130
|
-
}
|
|
2131
|
-
}
|
|
2132
|
-
const INV_MAX = 1 / 2 ** 32;
|
|
2133
|
-
class ARandom {
|
|
2134
|
-
float(norm2 = 1) {
|
|
2135
|
-
return this.int() * INV_MAX * norm2;
|
|
2136
|
-
}
|
|
2137
|
-
probability(p) {
|
|
2138
|
-
return this.float() < p;
|
|
2139
|
-
}
|
|
2140
|
-
norm(norm2 = 1) {
|
|
2141
|
-
return (this.int() * INV_MAX - 0.5) * 2 * norm2;
|
|
2142
|
-
}
|
|
2143
|
-
normMinMax(min2, max2) {
|
|
2144
|
-
const x = this.minmax(min2, max2);
|
|
2145
|
-
return this.float() < 0.5 ? x : -x;
|
|
2146
|
-
}
|
|
2147
|
-
minmax(min2, max2) {
|
|
2148
|
-
return this.float() * (max2 - min2) + min2;
|
|
2149
|
-
}
|
|
2150
|
-
minmaxInt(min2, max2) {
|
|
2151
|
-
min2 |= 0;
|
|
2152
|
-
const range = (max2 | 0) - min2;
|
|
2153
|
-
return range ? min2 + this.int() % range : min2;
|
|
2154
|
-
}
|
|
2155
|
-
minmaxUint(min2, max2) {
|
|
2156
|
-
min2 >>>= 0;
|
|
2157
|
-
const range = (max2 >>> 0) - min2;
|
|
2158
|
-
return range ? min2 + this.int() % range : min2;
|
|
2159
|
-
}
|
|
2160
|
-
}
|
|
2161
|
-
class WrappedRandom extends ARandom {
|
|
2162
|
-
constructor(rnd) {
|
|
2163
|
-
super();
|
|
2164
|
-
this.rnd = rnd;
|
|
2165
|
-
}
|
|
2166
|
-
float(norm2 = 1) {
|
|
2167
|
-
return this.rnd() * norm2;
|
|
2168
|
-
}
|
|
2169
|
-
norm(norm2 = 1) {
|
|
2170
|
-
return (this.rnd() - 0.5) * 2 * norm2;
|
|
2171
|
-
}
|
|
2172
|
-
int() {
|
|
2173
|
-
return this.rnd() * 4294967296 >>> 0;
|
|
2174
|
-
}
|
|
2175
|
-
}
|
|
2176
|
-
const SYSTEM = new WrappedRandom(Math.random);
|
|
2177
|
-
const weightedRandom = (choices, weights, rnd = SYSTEM) => {
|
|
2178
|
-
const n = choices.length;
|
|
2179
|
-
assert(n > 0, "no choices given");
|
|
2180
|
-
const opts = weights ? choices.map((x, i) => [weights[i] || 0, x]).sort((a2, b2) => b2[0] - a2[0]) : choices.map((x) => [1, x]);
|
|
2181
|
-
const total = opts.reduce((acc, o) => acc + o[0], 0);
|
|
2182
|
-
total <= 0 && console.warn("total weights <= 0");
|
|
2183
|
-
return () => {
|
|
2184
|
-
const r = rnd.float(total);
|
|
2185
|
-
let sum5 = total;
|
|
2186
|
-
for (let i = 0; i < n; i++) {
|
|
2187
|
-
sum5 -= opts[i][0];
|
|
2188
|
-
if (sum5 <= r) {
|
|
2189
|
-
return opts[i][1];
|
|
2190
|
-
}
|
|
2191
|
-
}
|
|
2192
|
-
return void 0;
|
|
2193
|
-
};
|
|
2194
|
-
};
|
|
2195
|
-
const randMinMax = vop(
|
|
2196
|
-
1,
|
|
2197
|
-
(o, a2, b2, rnd = SYSTEM) => {
|
|
2198
|
-
!o && (o = a2);
|
|
2199
|
-
for (let i = a2.length; i-- > 0; ) o[i] = rnd.minmax(a2[i], b2[i]);
|
|
2200
|
-
return o;
|
|
2201
|
-
}
|
|
2202
|
-
);
|
|
2203
|
-
const isArray = Array.isArray;
|
|
2204
|
-
const CONVERSIONS = {};
|
|
2205
|
-
const defConversions = (mode, spec) => {
|
|
2206
|
-
for (let id in spec) {
|
|
2207
|
-
const val = spec[id];
|
|
2208
|
-
if (isArray(val)) {
|
|
2209
|
-
const [a2, b2, c2, d2] = val;
|
|
2210
|
-
spec[id] = val.length === 2 ? (out, src) => b2(out, a2(out, src)) : val.length === 3 ? (out, src) => c2(out, b2(out, a2(out, src))) : (out, src) => d2(out, c2(out, b2(out, a2(out, src))));
|
|
2211
|
-
}
|
|
2212
|
-
}
|
|
2213
|
-
CONVERSIONS[mode] = { ...CONVERSIONS[mode], ...spec };
|
|
2214
|
-
};
|
|
2215
|
-
const convert = (res, src, destMode, srcMode) => {
|
|
2216
|
-
const spec = CONVERSIONS[destMode];
|
|
2217
|
-
assert(!!spec, `no conversions available for ${destMode}`);
|
|
2218
|
-
let $convert = spec[srcMode];
|
|
2219
|
-
return $convert ? $convert(res, src) : CONVERSIONS.rgb[srcMode] ? spec.rgb(res, CONVERSIONS.rgb[srcMode]([], src)) : unsupported(`can't convert: ${srcMode} -> ${destMode}`);
|
|
2220
|
-
};
|
|
2221
|
-
const rotateRight = (x, n) => (x >>> n | x << 32 - n) >>> 0;
|
|
2222
|
-
const interleave4_12_24 = (x) => (x & 3840) * 4352 | (x & 240) * 272 | (x & 15) * 17;
|
|
2223
|
-
const interleave4_16_32 = (x) => ((x & 61440) * 69632 | (x & 3840) * 4352 | (x & 240) * 272 | (x & 15) * 17) >>> 0;
|
|
2224
|
-
class ParsedColor {
|
|
2225
|
-
constructor(mode, value) {
|
|
2226
|
-
this.mode = mode;
|
|
2227
|
-
this.value = value;
|
|
2228
|
-
}
|
|
2229
|
-
deref() {
|
|
2230
|
-
return this.value;
|
|
2231
|
-
}
|
|
2232
|
-
}
|
|
2233
|
-
const CSS_NAMES = {
|
|
2234
|
-
aliceblue: "f0f8ff",
|
|
2235
|
-
antiquewhite: "faebd7",
|
|
2236
|
-
aqua: "0ff",
|
|
2237
|
-
aquamarine: "7fffd4",
|
|
2238
|
-
azure: "f0ffff",
|
|
2239
|
-
beige: "f5f5dc",
|
|
2240
|
-
bisque: "ffe4c4",
|
|
2241
|
-
black: "000",
|
|
2242
|
-
blanchedalmond: "ffebcd",
|
|
2243
|
-
blue: "00f",
|
|
2244
|
-
blueviolet: "8a2be2",
|
|
2245
|
-
brown: "a52a2a",
|
|
2246
|
-
burlywood: "deb887",
|
|
2247
|
-
cadetblue: "5f9ea0",
|
|
2248
|
-
chartreuse: "7fff00",
|
|
2249
|
-
chocolate: "d2691e",
|
|
2250
|
-
coral: "ff7f50",
|
|
2251
|
-
cornflowerblue: "6495ed",
|
|
2252
|
-
cornsilk: "fff8dc",
|
|
2253
|
-
crimson: "dc143c",
|
|
2254
|
-
cyan: "0ff",
|
|
2255
|
-
darkblue: "00008b",
|
|
2256
|
-
darkcyan: "008b8b",
|
|
2257
|
-
darkgoldenrod: "b8860b",
|
|
2258
|
-
darkgray: "a9a9a9",
|
|
2259
|
-
darkgreen: "006400",
|
|
2260
|
-
darkgrey: "a9a9a9",
|
|
2261
|
-
darkkhaki: "bdb76b",
|
|
2262
|
-
darkmagenta: "8b008b",
|
|
2263
|
-
darkolivegreen: "556b2f",
|
|
2264
|
-
darkorange: "ff8c00",
|
|
2265
|
-
darkorchid: "9932cc",
|
|
2266
|
-
darkred: "8b0000",
|
|
2267
|
-
darksalmon: "e9967a",
|
|
2268
|
-
darkseagreen: "8fbc8f",
|
|
2269
|
-
darkslateblue: "483d8b",
|
|
2270
|
-
darkslategray: "2f4f4f",
|
|
2271
|
-
darkslategrey: "2f4f4f",
|
|
2272
|
-
darkturquoise: "00ced1",
|
|
2273
|
-
darkviolet: "9400d3",
|
|
2274
|
-
deeppink: "ff1493",
|
|
2275
|
-
deepskyblue: "00bfff",
|
|
2276
|
-
dimgray: "696969",
|
|
2277
|
-
dimgrey: "696969",
|
|
2278
|
-
dodgerblue: "1e90ff",
|
|
2279
|
-
firebrick: "b22222",
|
|
2280
|
-
floralwhite: "fffaf0",
|
|
2281
|
-
forestgreen: "228b22",
|
|
2282
|
-
fuchsia: "f0f",
|
|
2283
|
-
gainsboro: "dcdcdc",
|
|
2284
|
-
ghostwhite: "f8f8ff",
|
|
2285
|
-
gold: "ffd700",
|
|
2286
|
-
goldenrod: "daa520",
|
|
2287
|
-
gray: "808080",
|
|
2288
|
-
grey: "808080",
|
|
2289
|
-
green: "008000",
|
|
2290
|
-
greenyellow: "adff2f",
|
|
2291
|
-
honeydew: "f0fff0",
|
|
2292
|
-
hotpink: "ff69b4",
|
|
2293
|
-
indianred: "cd5c5c",
|
|
2294
|
-
indigo: "4b0082",
|
|
2295
|
-
ivory: "fffff0",
|
|
2296
|
-
khaki: "f0e68c",
|
|
2297
|
-
lavender: "e6e6fa",
|
|
2298
|
-
lavenderblush: "fff0f5",
|
|
2299
|
-
lawngreen: "7cfc00",
|
|
2300
|
-
lemonchiffon: "fffacd",
|
|
2301
|
-
lightblue: "add8e6",
|
|
2302
|
-
lightcoral: "f08080",
|
|
2303
|
-
lightcyan: "e0ffff",
|
|
2304
|
-
lightgoldenrodyellow: "fafad2",
|
|
2305
|
-
lightgray: "d3d3d3",
|
|
2306
|
-
lightgreen: "90ee90",
|
|
2307
|
-
lightgrey: "d3d3d3",
|
|
2308
|
-
lightpink: "ffb6c1",
|
|
2309
|
-
lightsalmon: "ffa07a",
|
|
2310
|
-
lightseagreen: "20b2aa",
|
|
2311
|
-
lightskyblue: "87cefa",
|
|
2312
|
-
lightslategray: "789",
|
|
2313
|
-
lightslategrey: "789",
|
|
2314
|
-
lightsteelblue: "b0c4de",
|
|
2315
|
-
lightyellow: "ffffe0",
|
|
2316
|
-
lime: "0f0",
|
|
2317
|
-
limegreen: "32cd32",
|
|
2318
|
-
linen: "faf0e6",
|
|
2319
|
-
magenta: "f0f",
|
|
2320
|
-
maroon: "800000",
|
|
2321
|
-
mediumaquamarine: "66cdaa",
|
|
2322
|
-
mediumblue: "0000cd",
|
|
2323
|
-
mediumorchid: "ba55d3",
|
|
2324
|
-
mediumpurple: "9370db",
|
|
2325
|
-
mediumseagreen: "3cb371",
|
|
2326
|
-
mediumslateblue: "7b68ee",
|
|
2327
|
-
mediumspringgreen: "00fa9a",
|
|
2328
|
-
mediumturquoise: "48d1cc",
|
|
2329
|
-
mediumvioletred: "c71585",
|
|
2330
|
-
midnightblue: "191970",
|
|
2331
|
-
mintcream: "f5fffa",
|
|
2332
|
-
mistyrose: "ffe4e1",
|
|
2333
|
-
moccasin: "ffe4b5",
|
|
2334
|
-
navajowhite: "ffdead",
|
|
2335
|
-
navy: "000080",
|
|
2336
|
-
oldlace: "fdf5e6",
|
|
2337
|
-
olive: "808000",
|
|
2338
|
-
olivedrab: "6b8e23",
|
|
2339
|
-
orange: "ffa500",
|
|
2340
|
-
orangered: "ff4500",
|
|
2341
|
-
orchid: "da70d6",
|
|
2342
|
-
palegoldenrod: "eee8aa",
|
|
2343
|
-
palegreen: "98fb98",
|
|
2344
|
-
paleturquoise: "afeeee",
|
|
2345
|
-
palevioletred: "db7093",
|
|
2346
|
-
papayawhip: "ffefd5",
|
|
2347
|
-
peachpuff: "ffdab9",
|
|
2348
|
-
peru: "cd853f",
|
|
2349
|
-
pink: "ffc0cb",
|
|
2350
|
-
plum: "dda0dd",
|
|
2351
|
-
powderblue: "b0e0e6",
|
|
2352
|
-
purple: "800080",
|
|
2353
|
-
red: "f00",
|
|
2354
|
-
rosybrown: "bc8f8f",
|
|
2355
|
-
royalblue: "4169e1",
|
|
2356
|
-
saddlebrown: "8b4513",
|
|
2357
|
-
salmon: "fa8072",
|
|
2358
|
-
sandybrown: "f4a460",
|
|
2359
|
-
seagreen: "2e8b57",
|
|
2360
|
-
seashell: "fff5ee",
|
|
2361
|
-
sienna: "a0522d",
|
|
2362
|
-
silver: "c0c0c0",
|
|
2363
|
-
skyblue: "87ceeb",
|
|
2364
|
-
slateblue: "6a5acd",
|
|
2365
|
-
slategray: "708090",
|
|
2366
|
-
slategrey: "708090",
|
|
2367
|
-
snow: "fffafa",
|
|
2368
|
-
springgreen: "00ff7f",
|
|
2369
|
-
steelblue: "4682b4",
|
|
2370
|
-
tan: "d2b48c",
|
|
2371
|
-
teal: "008080",
|
|
2372
|
-
thistle: "d8bfd8",
|
|
2373
|
-
tomato: "ff6347",
|
|
2374
|
-
turquoise: "40e0d0",
|
|
2375
|
-
violet: "ee82ee",
|
|
2376
|
-
wheat: "f5deb3",
|
|
2377
|
-
white: "fff",
|
|
2378
|
-
whitesmoke: "f5f5f5",
|
|
2379
|
-
yellow: "ff0",
|
|
2380
|
-
yellowgreen: "9acd32",
|
|
2381
|
-
// additions
|
|
2382
|
-
transparent: "0000",
|
|
2383
|
-
rebeccapurple: "639"
|
|
2384
|
-
};
|
|
2385
|
-
let CSS_SYSTEM_COLORS = {
|
|
2386
|
-
canvas: "fff",
|
|
2387
|
-
canvastext: "000",
|
|
2388
|
-
linktext: "001ee4",
|
|
2389
|
-
visitedtext: "4e2386",
|
|
2390
|
-
activetext: "eb3323",
|
|
2391
|
-
buttonface: "ddd",
|
|
2392
|
-
buttontext: "000",
|
|
2393
|
-
buttonborder: "000",
|
|
2394
|
-
field: "fff",
|
|
2395
|
-
fieldtext: "000",
|
|
2396
|
-
highlight: "bbd5fb",
|
|
2397
|
-
highlighttext: "000",
|
|
2398
|
-
mark: "000",
|
|
2399
|
-
marktext: "fff",
|
|
2400
|
-
graytext: "808080"
|
|
2401
|
-
};
|
|
2402
|
-
const setC3 = (out, x, y, z) => {
|
|
2403
|
-
!out && (out = []);
|
|
2404
|
-
out[0] = x;
|
|
2405
|
-
out[1] = y;
|
|
2406
|
-
out[2] = z;
|
|
2407
|
-
return out;
|
|
2408
|
-
};
|
|
2409
|
-
const setC4 = (out, x, y, z, w) => {
|
|
2410
|
-
!out && (out = []);
|
|
2411
|
-
out[0] = x;
|
|
2412
|
-
out[1] = y;
|
|
2413
|
-
out[2] = z;
|
|
2414
|
-
out[3] = w;
|
|
2415
|
-
return out;
|
|
2416
|
-
};
|
|
2417
|
-
const intArgb32Srgb = (out, src) => setC4(
|
|
2418
|
-
out || [],
|
|
2419
|
-
(src >>> 16 & 255) * INV8BIT,
|
|
2420
|
-
(src >>> 8 & 255) * INV8BIT,
|
|
2421
|
-
(src & 255) * INV8BIT,
|
|
2422
|
-
(src >>> 24) * INV8BIT
|
|
2423
|
-
);
|
|
2424
|
-
const intAbgr32Srgb = (out, src) => setC4(
|
|
2425
|
-
out || [],
|
|
2426
|
-
(src & 255) * INV8BIT,
|
|
2427
|
-
(src >>> 8 & 255) * INV8BIT,
|
|
2428
|
-
(src >>> 16 & 255) * INV8BIT,
|
|
2429
|
-
(src >>> 24) * INV8BIT
|
|
2430
|
-
);
|
|
2431
|
-
const parseCss = (src) => {
|
|
2432
|
-
src = (isString(src) ? src : src.deref()).toLowerCase();
|
|
2433
|
-
const named = CSS_NAMES[src] || CSS_SYSTEM_COLORS[src];
|
|
2434
|
-
if (named || src[0] === "#")
|
|
2435
|
-
return new ParsedColor(
|
|
2436
|
-
"srgb",
|
|
2437
|
-
intArgb32Srgb([], parseHex(named || src))
|
|
2438
|
-
);
|
|
2439
|
-
const parts = src.split(/[(),/ ]+/);
|
|
2440
|
-
const [mode, a2, b2, c2, d2] = parts;
|
|
2441
|
-
assert(parts.length === 5 || parts.length === 6, `invalid color: ${src}`);
|
|
2442
|
-
switch (mode) {
|
|
2443
|
-
case "rgb":
|
|
2444
|
-
case "rgba":
|
|
2445
|
-
return new ParsedColor("srgb", [
|
|
2446
|
-
__numOrPercent(a2, 1, INV8BIT, true),
|
|
2447
|
-
__numOrPercent(b2, 1, INV8BIT, true),
|
|
2448
|
-
__numOrPercent(c2, 1, INV8BIT, true),
|
|
2449
|
-
__alpha(d2)
|
|
2450
|
-
]);
|
|
2451
|
-
case "hsl":
|
|
2452
|
-
case "hsla":
|
|
2453
|
-
return new ParsedColor("hsl", [
|
|
2454
|
-
__hue(a2),
|
|
2455
|
-
__percent(b2),
|
|
2456
|
-
__percent(c2),
|
|
2457
|
-
__alpha(d2)
|
|
2458
|
-
]);
|
|
2459
|
-
case "lab":
|
|
2460
|
-
return new ParsedColor("lab50", [
|
|
2461
|
-
__numOrPercent(a2),
|
|
2462
|
-
__numOrPercent(b2, 1.25),
|
|
2463
|
-
__numOrPercent(c2, 1.25),
|
|
2464
|
-
__alpha(d2)
|
|
2465
|
-
]);
|
|
2466
|
-
case "lch":
|
|
2467
|
-
return new ParsedColor(mode, [
|
|
2468
|
-
__numOrPercent(a2),
|
|
2469
|
-
__numOrPercent(b2, 1.5),
|
|
2470
|
-
__hue(c2),
|
|
2471
|
-
__alpha(d2)
|
|
2472
|
-
]);
|
|
2473
|
-
case "oklab":
|
|
2474
|
-
return new ParsedColor(mode, [
|
|
2475
|
-
__numOrPercent(a2, 1, 1),
|
|
2476
|
-
__numOrPercent(b2, 0.4, 1),
|
|
2477
|
-
__numOrPercent(c2, 0.4, 1),
|
|
2478
|
-
__alpha(d2)
|
|
2479
|
-
]);
|
|
2480
|
-
case "oklch":
|
|
2481
|
-
return new ParsedColor(mode, [
|
|
2482
|
-
__numOrPercent(a2, 1, 1),
|
|
2483
|
-
__numOrPercent(b2, 0.4, 1),
|
|
2484
|
-
__hue(c2),
|
|
2485
|
-
__alpha(d2)
|
|
2486
|
-
]);
|
|
2487
|
-
default:
|
|
2488
|
-
unsupported(`color mode: ${mode}`);
|
|
2489
|
-
}
|
|
2490
|
-
};
|
|
2491
|
-
const HUE_NORMS = {
|
|
2492
|
-
rad: TAU,
|
|
2493
|
-
grad: 400,
|
|
2494
|
-
turn: 1,
|
|
2495
|
-
deg: 360
|
|
2496
|
-
};
|
|
2497
|
-
const __hue = (x) => {
|
|
2498
|
-
const match = /^(-?[0-9.]+)(deg|rad|grad|turn)?$/.exec(x);
|
|
2499
|
-
assert(!!match, `expected hue, got: ${x}`);
|
|
2500
|
-
return fract(parseFloat(match[1]) / (HUE_NORMS[match[2]] || 360));
|
|
2501
|
-
};
|
|
2502
|
-
const __alpha = (x) => x ? __numOrPercent(x, 1, 1, true) : 1;
|
|
2503
|
-
const __percent = (x, clamp2 = true) => {
|
|
2504
|
-
assert(/^([0-9.]+)%$/.test(x), `expected percentage, got: ${x}`);
|
|
2505
|
-
const res = parseFloat(x) / 100;
|
|
2506
|
-
return clamp2 ? clamp01(res) : res;
|
|
2507
|
-
};
|
|
2508
|
-
const __numOrPercent = (x, scalePerc = 1, scale = 0.01, clamp2 = false) => {
|
|
2509
|
-
assert(/^-?[0-9.]+%?$/.test(x), `expected number or percentage, got: ${x}`);
|
|
2510
|
-
const res = parseFloat(x) * (x.endsWith("%") ? 0.01 * scalePerc : scale);
|
|
2511
|
-
return clamp2 ? clamp01(res) : res;
|
|
2512
|
-
};
|
|
2513
|
-
const parseHex = (src) => {
|
|
2514
|
-
const match = /^#?([0-9a-f]{3,8})$/i.exec(src);
|
|
2515
|
-
if (match) {
|
|
2516
|
-
const hex = match[1];
|
|
2517
|
-
const val = parseInt(hex, 16);
|
|
2518
|
-
switch (hex.length) {
|
|
2519
|
-
case 3:
|
|
2520
|
-
return (interleave4_12_24(val) | 4278190080) >>> 0;
|
|
2521
|
-
case 4:
|
|
2522
|
-
return rotateRight(interleave4_16_32(val), 8);
|
|
2523
|
-
case 6:
|
|
2524
|
-
return (val | 4278190080) >>> 0;
|
|
2525
|
-
case 8:
|
|
2526
|
-
return rotateRight(val, 8);
|
|
2527
|
-
}
|
|
2528
|
-
}
|
|
2529
|
-
return illegalArgs(`invalid hex color: "${src}"`);
|
|
2530
|
-
};
|
|
2531
|
-
const __ensureAlpha = (x, def = 1) => x != void 0 ? clamp01(x) : def;
|
|
2532
|
-
const __ensureArgs = (args) => {
|
|
2533
|
-
if (typeof args[0] === "number") {
|
|
2534
|
-
switch (args.length) {
|
|
2535
|
-
case 1:
|
|
2536
|
-
return args.push(0, 0, 1), [args];
|
|
2537
|
-
case 2:
|
|
2538
|
-
return args.push(0, 1), [args];
|
|
2539
|
-
case 3:
|
|
2540
|
-
return args.push(1), [args];
|
|
2541
|
-
default:
|
|
2542
|
-
return [args];
|
|
2543
|
-
}
|
|
2544
|
-
}
|
|
2545
|
-
return args;
|
|
2546
|
-
};
|
|
2547
|
-
const defColor = (spec) => {
|
|
2548
|
-
const channels = spec.channels || {};
|
|
2549
|
-
const order = spec.order;
|
|
2550
|
-
const numChannels = order.length;
|
|
2551
|
-
order.reduce((acc, id) => {
|
|
2552
|
-
acc[id] = {
|
|
2553
|
-
range: [0, 1],
|
|
2554
|
-
...channels[id]
|
|
2555
|
-
};
|
|
2556
|
-
return acc;
|
|
2557
|
-
}, channels);
|
|
2558
|
-
const min2 = Object.freeze(order.map((id) => channels[id].range[0]));
|
|
2559
|
-
const max2 = Object.freeze(order.map((id) => channels[id].range[1]));
|
|
2560
|
-
const minR = set4([], min2);
|
|
2561
|
-
const maxR = set4([], max2);
|
|
2562
|
-
minR[numChannels - 1] = 1;
|
|
2563
|
-
const hueChanID = order.findIndex((id) => !!channels[id].hue);
|
|
2564
|
-
const $Color = class {
|
|
2565
|
-
constructor(buf, offset = 0, stride = 1) {
|
|
2566
|
-
this.offset = offset;
|
|
2567
|
-
this.stride = stride;
|
|
2568
|
-
this.buf = buf || [0, 0, 0, 0];
|
|
2569
|
-
this.offset = offset;
|
|
2570
|
-
this.stride = stride;
|
|
2571
|
-
}
|
|
2572
|
-
buf;
|
|
2573
|
-
get mode() {
|
|
2574
|
-
return spec.mode;
|
|
2575
|
-
}
|
|
2576
|
-
get length() {
|
|
2577
|
-
return numChannels;
|
|
2578
|
-
}
|
|
2579
|
-
get range() {
|
|
2580
|
-
return [min2, max2];
|
|
2581
|
-
}
|
|
2582
|
-
get [Symbol.toStringTag]() {
|
|
2583
|
-
return spec.mode;
|
|
2584
|
-
}
|
|
2585
|
-
get xyz() {
|
|
2586
|
-
return [this[0], this[1], this[2]];
|
|
2587
|
-
}
|
|
2588
|
-
[Symbol.iterator]() {
|
|
2589
|
-
return stridedValues(
|
|
2590
|
-
this.buf,
|
|
2591
|
-
this.length,
|
|
2592
|
-
this.offset,
|
|
2593
|
-
this.stride
|
|
2594
|
-
);
|
|
2595
|
-
}
|
|
2596
|
-
copy() {
|
|
2597
|
-
return new $Color(this.deref());
|
|
2598
|
-
}
|
|
2599
|
-
copyView() {
|
|
2600
|
-
return new $Color(this.buf, this.offset, this.stride);
|
|
2601
|
-
}
|
|
2602
|
-
empty() {
|
|
2603
|
-
return new $Color();
|
|
2604
|
-
}
|
|
2605
|
-
deref() {
|
|
2606
|
-
return [this[0], this[1], this[2], this[3]];
|
|
2607
|
-
}
|
|
2608
|
-
set(src) {
|
|
2609
|
-
return set4(this, src);
|
|
2610
|
-
}
|
|
2611
|
-
clamp() {
|
|
2612
|
-
hueChanID >= 0 && (this[hueChanID] = fract(this[hueChanID]));
|
|
2613
|
-
clamp4(null, this, min2, max2);
|
|
2614
|
-
return this;
|
|
2615
|
-
}
|
|
2616
|
-
eqDelta(o, eps = EPS) {
|
|
2617
|
-
return eqDelta4(this, o, eps);
|
|
2618
|
-
}
|
|
2619
|
-
randomize(rnd) {
|
|
2620
|
-
return randMinMax(this, minR, maxR, rnd);
|
|
2621
|
-
}
|
|
2622
|
-
toJSON() {
|
|
2623
|
-
return this.deref();
|
|
2624
|
-
}
|
|
2625
|
-
toString() {
|
|
2626
|
-
return vector(4, 4)(this);
|
|
2627
|
-
}
|
|
2628
|
-
};
|
|
2629
|
-
declareIndices($Color.prototype, order);
|
|
2630
|
-
defConversions(spec.mode, spec.from);
|
|
2631
|
-
defConversions("rgb", { [spec.mode]: spec.toRgb });
|
|
2632
|
-
const fromColor = (src, mode, args) => {
|
|
2633
|
-
const res = new $Color(...args);
|
|
2634
|
-
return mode !== spec.mode ? convert(res, src, spec.mode, mode) : res.set(src);
|
|
2635
|
-
};
|
|
2636
|
-
const factory = (src, ...args) => src == null ? new $Color() : isString(src) ? factory(parseCss(src), ...args) : isArrayLike(src) ? isString(src.mode) ? fromColor(src, src.mode, args) : new $Color(src, ...args) : implementsFunction(src, "deref") ? fromColor(src.deref(), src.mode, args) : isNumber(src) ? args.length && args.every(isNumber) ? new $Color(...__ensureArgs([src, ...args])) : fromColor(intArgb32Srgb([], src), "srgb", args) : illegalArgs(`can't create a ${spec.mode} color from: ${src}`);
|
|
2637
|
-
factory.class = $Color;
|
|
2638
|
-
factory.range = [min2, max2];
|
|
2639
|
-
factory.random = (rnd, buf, idx, stride) => new $Color(buf, idx, stride).randomize(rnd);
|
|
2640
|
-
factory.mapBuffer = (buf, num = buf.length / numChannels | 0, start = 0, cstride = 1, estride = numChannels) => mapStridedBuffer($Color, buf, num, start, cstride, estride);
|
|
2641
|
-
return factory;
|
|
2642
|
-
};
|
|
2643
|
-
const hueRgb = (out, hue, alpha = 1) => {
|
|
2644
|
-
hue = fract(hue) * 6;
|
|
2645
|
-
return setC4(
|
|
2646
|
-
out || [],
|
|
2647
|
-
clamp01(Math.abs(hue - 3) - 1),
|
|
2648
|
-
clamp01(2 - Math.abs(hue - 2)),
|
|
2649
|
-
clamp01(2 - Math.abs(hue - 4)),
|
|
2650
|
-
alpha
|
|
2651
|
-
);
|
|
2652
|
-
};
|
|
2653
|
-
const hcyRgb = (out, src) => {
|
|
2654
|
-
const h = src[0];
|
|
2655
|
-
let c2 = src[1];
|
|
2656
|
-
const y = src[2];
|
|
2657
|
-
const rgb2 = hueRgb(out || src, h, __ensureAlpha(src[3]));
|
|
2658
|
-
const lum = luminanceRgb(rgb2);
|
|
2659
|
-
if (y < lum) {
|
|
2660
|
-
c2 *= y / lum;
|
|
2661
|
-
} else if (lum < 1) {
|
|
2662
|
-
c2 *= (1 - y) / (1 - lum);
|
|
2663
|
-
}
|
|
2664
|
-
return setC3(
|
|
2665
|
-
rgb2,
|
|
2666
|
-
clamp01((rgb2[0] - lum) * c2 + y),
|
|
2667
|
-
clamp01((rgb2[1] - lum) * c2 + y),
|
|
2668
|
-
clamp01((rgb2[2] - lum) * c2 + y)
|
|
2669
|
-
);
|
|
2670
|
-
};
|
|
2671
|
-
const clamp = (out, src, alpha = 1) => setC4(
|
|
2672
|
-
out || src,
|
|
2673
|
-
clamp01(src[0]),
|
|
2674
|
-
clamp01(src[1]),
|
|
2675
|
-
clamp01(src[2]),
|
|
2676
|
-
__ensureAlpha(src[3], alpha)
|
|
2677
|
-
);
|
|
2678
|
-
const clampH = (out, src, alpha = 1) => setC4(
|
|
2679
|
-
out || src,
|
|
2680
|
-
fract(src[0]),
|
|
2681
|
-
clamp01(src[1]),
|
|
2682
|
-
clamp01(src[2]),
|
|
2683
|
-
__ensureAlpha(src[3], alpha)
|
|
2684
|
-
);
|
|
2685
|
-
const hsiRgb = (out, src) => {
|
|
2686
|
-
out = clampH(out || src, src);
|
|
2687
|
-
const s = out[1];
|
|
2688
|
-
const i = out[2];
|
|
2689
|
-
if (s < 1e-6) {
|
|
2690
|
-
return setC3(out, i, i, i);
|
|
2691
|
-
}
|
|
2692
|
-
const h = out[0] * 6 % 6;
|
|
2693
|
-
const m = i * (1 - s);
|
|
2694
|
-
const z = 1 - Math.abs(h % 2 - 1);
|
|
2695
|
-
let c2 = 3 * i * s / (1 + z);
|
|
2696
|
-
const x = c2 * z + m;
|
|
2697
|
-
c2 += m;
|
|
2698
|
-
switch (h | 0) {
|
|
2699
|
-
case 0:
|
|
2700
|
-
return setC3(out, c2, x, m);
|
|
2701
|
-
case 1:
|
|
2702
|
-
return setC3(out, x, c2, m);
|
|
2703
|
-
case 2:
|
|
2704
|
-
return setC3(out, m, c2, x);
|
|
2705
|
-
case 3:
|
|
2706
|
-
return setC3(out, m, x, c2);
|
|
2707
|
-
case 4:
|
|
2708
|
-
return setC3(out, x, m, c2);
|
|
2709
|
-
case 5:
|
|
2710
|
-
return setC3(out, c2, m, x);
|
|
2711
|
-
default:
|
|
2712
|
-
return setC3(out, m, m, m);
|
|
2713
|
-
}
|
|
2714
|
-
};
|
|
2715
|
-
const hslRgb = (out, src) => {
|
|
2716
|
-
const s = clamp01(src[1]);
|
|
2717
|
-
const l = clamp01(src[2]);
|
|
2718
|
-
out = hueRgb(out || src, src[0], __ensureAlpha(src[3]));
|
|
2719
|
-
const c2 = (1 - Math.abs(2 * l - 1)) * s;
|
|
2720
|
-
return setC3(
|
|
2721
|
-
out,
|
|
2722
|
-
(out[0] - 0.5) * c2 + l,
|
|
2723
|
-
(out[1] - 0.5) * c2 + l,
|
|
2724
|
-
(out[2] - 0.5) * c2 + l
|
|
2725
|
-
);
|
|
2726
|
-
};
|
|
2727
|
-
const hsvRgb = (out, src) => {
|
|
2728
|
-
out = clampH(out || src, src);
|
|
2729
|
-
const s = out[1];
|
|
2730
|
-
const v = out[2];
|
|
2731
|
-
hueRgb(out, src[0], out[3]);
|
|
2732
|
-
return setC3(
|
|
2733
|
-
out,
|
|
2734
|
-
((out[0] - 1) * s + 1) * v,
|
|
2735
|
-
((out[1] - 1) * s + 1) * v,
|
|
2736
|
-
((out[2] - 1) * s + 1) * v
|
|
2737
|
-
);
|
|
2738
|
-
};
|
|
2739
|
-
const linearSrgb = (x) => x <= 31308e-7 ? 12.92 * x : 1.055 * Math.pow(x, 1 / 2.4) - 0.055;
|
|
2740
|
-
const srgbLinear = (x) => x <= 0.04045 ? x / 12.92 : Math.pow((x + 0.055) / 1.055, 2.4);
|
|
2741
|
-
const srgbRgb = (out, src) => setC4(
|
|
2742
|
-
out || src,
|
|
2743
|
-
srgbLinear(src[0]),
|
|
2744
|
-
srgbLinear(src[1]),
|
|
2745
|
-
srgbLinear(src[2]),
|
|
2746
|
-
__ensureAlpha(src[3])
|
|
2747
|
-
);
|
|
2748
|
-
const intArgb32Rgb = (out, src) => srgbRgb(null, intArgb32Srgb(out, src));
|
|
2749
|
-
const intAbgr32Rgb = (out, src) => srgbRgb(null, intAbgr32Srgb(out, src));
|
|
2750
|
-
const cossin = (theta, n = 1) => [
|
|
2751
|
-
Math.cos(theta) * n,
|
|
2752
|
-
Math.sin(theta) * n
|
|
2753
|
-
];
|
|
2754
|
-
const absTheta = (theta) => (theta %= TAU, theta < 0 ? TAU + theta : theta);
|
|
2755
|
-
const atan2Abs = (y, x) => absTheta(Math.atan2(y, x));
|
|
2756
|
-
const lchLab = (out, src) => {
|
|
2757
|
-
let { 1: c2, 2: h } = src;
|
|
2758
|
-
h *= TAU;
|
|
2759
|
-
const a2 = __ensureAlpha(src[3]);
|
|
2760
|
-
return c2 > 0 ? setC4(out || src, src[0], Math.cos(h) * c2, Math.sin(h) * c2, a2) : setC4(out || src, src[0], 0, 0, a2);
|
|
2761
|
-
};
|
|
2762
|
-
const __transform = (x) => {
|
|
2763
|
-
const y = x ** 3;
|
|
2764
|
-
return y > 8856e-6 ? y : (x - 16 / 116) / 7.787;
|
|
2765
|
-
};
|
|
2766
|
-
const labXyz = (out, src, white = D50) => {
|
|
2767
|
-
const y = (src[0] + 0.16) / 1.16;
|
|
2768
|
-
return setC4(
|
|
2769
|
-
out || src,
|
|
2770
|
-
__transform(src[1] / 5 + y) * white[0],
|
|
2771
|
-
__transform(y) * white[1],
|
|
2772
|
-
__transform(y - src[2] / 2) * white[2],
|
|
2773
|
-
__ensureAlpha(src[3])
|
|
2774
|
-
);
|
|
2775
|
-
};
|
|
2776
|
-
const labXyzD65 = (out, src) => labXyz(out, src, D65);
|
|
2777
|
-
const dotS3 = (a2, b2, ia = 0, ib = 0, sa = 1, sb = 1) => a2[ia] * b2[ib] + a2[ia + sa] * b2[ib + sb] + a2[ia + 2 * sa] * b2[ib + 2 * sb];
|
|
2778
|
-
const __mulV33 = (out, mat, src, clampOut = false) => {
|
|
2779
|
-
const x = dotS3(mat, src, 0, 0, 3);
|
|
2780
|
-
const y = dotS3(mat, src, 1, 0, 3);
|
|
2781
|
-
const z = dotS3(mat, src, 2, 0, 3);
|
|
2782
|
-
const a2 = __ensureAlpha(src[3]);
|
|
2783
|
-
return clampOut ? setC4(out || src, clamp01(x), clamp01(y), clamp01(z), a2) : setC4(out || src, x, y, z, a2);
|
|
2784
|
-
};
|
|
2785
|
-
const xyzRgb = (out, src, mat = XYZ_RGB_D50) => __mulV33(out, mat, src);
|
|
2786
|
-
const xyzRgbD65 = (out, src) => xyzRgb(out, src, XYZ_RGB_D65);
|
|
2787
|
-
const labRgb = (out, src) => xyzRgb(null, labXyz(out, src));
|
|
2788
|
-
const labRgbD65 = (out, src) => xyzRgbD65(null, labXyzD65(out, src));
|
|
2789
|
-
const LMS_CONE = [
|
|
2790
|
-
4.0767416621,
|
|
2791
|
-
-1.2684380046,
|
|
2792
|
-
-0.0041960863,
|
|
2793
|
-
-3.307711591,
|
|
2794
|
-
2.6097574011,
|
|
2795
|
-
-0.7034186147,
|
|
2796
|
-
0.2309699292,
|
|
2797
|
-
-0.3413193965,
|
|
2798
|
-
1.707614701
|
|
2799
|
-
];
|
|
2800
|
-
const oklabRgb = (out, { 0: l, 1: a2, 2: b2, 3: alpha }) => __mulV33(out, LMS_CONE, [
|
|
2801
|
-
(l + 0.3963377774 * a2 + 0.2158037573 * b2) ** 3,
|
|
2802
|
-
(l - 0.1055613458 * a2 - 0.0638541728 * b2) ** 3,
|
|
2803
|
-
(l - 0.0894841775 * a2 - 1.291485548 * b2) ** 3,
|
|
2804
|
-
alpha
|
|
2805
|
-
]);
|
|
2806
|
-
const safeDiv = (a2, b2) => b2 !== 0 ? a2 / b2 : 0;
|
|
2807
|
-
const xyyXyz = (out, src) => {
|
|
2808
|
-
const { 0: x, 1: y, 2: Y } = src;
|
|
2809
|
-
return setC4(
|
|
2810
|
-
out || src,
|
|
2811
|
-
safeDiv(Y * x, y),
|
|
2812
|
-
Y,
|
|
2813
|
-
safeDiv(Y * (1 - x - y), y),
|
|
2814
|
-
__ensureAlpha(src[3])
|
|
2815
|
-
);
|
|
2816
|
-
};
|
|
2817
|
-
const yccRgb = (out, src, luma = RGB_LUMINANCE_REC709) => {
|
|
2818
|
-
const y = src[0];
|
|
2819
|
-
const bb = (2 - 2 * luma[2]) * src[1];
|
|
2820
|
-
const rr = (2 - 2 * luma[0]) * src[2];
|
|
2821
|
-
return setC4(
|
|
2822
|
-
out || src,
|
|
2823
|
-
y + rr,
|
|
2824
|
-
y - luma[2] / luma[1] * bb - luma[0] / luma[1] * rr,
|
|
2825
|
-
y + bb,
|
|
2826
|
-
__ensureAlpha(src[3])
|
|
2827
|
-
);
|
|
2828
|
-
};
|
|
2829
|
-
const rgb = defColor({
|
|
2830
|
-
mode: "rgb",
|
|
2831
|
-
order: ["r", "g", "b", "alpha"],
|
|
2832
|
-
from: {
|
|
2833
|
-
abgr32: (out, src) => intAbgr32Rgb(out, src[0]),
|
|
2834
|
-
argb32: (out, src) => intArgb32Rgb(out, src[0]),
|
|
2835
|
-
hcy: hcyRgb,
|
|
2836
|
-
hsi: hsiRgb,
|
|
2837
|
-
hsl: hslRgb,
|
|
2838
|
-
hsv: hsvRgb,
|
|
2839
|
-
lab50: labRgb,
|
|
2840
|
-
lab65: labRgbD65,
|
|
2841
|
-
lch: [lchLab, labRgb],
|
|
2842
|
-
oklab: oklabRgb,
|
|
2843
|
-
rgb: set4,
|
|
2844
|
-
srgb: srgbRgb,
|
|
2845
|
-
xyy: [xyyXyz, xyzRgbD65],
|
|
2846
|
-
xyz50: xyzRgb,
|
|
2847
|
-
xyz65: xyzRgbD65,
|
|
2848
|
-
ycc: yccRgb
|
|
2849
|
-
},
|
|
2850
|
-
toRgb: set4
|
|
2851
|
-
});
|
|
2852
|
-
const contrast = (a2, b2) => {
|
|
2853
|
-
const lumA = luminanceRgb(rgb(a2)) + 0.05;
|
|
2854
|
-
const lumB = luminanceRgb(rgb(b2)) + 0.05;
|
|
2855
|
-
return lumA > lumB ? lumA / lumB : lumB / lumA;
|
|
2856
|
-
};
|
|
2857
|
-
const hslCss = (src) => {
|
|
2858
|
-
const h = FF(fract(src[0]) * 360);
|
|
2859
|
-
const s = PC(clamp01(src[1]));
|
|
2860
|
-
const l = PC(clamp01(src[2]));
|
|
2861
|
-
const a2 = __ensureAlpha(src[3]);
|
|
2862
|
-
return a2 < 1 ? `hsla(${h},${s},${l},${FF(a2)})` : `hsl(${h},${s},${l})`;
|
|
2863
|
-
};
|
|
2864
|
-
const hsvHsl = (out, src) => {
|
|
2865
|
-
out = clampH(out || src, src);
|
|
2866
|
-
const s = out[1];
|
|
2867
|
-
const v = out[2];
|
|
2868
|
-
const l = (2 - s) * v / 2;
|
|
2869
|
-
out[2] = l;
|
|
2870
|
-
out[1] = l && l < 1 ? s * v / (l < 0.5 ? l * 2 : 2 - l * 2) : s;
|
|
2871
|
-
return out;
|
|
2872
|
-
};
|
|
2873
|
-
const hsvCss = (src) => hslCss(hsvHsl([], src));
|
|
2874
|
-
const HEX = "0123456789abcdef";
|
|
2875
|
-
const U8 = (x) => HEX[x >>> 4 & 15] + HEX[x & 15];
|
|
2876
|
-
const U16 = (x) => U8(x >>> 8) + U8(x & 255);
|
|
2877
|
-
const U24$1 = (x) => U8(x >>> 16) + U16(x);
|
|
2878
|
-
const radix = memoizeO(
|
|
2879
|
-
(radix2, n, prefix = "") => {
|
|
2880
|
-
const buf = repeat$1("0", n);
|
|
2881
|
-
return (x) => {
|
|
2882
|
-
x = (x >>> 0).toString(radix2);
|
|
2883
|
-
return prefix + (x.length < n ? buf.substring(x.length) + x : x);
|
|
2884
|
-
};
|
|
2885
|
-
}
|
|
2886
|
-
);
|
|
2887
|
-
radix(2, 8);
|
|
2888
|
-
radix(2, 16);
|
|
2889
|
-
radix(2, 32);
|
|
2890
|
-
const U24 = U24$1;
|
|
2891
|
-
const intArgb32Css = (src) => {
|
|
2892
|
-
const a2 = src >>> 24;
|
|
2893
|
-
return a2 < 255 ? `rgba(${src >> 16 & 255},${src >> 8 & 255},${src & 255},${FF(
|
|
2894
|
-
a2 * INV8BIT
|
|
2895
|
-
)})` : `#${U24(src & 16777215)}`;
|
|
2896
|
-
};
|
|
2897
|
-
const swapLane13 = (x) => (x & 255) << 16 | x >> 16 & 255 | x & 4278255360;
|
|
2898
|
-
const intAbgr32Argb32 = swapLane13;
|
|
2899
|
-
const rgbSrgb = (out, src) => setC4(
|
|
2900
|
-
out || src,
|
|
2901
|
-
linearSrgb(src[0]),
|
|
2902
|
-
linearSrgb(src[1]),
|
|
2903
|
-
linearSrgb(src[2]),
|
|
2904
|
-
__ensureAlpha(src[3])
|
|
2905
|
-
);
|
|
2906
|
-
const __scale8bit = (x, shift = 0) => (x < 0 ? 0 : x > 1 ? 1 : x) * 255 + 0.5 << shift;
|
|
2907
|
-
const srgbCss = (src) => {
|
|
2908
|
-
const r = __scale8bit(src[0]);
|
|
2909
|
-
const g = __scale8bit(src[1]);
|
|
2910
|
-
const b2 = __scale8bit(src[2]);
|
|
2911
|
-
const a2 = __ensureAlpha(src[3]);
|
|
2912
|
-
return a2 < 1 ? `rgba(${r},${g},${b2},${FF(a2)})` : `#${U24(r << 16 | g << 8 | b2)}`;
|
|
2913
|
-
};
|
|
2914
|
-
const rgbCss = (src) => srgbCss(rgbSrgb([], src));
|
|
2915
|
-
const CSS_LEVEL3 = {
|
|
2916
|
-
abgr32: (x) => intArgb32Css(intAbgr32Argb32(x[0])),
|
|
2917
|
-
argb32: (x) => intArgb32Css(x[0]),
|
|
2918
|
-
hsl: hslCss,
|
|
2919
|
-
hsv: hsvCss,
|
|
2920
|
-
lab50: (src) => srgbCss(rgbSrgb(null, labRgb([], src))),
|
|
2921
|
-
lab65: (src) => srgbCss(rgbSrgb(null, labRgbD65([], src))),
|
|
2922
|
-
lch: (src) => srgbCss(rgbSrgb(null, labRgb(null, lchLab([], src)))),
|
|
2923
|
-
rgb: rgbCss,
|
|
2924
|
-
srgb: srgbCss
|
|
2925
|
-
};
|
|
2926
|
-
({
|
|
2927
|
-
...CSS_LEVEL3
|
|
2928
|
-
});
|
|
2929
|
-
let CSS_DEFAULT = CSS_LEVEL3;
|
|
2930
|
-
const css = (src, cssTarget = CSS_DEFAULT) => {
|
|
2931
|
-
let asCss;
|
|
2932
|
-
return isString(src) ? src : isNumber(src) ? intArgb32Css(src) : src.mode ? (asCss = cssTarget[src.mode]) ? asCss(src) : cssTarget.rgb(
|
|
2933
|
-
convert([], src, "rgb", src.mode)
|
|
2934
|
-
) : srgbCss(src);
|
|
2935
|
-
};
|
|
2936
|
-
const hslHsv = (out, src) => {
|
|
2937
|
-
out = clampH(out || src, src);
|
|
2938
|
-
const s = out[1];
|
|
2939
|
-
const l = out[2];
|
|
2940
|
-
const l2 = 2 * l;
|
|
2941
|
-
const v = (l2 + s * (1 - Math.abs(l2 - 1))) * 0.5;
|
|
2942
|
-
out[1] = 2 * (v - l) / v;
|
|
2943
|
-
out[2] = v;
|
|
2944
|
-
return out;
|
|
2945
|
-
};
|
|
2946
|
-
const rgbHcv = (out, src) => {
|
|
2947
|
-
out = clamp(out || src, src);
|
|
2948
|
-
const p = out[1] < out[2] ? [out[2], out[1], -1, 2 / 3] : [out[1], out[2], 0, -1 / 3];
|
|
2949
|
-
const q = out[0] < p[0] ? [p[0], p[1], p[3], out[0]] : [out[0], p[1], p[2], p[0]];
|
|
2950
|
-
const c2 = q[0] - Math.min(q[1], q[3]);
|
|
2951
|
-
return setC3(
|
|
2952
|
-
out,
|
|
2953
|
-
clamp01(Math.abs((q[3] - q[1]) / (6 * c2 + EPS) + q[2])),
|
|
2954
|
-
clamp01(c2),
|
|
2955
|
-
clamp01(q[0])
|
|
2956
|
-
);
|
|
2957
|
-
};
|
|
2958
|
-
const rgbHsv = (out, src) => {
|
|
2959
|
-
out = rgbHcv(out, src);
|
|
2960
|
-
out[1] /= out[2] + EPS;
|
|
2961
|
-
return out;
|
|
2962
|
-
};
|
|
2963
|
-
const hsv = defColor({
|
|
2964
|
-
mode: "hsv",
|
|
2965
|
-
channels: { h: { hue: true } },
|
|
2966
|
-
order: ["h", "s", "v", "alpha"],
|
|
2967
|
-
from: {
|
|
2968
|
-
rgb: rgbHsv,
|
|
2969
|
-
srgb: rgbHsv,
|
|
2970
|
-
hsl: hslHsv,
|
|
2971
|
-
lch: [lchLab, labRgb, rgbSrgb, rgbHsv]
|
|
2972
|
-
},
|
|
2973
|
-
toRgb: hsvRgb
|
|
2974
|
-
});
|
|
2975
|
-
const defOpVN = (op, dispatch = 1) => {
|
|
2976
|
-
const a2 = (o, a22, n) => {
|
|
2977
|
-
!o && (o = a22);
|
|
2978
|
-
for (let i = a22.length; i-- > 0; ) o[i] = op(a22[i], n);
|
|
2979
|
-
return o;
|
|
2980
|
-
};
|
|
2981
|
-
const b2 = (o, a22, n) => {
|
|
2982
|
-
!o && (o = a22);
|
|
2983
|
-
o[0] = op(a22[0], n);
|
|
2984
|
-
o[1] = op(a22[1], n);
|
|
2985
|
-
return o;
|
|
2986
|
-
};
|
|
2987
|
-
const c2 = (o, a22, n) => {
|
|
2988
|
-
!o && (o = a22);
|
|
2989
|
-
o[0] = op(a22[0], n);
|
|
2990
|
-
o[1] = op(a22[1], n);
|
|
2991
|
-
o[2] = op(a22[2], n);
|
|
2992
|
-
return o;
|
|
2993
|
-
};
|
|
2994
|
-
const d2 = (o, a22, n) => {
|
|
2995
|
-
!o && (o = a22);
|
|
2996
|
-
o[0] = op(a22[0], n);
|
|
2997
|
-
o[1] = op(a22[1], n);
|
|
2998
|
-
o[2] = op(a22[2], n);
|
|
2999
|
-
o[3] = op(a22[3], n);
|
|
3000
|
-
return o;
|
|
3001
|
-
};
|
|
3002
|
-
return [
|
|
3003
|
-
vop(dispatch, a2, b2, c2, d2),
|
|
3004
|
-
b2,
|
|
3005
|
-
c2,
|
|
3006
|
-
d2
|
|
3007
|
-
];
|
|
3008
|
-
};
|
|
3009
|
-
const [a$4, b$1, c] = defOpVN(Math.pow);
|
|
3010
|
-
const powN3 = c;
|
|
3011
|
-
const CONE_LMS = [
|
|
3012
|
-
0.4122214708,
|
|
3013
|
-
0.2119034982,
|
|
3014
|
-
0.0883024619,
|
|
3015
|
-
0.5363325363,
|
|
3016
|
-
0.6806995451,
|
|
3017
|
-
0.2817188376,
|
|
3018
|
-
0.0514459929,
|
|
3019
|
-
0.1073969566,
|
|
3020
|
-
0.6299787005
|
|
3021
|
-
];
|
|
3022
|
-
const rgbOklab = (out, src) => __mulV33(null, OKLAB_M2, powN3(null, __mulV33(out, CONE_LMS, src), 1 / 3));
|
|
3023
|
-
const oklabOklch = (out, src) => setC4(
|
|
3024
|
-
out || src,
|
|
3025
|
-
src[0],
|
|
3026
|
-
Math.hypot(src[1], src[2]),
|
|
3027
|
-
atan2Abs(src[2], src[1]) * INV_TAU,
|
|
3028
|
-
__ensureAlpha(src[3])
|
|
3029
|
-
);
|
|
3030
|
-
const oklchOklab = (out, src) => setC4(
|
|
3031
|
-
out || src,
|
|
3032
|
-
src[0],
|
|
3033
|
-
...cossin(src[2] * TAU, src[1]),
|
|
3034
|
-
__ensureAlpha(src[3])
|
|
3035
|
-
);
|
|
3036
|
-
const oklch = defColor({
|
|
3037
|
-
mode: "oklch",
|
|
3038
|
-
channels: {
|
|
3039
|
-
c: { range: [0, 0.3225] }
|
|
3040
|
-
},
|
|
3041
|
-
order: ["l", "c", "h", "alpha"],
|
|
3042
|
-
from: {
|
|
3043
|
-
oklab: oklabOklch,
|
|
3044
|
-
rgb: (out, src) => oklabOklch(null, rgbOklab(out, src))
|
|
3045
|
-
},
|
|
3046
|
-
toRgb: [oklchOklab, oklabRgb]
|
|
3047
|
-
});
|
|
3048
|
-
const srgb = defColor({
|
|
3049
|
-
mode: "srgb",
|
|
3050
|
-
order: ["r", "g", "b", "alpha"],
|
|
3051
|
-
from: {
|
|
3052
|
-
abgr32: (out, src) => intAbgr32Srgb(out, src[0]),
|
|
3053
|
-
argb32: (out, src) => intArgb32Srgb(out, src[0]),
|
|
3054
|
-
hcy: hcyRgb,
|
|
3055
|
-
hsi: hsiRgb,
|
|
3056
|
-
hsl: hslRgb,
|
|
3057
|
-
hsv: hsvRgb,
|
|
3058
|
-
rgb: rgbSrgb
|
|
3059
|
-
},
|
|
3060
|
-
toRgb: srgbRgb
|
|
3061
|
-
});
|
|
3062
|
-
const compare = (a2, b2) => {
|
|
3063
|
-
if (a2 === b2) {
|
|
3064
|
-
return 0;
|
|
3065
|
-
}
|
|
3066
|
-
if (a2 == null) {
|
|
3067
|
-
return b2 == null ? 0 : -1;
|
|
3068
|
-
}
|
|
3069
|
-
if (b2 == null) {
|
|
3070
|
-
return a2 == null ? 0 : 1;
|
|
3071
|
-
}
|
|
3072
|
-
if (typeof a2.compare === "function") {
|
|
3073
|
-
return a2.compare(b2);
|
|
3074
|
-
}
|
|
3075
|
-
if (typeof b2.compare === "function") {
|
|
3076
|
-
return -b2.compare(a2);
|
|
3077
|
-
}
|
|
3078
|
-
return a2 < b2 ? -1 : a2 > b2 ? 1 : 0;
|
|
3079
|
-
};
|
|
3080
|
-
const __key = (k) => typeof k === "function" ? k : (x) => x[k];
|
|
3081
|
-
function compareByKey(key, cmp = compare) {
|
|
3082
|
-
const kfn = __key(key);
|
|
3083
|
-
return (x, y) => cmp(kfn(x), kfn(y));
|
|
3084
|
-
}
|
|
3085
|
-
const compareNumDesc = (a2, b2) => b2 - a2;
|
|
3086
|
-
const defOpVV = (op, dispatch = 1, outA = true) => {
|
|
3087
|
-
const a2 = outA ? (o, a22, b22) => {
|
|
3088
|
-
!o && (o = a22);
|
|
3089
|
-
for (let i = a22.length; i-- > 0; ) o[i] = op(a22[i], b22[i]);
|
|
3090
|
-
return o;
|
|
3091
|
-
} : (o, a22, b22) => {
|
|
3092
|
-
!o && (o = b22);
|
|
3093
|
-
for (let i = a22.length; i-- > 0; ) o[i] = op(a22[i], b22[i]);
|
|
3094
|
-
return o;
|
|
3095
|
-
};
|
|
3096
|
-
const b2 = outA ? (o, a22, b22) => {
|
|
3097
|
-
!o && (o = a22);
|
|
3098
|
-
o[0] = op(a22[0], b22[0]);
|
|
3099
|
-
o[1] = op(a22[1], b22[1]);
|
|
3100
|
-
return o;
|
|
3101
|
-
} : (o, a22, b22) => {
|
|
3102
|
-
!o && (o = b22);
|
|
3103
|
-
o[0] = op(a22[0], b22[0]);
|
|
3104
|
-
o[1] = op(a22[1], b22[1]);
|
|
3105
|
-
return o;
|
|
3106
|
-
};
|
|
3107
|
-
const c2 = outA ? (o, a22, b22) => {
|
|
3108
|
-
!o && (o = a22);
|
|
3109
|
-
o[0] = op(a22[0], b22[0]);
|
|
3110
|
-
o[1] = op(a22[1], b22[1]);
|
|
3111
|
-
o[2] = op(a22[2], b22[2]);
|
|
3112
|
-
return o;
|
|
3113
|
-
} : (o, a22, b22) => {
|
|
3114
|
-
!o && (o = b22);
|
|
3115
|
-
o[0] = op(a22[0], b22[0]);
|
|
3116
|
-
o[1] = op(a22[1], b22[1]);
|
|
3117
|
-
o[2] = op(a22[2], b22[2]);
|
|
3118
|
-
return o;
|
|
3119
|
-
};
|
|
3120
|
-
const d2 = outA ? (o, a22, b22) => {
|
|
3121
|
-
!o && (o = a22);
|
|
3122
|
-
o[0] = op(a22[0], b22[0]);
|
|
3123
|
-
o[1] = op(a22[1], b22[1]);
|
|
3124
|
-
o[2] = op(a22[2], b22[2]);
|
|
3125
|
-
o[3] = op(a22[3], b22[3]);
|
|
3126
|
-
return o;
|
|
3127
|
-
} : (o, a22, b22) => {
|
|
3128
|
-
!o && (o = b22);
|
|
3129
|
-
o[0] = op(a22[0], b22[0]);
|
|
3130
|
-
o[1] = op(a22[1], b22[1]);
|
|
3131
|
-
o[2] = op(a22[2], b22[2]);
|
|
3132
|
-
o[3] = op(a22[3], b22[3]);
|
|
3133
|
-
return o;
|
|
3134
|
-
};
|
|
3135
|
-
return [
|
|
3136
|
-
vop(dispatch, a2, b2, c2, d2),
|
|
3137
|
-
b2,
|
|
3138
|
-
c2,
|
|
3139
|
-
d2
|
|
3140
|
-
];
|
|
3141
|
-
};
|
|
3142
|
-
const $add = (a2, b2) => a2 + b2;
|
|
3143
|
-
const $mul = (a2, b2) => a2 * b2;
|
|
3144
|
-
const $sub = (a2, b2) => a2 - b2;
|
|
3145
|
-
const [a$3, b] = defOpVV($add);
|
|
3146
|
-
const add = a$3;
|
|
3147
|
-
const add2 = b;
|
|
3148
|
-
const ZERO2 = Object.freeze([0, 0]);
|
|
3149
|
-
const ZERO3 = Object.freeze([0, 0, 0]);
|
|
3150
|
-
const cos = Math.cos;
|
|
3151
|
-
const sin = Math.sin;
|
|
3152
|
-
const cartesian = vop(1);
|
|
3153
|
-
cartesian.add(
|
|
3154
|
-
2,
|
|
3155
|
-
(out, v, offset = ZERO2) => add2(out || v, cossin(v[1], v[0]), offset)
|
|
3156
|
-
);
|
|
3157
|
-
cartesian.add(3, (out, v, offset = ZERO3) => {
|
|
3158
|
-
const r = v[0];
|
|
3159
|
-
const theta = v[1];
|
|
3160
|
-
const phi = v[2];
|
|
3161
|
-
const ct = cos(theta);
|
|
3162
|
-
return setC3(
|
|
3163
|
-
out || v,
|
|
3164
|
-
r * ct * cos(phi) + offset[0],
|
|
3165
|
-
r * ct * sin(phi) + offset[1],
|
|
3166
|
-
r * sin(theta) + offset[2]
|
|
3167
|
-
);
|
|
3168
|
-
});
|
|
3169
|
-
const cartesian2FromAngles = (angles, n) => {
|
|
3170
|
-
const polar = [];
|
|
3171
|
-
for (let x of angles) polar.push(cossin(x, n));
|
|
3172
|
-
return polar;
|
|
3173
|
-
};
|
|
3174
|
-
const __ensureInputs = (src) => assert(src.length > 0, `no inputs given`);
|
|
3175
|
-
const [a$2] = defOpVN($mul);
|
|
3176
|
-
const mulN = a$2;
|
|
3177
|
-
const sum2 = (a2) => a2[0] + a2[1];
|
|
3178
|
-
const sum3 = (a2) => a2[0] + a2[1] + a2[2];
|
|
3179
|
-
const sum4 = (a2) => a2[0] + a2[1] + a2[2] + a2[3];
|
|
3180
|
-
const sum = vop(
|
|
3181
|
-
0,
|
|
3182
|
-
(v) => {
|
|
3183
|
-
let res = 0;
|
|
3184
|
-
for (let i = v.length; i-- > 0; ) res += v[i];
|
|
3185
|
-
return res;
|
|
3186
|
-
},
|
|
3187
|
-
sum2,
|
|
3188
|
-
sum3,
|
|
3189
|
-
sum4
|
|
3190
|
-
);
|
|
3191
|
-
const mean = (out, src) => {
|
|
3192
|
-
__ensureInputs(src);
|
|
3193
|
-
out = set(out || [], src[0]);
|
|
3194
|
-
for (let i = src.length; i-- > 1; ) {
|
|
3195
|
-
add(out, out, src[i]);
|
|
3196
|
-
}
|
|
3197
|
-
return mulN(out, out, 1 / src.length);
|
|
3198
|
-
};
|
|
3199
|
-
const vmean = (a2) => a2.length > 0 ? sum(a2) / a2.length : 0;
|
|
3200
|
-
const [a$1] = defOpVN($sub);
|
|
3201
|
-
const subN = a$1;
|
|
3202
|
-
const center = (out, a2) => subN(out, a2, vmean(a2));
|
|
3203
|
-
const headingXY = (a2) => atan2Abs(a2[1], a2[0]);
|
|
3204
|
-
const magSq2 = (a2) => a2[0] * a2[0] + a2[1] * a2[1];
|
|
3205
|
-
const magSq3 = (a2) => a2[0] * a2[0] + a2[1] * a2[1] + a2[2] * a2[2];
|
|
3206
|
-
const magSq4 = (a2) => a2[0] * a2[0] + a2[1] * a2[1] + a2[2] * a2[2] + a2[3] * a2[3];
|
|
3207
|
-
const magSq = vop(
|
|
3208
|
-
0,
|
|
3209
|
-
(a2) => {
|
|
3210
|
-
let sum5 = 0;
|
|
3211
|
-
for (let i = a2.length; i-- > 0; ) sum5 += a2[i] * a2[i];
|
|
3212
|
-
return sum5;
|
|
3213
|
-
},
|
|
3214
|
-
magSq2,
|
|
3215
|
-
magSq3,
|
|
3216
|
-
magSq4
|
|
3217
|
-
);
|
|
3218
|
-
const variance = (a2, isCentered = false, corrected = false) => {
|
|
3219
|
-
const k = ~~corrected;
|
|
3220
|
-
return a2.length > k ? magSq(isCentered ? a2 : center([], a2)) / (a2.length - k) : 0;
|
|
3221
|
-
};
|
|
3222
|
-
const sd = (a2, isCentered = false, corrected = false) => Math.sqrt(variance(a2, isCentered, corrected));
|
|
3223
|
-
const circularMean = (angles) => headingXY(mean([], cartesian2FromAngles(angles)));
|
|
3224
|
-
const centerCircular = (out, angles) => {
|
|
3225
|
-
const mean2 = circularMean(angles);
|
|
3226
|
-
!out && (out = []);
|
|
3227
|
-
for (let i = 0, n = angles.length; i < n; i++) {
|
|
3228
|
-
out[i] = (angles[i] - mean2 + PI) % TAU;
|
|
3229
|
-
}
|
|
3230
|
-
return center(null, out);
|
|
3231
|
-
};
|
|
3232
|
-
const circularSD = (angles, corrected) => sd(centerCircular([], angles), true, corrected);
|
|
3233
|
-
defOpVV(Math.max);
|
|
3234
|
-
const vmax = (v) => {
|
|
3235
|
-
let max5 = -Infinity;
|
|
3236
|
-
for (let i = v.length; i-- > 0; ) max5 = Math.max(max5, v[i]);
|
|
3237
|
-
return max5;
|
|
3238
|
-
};
|
|
3239
|
-
const vmedian = (a2) => {
|
|
3240
|
-
if (!a2.length) return 0;
|
|
3241
|
-
const n = a2.length;
|
|
3242
|
-
const m = n >> 1;
|
|
3243
|
-
a2 = [...a2].sort((a22, b2) => a22 - b2);
|
|
3244
|
-
return n & 1 ? a2[m] : (a2[m - 1] + a2[m]) * 0.5;
|
|
3245
|
-
};
|
|
3246
|
-
defOpVV(Math.min);
|
|
3247
|
-
const vmin = (v) => {
|
|
3248
|
-
let min5 = Infinity;
|
|
3249
|
-
for (let i = v.length; i-- > 0; ) min5 = Math.min(min5, v[i]);
|
|
3250
|
-
return min5;
|
|
3251
|
-
};
|
|
3252
|
-
const defMetric = (values) => {
|
|
3253
|
-
const [min2, max2] = valueRange(values);
|
|
3254
|
-
return {
|
|
3255
|
-
min: min2,
|
|
3256
|
-
max: max2,
|
|
3257
|
-
mean: vmean(values),
|
|
3258
|
-
median: vmedian(values),
|
|
3259
|
-
sd: sd(values)
|
|
3260
|
-
};
|
|
3261
|
-
};
|
|
3262
|
-
const defWeightedMetric = (values, weights) => {
|
|
3263
|
-
const [min2, max2] = valueRange(values);
|
|
3264
|
-
return {
|
|
3265
|
-
min: min2,
|
|
3266
|
-
max: max2,
|
|
3267
|
-
mean: vmean(values),
|
|
3268
|
-
median: vmedian(values),
|
|
3269
|
-
sd: sd(values),
|
|
3270
|
-
weighted: dot(values, weights)
|
|
3271
|
-
};
|
|
3272
|
-
};
|
|
3273
|
-
const defCircularMetric = (values) => {
|
|
3274
|
-
const scaledValues = values.map((x) => x * TAU);
|
|
3275
|
-
const mean2 = fract(circularMean(scaledValues) / TAU);
|
|
3276
|
-
const [min2, max2] = circularRange(values, mean2);
|
|
3277
|
-
return {
|
|
3278
|
-
min: min2,
|
|
3279
|
-
max: max2,
|
|
3280
|
-
mean: mean2,
|
|
3281
|
-
median: __circularMedian(values, min2, max2),
|
|
3282
|
-
sd: circularSD(scaledValues) / TAU
|
|
3283
|
-
};
|
|
3284
|
-
};
|
|
3285
|
-
const valueRange = (values) => [
|
|
3286
|
-
vmin(values),
|
|
3287
|
-
vmax(values)
|
|
3288
|
-
];
|
|
3289
|
-
const circularRange = (values, mean2) => {
|
|
3290
|
-
const range = valueRange(values);
|
|
3291
|
-
const [min2, max2] = range;
|
|
3292
|
-
if (mean2 < min2 || mean2 > max2) {
|
|
3293
|
-
return [
|
|
3294
|
-
values.reduce(
|
|
3295
|
-
(acc, x) => {
|
|
3296
|
-
const d2 = fract(mean2 - x);
|
|
3297
|
-
return d2 < 0.5 && d2 > acc[1] ? [x, d2] : acc;
|
|
3298
|
-
},
|
|
3299
|
-
[max2, fract(mean2 - max2)]
|
|
3300
|
-
)[0],
|
|
3301
|
-
values.reduce(
|
|
3302
|
-
(acc, x) => {
|
|
3303
|
-
const d2 = fract(x - mean2);
|
|
3304
|
-
return d2 < 0.5 && d2 > acc[1] ? [x, d2] : acc;
|
|
3305
|
-
},
|
|
3306
|
-
[min2, fract(min2 - mean2)]
|
|
3307
|
-
)[0]
|
|
3308
|
-
];
|
|
3309
|
-
}
|
|
3310
|
-
return range;
|
|
3311
|
-
};
|
|
3312
|
-
const __circularMedian = (values, min2, max2) => {
|
|
3313
|
-
if (min2 <= max2) return vmedian(values);
|
|
3314
|
-
const n = values.length;
|
|
3315
|
-
const m = n >> 1;
|
|
3316
|
-
const sorted = [...values].sort((a2, b2) => a2 - b2);
|
|
3317
|
-
const split = sorted.findIndex((x) => x === min2);
|
|
3318
|
-
const reordered = sorted.slice(split).concat(sorted.slice(0, split));
|
|
3319
|
-
return n & 1 ? reordered[m] : (reordered[m - 1] + reordered[m]) * 0.5;
|
|
3320
|
-
};
|
|
3321
|
-
const isFunction = (x) => typeof x === "function";
|
|
3322
|
-
const distSq2 = (a2, b2) => {
|
|
3323
|
-
const dx = a2[0] - b2[0];
|
|
3324
|
-
const dy = a2[1] - b2[1];
|
|
3325
|
-
return dx * dx + dy * dy;
|
|
3326
|
-
};
|
|
3327
|
-
const distSq3 = (a2, b2) => {
|
|
3328
|
-
const dx = a2[0] - b2[0];
|
|
3329
|
-
const dy = a2[1] - b2[1];
|
|
3330
|
-
const dz = a2[2] - b2[2];
|
|
3331
|
-
return dx * dx + dy * dy + dz * dz;
|
|
3332
|
-
};
|
|
3333
|
-
const distSq4 = (a2, b2) => {
|
|
3334
|
-
const dx = a2[0] - b2[0];
|
|
3335
|
-
const dy = a2[1] - b2[1];
|
|
3336
|
-
const dz = a2[2] - b2[2];
|
|
3337
|
-
const dw = a2[3] - b2[3];
|
|
3338
|
-
return dx * dx + dy * dy + dz * dz + dw * dw;
|
|
3339
|
-
};
|
|
3340
|
-
const distSq = vop(
|
|
3341
|
-
0,
|
|
3342
|
-
(a2, b2) => {
|
|
3343
|
-
let sum5 = 0;
|
|
3344
|
-
for (let i = a2.length; i-- > 0; ) {
|
|
3345
|
-
const d2 = a2[i] - b2[i];
|
|
3346
|
-
sum5 += d2 * d2;
|
|
3347
|
-
}
|
|
3348
|
-
return sum5;
|
|
3349
|
-
},
|
|
3350
|
-
distSq2,
|
|
3351
|
-
distSq3,
|
|
3352
|
-
distSq4
|
|
3353
|
-
);
|
|
3354
|
-
class Squared {
|
|
3355
|
-
constructor(metric) {
|
|
3356
|
-
this.metric = metric;
|
|
3357
|
-
}
|
|
3358
|
-
to(x) {
|
|
3359
|
-
return x * x;
|
|
3360
|
-
}
|
|
3361
|
-
from(x) {
|
|
3362
|
-
return Math.sqrt(x);
|
|
3363
|
-
}
|
|
3364
|
-
}
|
|
3365
|
-
const DIST_SQ = new Squared(distSq);
|
|
3366
|
-
const argmin = (p, samples, dist = DIST_SQ) => {
|
|
3367
|
-
const distFn = isFunction(dist) ? dist : dist.metric;
|
|
3368
|
-
let minD = Infinity;
|
|
3369
|
-
let minArg = -1;
|
|
3370
|
-
for (let i = 0, n = samples.length; i < n; i++) {
|
|
3371
|
-
const d2 = distFn(p, samples[i]);
|
|
3372
|
-
if (d2 < minD) {
|
|
3373
|
-
minD = d2;
|
|
3374
|
-
minArg = i;
|
|
3375
|
-
}
|
|
3376
|
-
}
|
|
3377
|
-
return minArg;
|
|
3378
|
-
};
|
|
3379
|
-
const setN2 = (a2, n) => {
|
|
3380
|
-
a2[0] = n;
|
|
3381
|
-
a2[1] = n;
|
|
3382
|
-
return a2;
|
|
3383
|
-
};
|
|
3384
|
-
const setN3 = (a2, n) => {
|
|
3385
|
-
a2[0] = n;
|
|
3386
|
-
a2[1] = n;
|
|
3387
|
-
a2[2] = n;
|
|
3388
|
-
return a2;
|
|
3389
|
-
};
|
|
3390
|
-
const setN4 = (a2, n) => {
|
|
3391
|
-
a2[0] = n;
|
|
3392
|
-
a2[1] = n;
|
|
3393
|
-
a2[2] = n;
|
|
3394
|
-
a2[3] = n;
|
|
3395
|
-
return a2;
|
|
3396
|
-
};
|
|
3397
|
-
vop(
|
|
3398
|
-
0,
|
|
3399
|
-
(a2, n) => {
|
|
3400
|
-
for (let i = a2.length; i-- > 0; ) a2[i] = n;
|
|
3401
|
-
return a2;
|
|
3402
|
-
},
|
|
3403
|
-
setN2,
|
|
3404
|
-
setN3,
|
|
3405
|
-
setN4
|
|
3406
|
-
);
|
|
3407
|
-
const zeroes = (n) => Array(n).fill(0);
|
|
3408
|
-
const ones = (n) => Array(n).fill(1);
|
|
3409
|
-
const kmeans = (k, samples, opts = {}) => {
|
|
3410
|
-
let {
|
|
3411
|
-
dim = samples[0].length,
|
|
3412
|
-
dist = DIST_SQ,
|
|
3413
|
-
maxIter = 32,
|
|
3414
|
-
strategy = means,
|
|
3415
|
-
exponent,
|
|
3416
|
-
initial,
|
|
3417
|
-
rnd
|
|
3418
|
-
} = opts;
|
|
3419
|
-
const num = samples.length;
|
|
3420
|
-
const centroids = Array.isArray(initial) ? initial : initial ? initial(k, samples, dist, rnd) : kmeansPlusPlus(k, samples, dist, rnd, exponent);
|
|
3421
|
-
assert(centroids.length > 0, `missing initial centroids`);
|
|
3422
|
-
k = centroids.length;
|
|
3423
|
-
const clusters = new Uint32Array(num).fill(k);
|
|
3424
|
-
let update = true;
|
|
3425
|
-
while (update && maxIter-- > 0) {
|
|
3426
|
-
update = __assign(samples, centroids, clusters, dist);
|
|
3427
|
-
if (!update) break;
|
|
3428
|
-
for (let i = 0; i < k; i++) {
|
|
3429
|
-
const impl = strategy(dim);
|
|
3430
|
-
for (let j = 0; j < num; j++) {
|
|
3431
|
-
i === clusters[j] && impl.update(samples[j]);
|
|
3432
|
-
}
|
|
3433
|
-
const centroid = impl.finish();
|
|
3434
|
-
if (centroid) centroids[i] = centroid;
|
|
3435
|
-
}
|
|
3436
|
-
}
|
|
3437
|
-
return __buildClusters(centroids, clusters);
|
|
3438
|
-
};
|
|
3439
|
-
const kmeansPlusPlus = (k, samples, dist = DIST_SQ, rnd = SYSTEM, exponent = 2) => {
|
|
3440
|
-
const num = samples.length;
|
|
3441
|
-
assert(num > 0, `missing samples`);
|
|
3442
|
-
k = Math.min(k, num);
|
|
3443
|
-
const centroidIDs = [rnd.int() % num];
|
|
3444
|
-
const centroids = [samples[centroidIDs[0]]];
|
|
3445
|
-
const indices = new Array(num).fill(0).map((_, i) => i);
|
|
3446
|
-
const metric = dist.metric;
|
|
3447
|
-
while (centroidIDs.length < k) {
|
|
3448
|
-
let psum = 0;
|
|
3449
|
-
const probs = samples.map((p) => {
|
|
3450
|
-
const d2 = dist.from(metric(p, centroids[argmin(p, centroids, dist)])) ** exponent;
|
|
3451
|
-
psum += d2;
|
|
3452
|
-
return d2;
|
|
3453
|
-
});
|
|
3454
|
-
if (!psum) break;
|
|
3455
|
-
let id;
|
|
3456
|
-
do {
|
|
3457
|
-
id = weightedRandom(indices, probs, rnd)();
|
|
3458
|
-
} while (centroidIDs.includes(id));
|
|
3459
|
-
centroidIDs.push(id);
|
|
3460
|
-
centroids.push(samples[id]);
|
|
3461
|
-
}
|
|
3462
|
-
return centroids;
|
|
3463
|
-
};
|
|
3464
|
-
const __assign = (samples, centroids, assignments, dist) => {
|
|
3465
|
-
let update = false;
|
|
3466
|
-
for (let i = samples.length; i-- > 0; ) {
|
|
3467
|
-
const id = argmin(samples[i], centroids, dist);
|
|
3468
|
-
if (id !== assignments[i]) {
|
|
3469
|
-
assignments[i] = id;
|
|
3470
|
-
update = true;
|
|
3471
|
-
}
|
|
3472
|
-
}
|
|
3473
|
-
return update;
|
|
3474
|
-
};
|
|
3475
|
-
const __buildClusters = (centroids, assignments) => {
|
|
3476
|
-
const clusters = [];
|
|
3477
|
-
for (let i = 0, n = assignments.length; i < n; i++) {
|
|
3478
|
-
const id = assignments[i];
|
|
3479
|
-
(clusters[id] || (clusters[id] = {
|
|
3480
|
-
id,
|
|
3481
|
-
centroid: centroids[id],
|
|
3482
|
-
items: []
|
|
3483
|
-
})).items.push(i);
|
|
3484
|
-
}
|
|
3485
|
-
return clusters.filter((x) => !!x);
|
|
3486
|
-
};
|
|
3487
|
-
const means = (dim) => {
|
|
3488
|
-
const acc = zeroes(dim);
|
|
3489
|
-
let n = 0;
|
|
3490
|
-
return {
|
|
3491
|
-
update: (p) => {
|
|
3492
|
-
add(acc, acc, p);
|
|
3493
|
-
n++;
|
|
3494
|
-
},
|
|
3495
|
-
finish: () => n ? mulN(acc, acc, 1 / n) : void 0
|
|
3496
|
-
};
|
|
3497
|
-
};
|
|
3498
|
-
const filterSamples = (pred, img) => {
|
|
3499
|
-
const samples = [];
|
|
3500
|
-
let i = 0;
|
|
3501
|
-
for (let p of img) {
|
|
3502
|
-
if (pred(p, i)) samples.push(p);
|
|
3503
|
-
i++;
|
|
3504
|
-
}
|
|
3505
|
-
return samples;
|
|
3506
|
-
};
|
|
3507
|
-
const dominantColorsKmeans = (img, num, opts) => {
|
|
3508
|
-
const samples = opts?.filter ? filterSamples(opts.filter, img) : Array.isArray(img) ? img : [...img];
|
|
3509
|
-
return samples.length ? kmeans(Math.min(num, samples.length), samples, opts).sort((a2, b2) => b2.items.length - a2.items.length).map(
|
|
3510
|
-
(c2) => ({
|
|
3511
|
-
color: [...c2.centroid],
|
|
3512
|
-
area: c2.items.length / samples.length,
|
|
3513
|
-
ids: c2.items
|
|
3514
|
-
})
|
|
3515
|
-
) : [];
|
|
3516
|
-
};
|
|
3517
|
-
const isIterable = (x) => typeof x?.[Symbol.iterator] === "function";
|
|
3518
|
-
const compR = (rfn, fn) => [rfn[0], rfn[1], fn];
|
|
3519
|
-
const SEMAPHORE = Symbol();
|
|
3520
|
-
const NO_OP = () => {
|
|
3521
|
-
};
|
|
3522
|
-
const ensureTransducer = (x) => implementsFunction(x, "xform") ? x.xform() : x;
|
|
3523
|
-
const IllegalArityError = defError(() => "illegal arity");
|
|
3524
|
-
const illegalArity = (n) => {
|
|
3525
|
-
throw new IllegalArityError(n);
|
|
3526
|
-
};
|
|
3527
|
-
class Reduced {
|
|
3528
|
-
value;
|
|
3529
|
-
constructor(val) {
|
|
3530
|
-
this.value = val;
|
|
3531
|
-
}
|
|
3532
|
-
deref() {
|
|
3533
|
-
return this.value;
|
|
3534
|
-
}
|
|
3535
|
-
}
|
|
3536
|
-
const isReduced = (x) => x instanceof Reduced;
|
|
3537
|
-
const ensureReduced = (x) => x instanceof Reduced ? x : new Reduced(x);
|
|
3538
|
-
const unreduced = (x) => x instanceof Reduced ? x.deref() : x;
|
|
3539
|
-
const __parseArgs = (args) => args.length === 2 ? [void 0, args[1]] : args.length === 3 ? [args[1], args[2]] : illegalArity(args.length);
|
|
3540
|
-
function reduce(...args) {
|
|
3541
|
-
const rfn = args[0];
|
|
3542
|
-
const init = rfn[0];
|
|
3543
|
-
const complete = rfn[1];
|
|
3544
|
-
const reduce2 = rfn[2];
|
|
3545
|
-
args = __parseArgs(args);
|
|
3546
|
-
const acc = args[0] == null ? init() : args[0];
|
|
3547
|
-
const src = args[1];
|
|
3548
|
-
return unreduced(
|
|
3549
|
-
complete(
|
|
3550
|
-
implementsFunction(src, "$reduce") ? src.$reduce(reduce2, acc) : isArrayLike(src) ? __reduceArray(reduce2, acc, src) : __reduceIterable(reduce2, acc, src)
|
|
3551
|
-
)
|
|
3552
|
-
);
|
|
3553
|
-
}
|
|
3554
|
-
const __reduceArray = (rfn, acc, src) => {
|
|
3555
|
-
for (let i = 0, n = src.length; i < n; i++) {
|
|
3556
|
-
acc = rfn(acc, src[i]);
|
|
3557
|
-
if (isReduced(acc)) {
|
|
3558
|
-
acc = acc.deref();
|
|
3559
|
-
break;
|
|
3560
|
-
}
|
|
3561
|
-
}
|
|
3562
|
-
return acc;
|
|
3563
|
-
};
|
|
3564
|
-
const __reduceIterable = (rfn, acc, src) => {
|
|
3565
|
-
for (let x of src) {
|
|
3566
|
-
acc = rfn(acc, x);
|
|
3567
|
-
if (isReduced(acc)) {
|
|
3568
|
-
acc = acc.deref();
|
|
3569
|
-
break;
|
|
3570
|
-
}
|
|
3571
|
-
}
|
|
3572
|
-
return acc;
|
|
3573
|
-
};
|
|
3574
|
-
const reducer = (init, rfn) => [init, identity$1, rfn];
|
|
3575
|
-
const $$reduce = (rfn, args) => {
|
|
3576
|
-
const n = args.length - 1;
|
|
3577
|
-
return isIterable(args[n]) ? args.length > 1 ? reduce(rfn.apply(null, args.slice(0, n)), args[n]) : reduce(rfn(), args[0]) : void 0;
|
|
3578
|
-
};
|
|
3579
|
-
function push(src) {
|
|
3580
|
-
return src ? [...src] : reducer(
|
|
3581
|
-
() => [],
|
|
3582
|
-
(acc, x) => (acc.push(x), acc)
|
|
3583
|
-
);
|
|
3584
|
-
}
|
|
3585
|
-
function* iterator(xform, src) {
|
|
3586
|
-
const rfn = ensureTransducer(xform)(push());
|
|
3587
|
-
const complete = rfn[1];
|
|
3588
|
-
const reduce2 = rfn[2];
|
|
3589
|
-
for (let x of src) {
|
|
3590
|
-
const y = reduce2([], x);
|
|
3591
|
-
if (isReduced(y)) {
|
|
3592
|
-
yield* unreduced(complete(y.deref()));
|
|
3593
|
-
return;
|
|
3594
|
-
}
|
|
3595
|
-
if (y.length) {
|
|
3596
|
-
yield* y;
|
|
3597
|
-
}
|
|
3598
|
-
}
|
|
3599
|
-
yield* unreduced(complete([]));
|
|
3600
|
-
}
|
|
3601
|
-
function* iterator1(xform, src) {
|
|
3602
|
-
const reduce2 = ensureTransducer(xform)([NO_OP, NO_OP, (_, x) => x])[2];
|
|
3603
|
-
for (let x of src) {
|
|
3604
|
-
let y = reduce2(SEMAPHORE, x);
|
|
3605
|
-
if (isReduced(y)) {
|
|
3606
|
-
y = unreduced(y.deref());
|
|
3607
|
-
if (y !== SEMAPHORE) {
|
|
3608
|
-
yield y;
|
|
3609
|
-
}
|
|
3610
|
-
return;
|
|
3611
|
-
}
|
|
3612
|
-
if (y !== SEMAPHORE) {
|
|
3613
|
-
yield y;
|
|
3614
|
-
}
|
|
3615
|
-
}
|
|
3616
|
-
}
|
|
3617
|
-
function map(fn, src) {
|
|
3618
|
-
return isIterable(src) ? iterator1(map(fn), src) : (rfn) => {
|
|
3619
|
-
const r = rfn[2];
|
|
3620
|
-
return compR(rfn, (acc, x) => r(acc, fn(x)));
|
|
3621
|
-
};
|
|
3622
|
-
}
|
|
3623
|
-
function max(src) {
|
|
3624
|
-
return src ? reduce(max(), src) : reducer(
|
|
3625
|
-
() => -Infinity,
|
|
3626
|
-
(acc, x) => Math.max(acc, x)
|
|
3627
|
-
);
|
|
3628
|
-
}
|
|
3629
|
-
const ensureIterable = (x) => {
|
|
3630
|
-
(x == null || !x[Symbol.iterator]) && illegalArgs(`value is not iterable: ${x}`);
|
|
3631
|
-
return x;
|
|
3632
|
-
};
|
|
3633
|
-
const ensureArray = (x) => isArray(x) ? x : [...ensureIterable(x)];
|
|
3634
|
-
const ensureArrayLike = (x) => isArrayLike(x) ? x : [...ensureIterable(x)];
|
|
3635
|
-
function* permutations(...src) {
|
|
3636
|
-
const n = src.length - 1;
|
|
3637
|
-
if (n < 0) {
|
|
3638
|
-
return;
|
|
3639
|
-
}
|
|
3640
|
-
const step = new Array(n + 1).fill(0);
|
|
3641
|
-
const realized = src.map(ensureArrayLike);
|
|
3642
|
-
const total = realized.reduce((acc, x) => acc * x.length, 1);
|
|
3643
|
-
for (let i = 0; i < total; i++) {
|
|
3644
|
-
const tuple = [];
|
|
3645
|
-
for (let j = n; j >= 0; j--) {
|
|
3646
|
-
const r = realized[j];
|
|
3647
|
-
let s = step[j];
|
|
3648
|
-
if (s === r.length) {
|
|
3649
|
-
step[j] = s = 0;
|
|
3650
|
-
j > 0 && step[j - 1]++;
|
|
3651
|
-
}
|
|
3652
|
-
tuple[j] = r[s];
|
|
3653
|
-
}
|
|
3654
|
-
step[n]++;
|
|
3655
|
-
yield tuple;
|
|
3656
|
-
}
|
|
3657
|
-
}
|
|
3658
|
-
function transduce(...args) {
|
|
3659
|
-
return $transduce(transduce, reduce, args);
|
|
3660
|
-
}
|
|
3661
|
-
const $transduce = (tfn, rfn, args) => {
|
|
3662
|
-
let acc, src;
|
|
3663
|
-
switch (args.length) {
|
|
3664
|
-
case 4:
|
|
3665
|
-
src = args[3];
|
|
3666
|
-
acc = args[2];
|
|
3667
|
-
break;
|
|
3668
|
-
case 3:
|
|
3669
|
-
src = args[2];
|
|
3670
|
-
break;
|
|
3671
|
-
case 2:
|
|
3672
|
-
return map((x) => tfn(args[0], args[1], x));
|
|
3673
|
-
default:
|
|
3674
|
-
illegalArity(args.length);
|
|
3675
|
-
}
|
|
3676
|
-
return rfn(ensureTransducer(args[0])(args[1]), acc, src);
|
|
3677
|
-
};
|
|
3678
|
-
const [a] = defOpVN(roundTo);
|
|
3679
|
-
const roundN = a;
|
|
3680
|
-
const smoothStep = (edge, edge2, x) => smoothStep01(clamp01((x - edge) / (edge2 - edge)));
|
|
3681
|
-
const smoothStep01 = (x) => x * x * (3 - 2 * x);
|
|
3682
|
-
function comp$1(...fns) {
|
|
3683
|
-
let [a2, b2, c2, d2, e, f, g, h, i, j] = fns;
|
|
3684
|
-
switch (fns.length) {
|
|
3685
|
-
case 0:
|
|
3686
|
-
illegalArity(0);
|
|
3687
|
-
case 1:
|
|
3688
|
-
return a2;
|
|
3689
|
-
case 2:
|
|
3690
|
-
return (...args) => a2(b2(...args));
|
|
3691
|
-
case 3:
|
|
3692
|
-
return (...args) => a2(b2(c2(...args)));
|
|
3693
|
-
case 4:
|
|
3694
|
-
return (...args) => a2(b2(c2(d2(...args))));
|
|
3695
|
-
case 5:
|
|
3696
|
-
return (...args) => a2(b2(c2(d2(e(...args)))));
|
|
3697
|
-
case 6:
|
|
3698
|
-
return (...args) => a2(b2(c2(d2(e(f(...args))))));
|
|
3699
|
-
case 7:
|
|
3700
|
-
return (...args) => a2(b2(c2(d2(e(f(g(...args)))))));
|
|
3701
|
-
case 8:
|
|
3702
|
-
return (...args) => a2(b2(c2(d2(e(f(g(h(...args))))))));
|
|
3703
|
-
case 9:
|
|
3704
|
-
return (...args) => a2(b2(c2(d2(e(f(g(h(i(...args)))))))));
|
|
3705
|
-
case 10:
|
|
3706
|
-
default:
|
|
3707
|
-
const fn = (...args) => a2(b2(c2(d2(e(f(g(h(i(j(...args))))))))));
|
|
3708
|
-
return fns.length === 10 ? fn : comp$1(fn, ...fns.slice(10));
|
|
3709
|
-
}
|
|
3710
|
-
}
|
|
3711
|
-
function comp(...fns) {
|
|
3712
|
-
fns = fns.map(ensureTransducer);
|
|
3713
|
-
return comp$1.apply(null, fns);
|
|
3714
|
-
}
|
|
3715
|
-
function count(...args) {
|
|
3716
|
-
const res = $$reduce(count, args);
|
|
3717
|
-
if (res !== void 0) {
|
|
3718
|
-
return res;
|
|
3719
|
-
}
|
|
3720
|
-
const [offset = 0, step = 1] = args;
|
|
3721
|
-
return reducer(
|
|
3722
|
-
() => offset,
|
|
3723
|
-
(acc, _) => acc + step
|
|
3724
|
-
);
|
|
3725
|
-
}
|
|
3726
|
-
const identity = (x) => x;
|
|
3727
|
-
const __groupByOpts = (opts) => ({
|
|
3728
|
-
key: (x) => x,
|
|
3729
|
-
group: push(),
|
|
3730
|
-
...opts
|
|
3731
|
-
});
|
|
3732
|
-
function groupByMap(...args) {
|
|
3733
|
-
const res = $$reduce(groupByMap, args);
|
|
3734
|
-
if (res !== void 0) return res;
|
|
3735
|
-
const opts = __groupByOpts(args[0]);
|
|
3736
|
-
const [init, complete, reduce2] = opts.group;
|
|
3737
|
-
return [
|
|
3738
|
-
() => /* @__PURE__ */ new Map(),
|
|
3739
|
-
(acc) => {
|
|
3740
|
-
for (let k of acc.keys()) {
|
|
3741
|
-
acc.set(k, complete(acc.get(k)));
|
|
3742
|
-
}
|
|
3743
|
-
return acc;
|
|
3744
|
-
},
|
|
3745
|
-
(acc, x) => {
|
|
3746
|
-
const k = opts.key(x);
|
|
3747
|
-
return acc.set(
|
|
3748
|
-
k,
|
|
3749
|
-
acc.has(k) ? reduce2(acc.get(k), x) : reduce2(init(), x)
|
|
3750
|
-
);
|
|
3751
|
-
}
|
|
3752
|
-
];
|
|
3753
|
-
}
|
|
3754
|
-
function frequencies(...args) {
|
|
3755
|
-
return $$reduce(frequencies, args) || groupByMap({ key: args[0] || identity, group: count() });
|
|
3756
|
-
}
|
|
3757
|
-
function normFrequenciesAuto(...args) {
|
|
3758
|
-
const res = $$reduce(normFrequenciesAuto, args);
|
|
3759
|
-
if (res !== void 0) return res;
|
|
3760
|
-
const [init, complete, reduce2] = frequencies(...args);
|
|
3761
|
-
let norm2 = 0;
|
|
3762
|
-
return [
|
|
3763
|
-
init,
|
|
3764
|
-
(acc) => {
|
|
3765
|
-
acc = complete(acc);
|
|
3766
|
-
for (let p of acc) {
|
|
3767
|
-
acc.set(p[0], p[1] / norm2);
|
|
3768
|
-
}
|
|
3769
|
-
return acc;
|
|
3770
|
-
},
|
|
3771
|
-
(acc, x) => (norm2++, reduce2(acc, x))
|
|
3772
|
-
];
|
|
3773
|
-
}
|
|
3774
|
-
const cat = () => (rfn) => {
|
|
3775
|
-
const r = rfn[2];
|
|
3776
|
-
return compR(rfn, (acc, x) => {
|
|
3777
|
-
if (x) {
|
|
3778
|
-
for (let y of unreduced(x) || []) {
|
|
3779
|
-
acc = r(acc, y);
|
|
3780
|
-
if (isReduced(acc)) {
|
|
3781
|
-
break;
|
|
3782
|
-
}
|
|
3783
|
-
}
|
|
3784
|
-
}
|
|
3785
|
-
return isReduced(x) ? ensureReduced(acc) : acc;
|
|
3786
|
-
});
|
|
3787
|
-
};
|
|
3788
|
-
function mapcat(fn, src) {
|
|
3789
|
-
return isIterable(src) ? iterator(mapcat(fn), src) : comp(map(fn), cat());
|
|
3790
|
-
}
|
|
3791
|
-
function* repeat(x, n = Infinity) {
|
|
3792
|
-
while (n-- > 0) {
|
|
3793
|
-
yield x;
|
|
3794
|
-
}
|
|
3795
|
-
}
|
|
3796
|
-
const temperature = (colors, minSat = 0.2, coeffs) => {
|
|
3797
|
-
const $colors = ensureArray(colors);
|
|
3798
|
-
const filtered = $colors.filter((x) => x[1] >= minSat);
|
|
3799
|
-
const area = filtered.length / $colors.length;
|
|
3800
|
-
const hues = [
|
|
3801
|
-
...transduce(
|
|
3802
|
-
map((x) => roundTo(x[0], 1 / 12) % 1),
|
|
3803
|
-
normFrequenciesAuto(),
|
|
3804
|
-
filtered
|
|
3805
|
-
)
|
|
3806
|
-
].sort(compareByKey(0));
|
|
3807
|
-
const angles = [
|
|
3808
|
-
...mapcat(([hue, num]) => {
|
|
3809
|
-
num *= 50;
|
|
3810
|
-
return num >= 1 ? repeat(hue * TAU, num) : null;
|
|
3811
|
-
}, hues)
|
|
3812
|
-
];
|
|
3813
|
-
if (!angles.length) {
|
|
3814
|
-
return { hues, meanHue: 0, temp: 0, areaTemp: 0, area: 0 };
|
|
3815
|
-
}
|
|
3816
|
-
const meanHue = circularMean(angles) / TAU;
|
|
3817
|
-
const temp = hueTemperature(meanHue, coeffs);
|
|
3818
|
-
const areaTemp = temp * area;
|
|
3819
|
-
return { hues, meanHue, temp, areaTemp, area };
|
|
3820
|
-
};
|
|
3821
|
-
const DEFAULT_TEMPERATURE_COEFFS = [
|
|
3822
|
-
0.1,
|
|
3823
|
-
0.6,
|
|
3824
|
-
0.72,
|
|
3825
|
-
0.92
|
|
3826
|
-
];
|
|
3827
|
-
const hueTemperature = (hue, [a2, b2, c2, d2] = DEFAULT_TEMPERATURE_COEFFS) => 2 * (hue < 2 / 3 ? smoothStep(b2, a2, hue) : smoothStep(c2, d2, hue)) - 1;
|
|
3828
|
-
const analyzeColors = (img, opts) => {
|
|
3829
|
-
let $img = img.format !== FLOAT_RGBA ? img.as(FLOAT_RGBA) : img;
|
|
3830
|
-
if (opts?.size) $img = __resize($img, opts.size);
|
|
3831
|
-
const imgGray = $img.as(FLOAT_GRAY);
|
|
3832
|
-
const imgHsv = $img.as(FLOAT_HSVA);
|
|
3833
|
-
const colors = __dominantColors($img, opts);
|
|
3834
|
-
const colorAreas = colors.map((x) => x.area);
|
|
3835
|
-
const derived = deriveColorResults(
|
|
3836
|
-
colors.map((x) => x.color),
|
|
3837
|
-
colorAreas,
|
|
3838
|
-
opts?.minSat,
|
|
3839
|
-
opts?.tempCoeffs
|
|
3840
|
-
);
|
|
3841
|
-
const lumImg = defMetric(imgGray.data);
|
|
3842
|
-
return {
|
|
3843
|
-
...derived,
|
|
3844
|
-
img: $img,
|
|
3845
|
-
imgGray,
|
|
3846
|
-
imgHsv,
|
|
3847
|
-
lumImg,
|
|
3848
|
-
temperature: temperature(imgHsv, opts?.minSat, opts?.tempCoeffs),
|
|
3849
|
-
contrastImg: lumImg.max - lumImg.min
|
|
3850
|
-
};
|
|
3851
|
-
};
|
|
3852
|
-
const deriveColorResults = (colors, areas = ones(colors.length), minSat, tempCoeffs) => {
|
|
3853
|
-
const dominantLuma = colors.map((x) => luminanceSrgb(x));
|
|
3854
|
-
const dominantSrgb = colors.map((x) => srgb(x));
|
|
3855
|
-
const dominantHsv = dominantSrgb.map((x) => hsv(x));
|
|
3856
|
-
const dominantOklch = dominantSrgb.map((x) => oklch(x));
|
|
3857
|
-
const dominantCss = dominantSrgb.map((x) => css(x));
|
|
3858
|
-
const hues = dominantHsv.map((x) => x[0]);
|
|
3859
|
-
const sats = dominantHsv.map((x) => x[1]);
|
|
3860
|
-
const lum = defWeightedMetric(dominantLuma, areas);
|
|
3861
|
-
return {
|
|
3862
|
-
css: dominantCss,
|
|
3863
|
-
srgb: dominantSrgb,
|
|
3864
|
-
hsv: dominantHsv,
|
|
3865
|
-
oklch: dominantOklch,
|
|
3866
|
-
hue: defCircularMetric(hues),
|
|
3867
|
-
sat: defWeightedMetric(sats, areas),
|
|
3868
|
-
chroma: defWeightedMetric(
|
|
3869
|
-
dominantOklch.map((x) => x[1]),
|
|
3870
|
-
areas
|
|
3871
|
-
),
|
|
3872
|
-
lum,
|
|
3873
|
-
areas,
|
|
3874
|
-
contrast: lum.max - lum.min,
|
|
3875
|
-
colorContrast: fit(
|
|
3876
|
-
transduce(
|
|
3877
|
-
map((pair) => contrast(...pair)),
|
|
3878
|
-
max(),
|
|
3879
|
-
permutations(dominantSrgb, dominantSrgb)
|
|
3880
|
-
),
|
|
3881
|
-
1,
|
|
3882
|
-
21,
|
|
3883
|
-
0,
|
|
3884
|
-
1
|
|
3885
|
-
),
|
|
3886
|
-
temperature: temperature(dominantHsv, minSat, tempCoeffs)
|
|
3887
|
-
};
|
|
3888
|
-
};
|
|
3889
|
-
const __dominantColors = (img, {
|
|
3890
|
-
dominantFn = dominantColorsKmeans,
|
|
3891
|
-
numColors = 4,
|
|
3892
|
-
prec = 1e-3
|
|
3893
|
-
} = {}) => dominantFn(img, numColors).sort(compareByKey("area", compareNumDesc)).map((x) => (roundN(null, x.color, prec), x));
|
|
3894
|
-
const __resize = ($img, size) => {
|
|
3895
|
-
size = ~~size;
|
|
3896
|
-
let w = $img.width;
|
|
3897
|
-
let h = $img.height;
|
|
3898
|
-
[w, h] = w > h ? [size, ~~Math.max(1, h / w * size)] : [~~Math.max(1, w / h * size), size];
|
|
3899
|
-
return $img.resize(w, h);
|
|
3900
|
-
};
|
|
3901
|
-
/**
|
|
3902
|
-
* Options for extracting colors / evaluating lightness from an image.
|
|
3903
|
-
*
|
|
3904
|
-
* @typedef {Object} ImageAnalysisSettings
|
|
3905
|
-
* @property {number} [numColors=2] - Number of dominant colors to return.
|
|
3906
|
-
* @property {number} [lightnessThreshold=0.5] - Threshold (0.0 - 1.0) used to decide if a color is considered "light".
|
|
3907
|
-
* @property {number} [yFrom=0.0] - Minimum Y (luminance) value (0.0 - 1.0) to include when evaluating lightness.
|
|
3908
|
-
* @property {number} [yTo=1.0] - Maximum Y (luminance) value (0.0 - 1.0) to include when evaluating lightness.
|
|
3909
|
-
* @property {number} [maxSize=320] - Maximum width/height to scale down the image to before analysis, for performance.
|
|
3910
|
-
* @property {number} [alphaThreshold=30] - Threhold (0-255) below which a pixel is considered "transparent" for the purposes of analysis.
|
|
3911
|
-
*
|
|
3912
|
-
* @preserve
|
|
3913
|
-
*/
|
|
3914
|
-
const defaultAnalysisSettings = {
|
|
3915
|
-
numColors: 3,
|
|
3916
|
-
lightnessThreshold: 0.5,
|
|
3917
|
-
yFrom: 0,
|
|
3918
|
-
yTo: 1,
|
|
3919
|
-
maxSize: 320,
|
|
3920
|
-
alphaThreshold: 30
|
|
3921
|
-
};
|
|
3922
|
-
/**
|
|
3923
|
-
* Analyze an image element to determine overall luminance, dominant colors and transparency.
|
|
3924
|
-
*
|
|
3925
|
-
* @param {string} url - URL of the image to check.
|
|
3926
|
-
* @param {ImageAnalysisSettings} [settings] - Optional settings to customize the analysis.
|
|
3927
|
-
*
|
|
3928
|
-
* @returns {{ isDark: boolean, dominantColors: Array<{ color: string, area: number, isDark: boolean }>, isTransparent: boolean } | false}
|
|
3929
|
-
* Returns an object on success:
|
|
3930
|
-
* - isDark: true if the computed mean image luminance is below 0.5.
|
|
3931
|
-
* - dominantColors: an array of up to the requested number of dominant colors. Each entry contains:
|
|
3932
|
-
* - color: CSS color string (as produced by the analyzer).
|
|
3933
|
-
* - area: the relative area (weight) of that color.
|
|
3934
|
-
* - isDark: boolean indicating whether the color's lightness (oklch.l) is < 0.5.
|
|
3935
|
-
* - isTransparent: true if any inspected pixel has alpha < 255.
|
|
3936
|
-
* Returns false if an error occurred during analysis.
|
|
3937
|
-
*
|
|
3938
|
-
* @preserve
|
|
3939
|
-
*/
|
|
3940
|
-
const analyzeImage = (image, rawSettings) => {
|
|
3941
|
-
const settings = { ...defaultAnalysisSettings, ...rawSettings };
|
|
3942
|
-
const { numColors, lightnessThreshold, yFrom, yTo, maxSize } = settings;
|
|
3943
|
-
try {
|
|
3944
|
-
const fileExtension = getFileExtension(image.src);
|
|
3945
|
-
let skipTransparencyCheck = false;
|
|
3946
|
-
if (fileExtension) {
|
|
3947
|
-
skipTransparencyCheck = !["png", "webp", "gif", "tiff", "svg", "avif"].includes(fileExtension);
|
|
3948
|
-
}
|
|
3949
|
-
const imageWidth = image.naturalWidth;
|
|
3950
|
-
const imageHeight = image.naturalHeight;
|
|
3951
|
-
if (!imageWidth || !imageHeight) {
|
|
3952
|
-
return false;
|
|
3953
|
-
}
|
|
3954
|
-
let imageScale = 1;
|
|
3955
|
-
if (imageWidth > maxSize || imageHeight > maxSize) {
|
|
3956
|
-
imageScale = Math.min(maxSize / imageWidth, maxSize / imageHeight);
|
|
3957
|
-
}
|
|
3958
|
-
const imageWidthScaled = Math.floor(imageWidth * imageScale);
|
|
3959
|
-
const imageHeightScaled = Math.floor(imageHeight * imageScale);
|
|
3960
|
-
const srcX = 0;
|
|
3961
|
-
const srcY = Math.floor(yFrom * imageHeight);
|
|
3962
|
-
const srcW = Math.max(1, imageWidth);
|
|
3963
|
-
const srcH = Math.max(1, Math.ceil((yTo - yFrom) * imageHeight));
|
|
3964
|
-
const destW = Math.max(1, imageWidthScaled);
|
|
3965
|
-
const destH = Math.max(1, Math.ceil((yTo - yFrom) * imageHeightScaled));
|
|
3966
|
-
const colorCanvas = document.createElement("canvas");
|
|
3967
|
-
colorCanvas.width = destW;
|
|
3968
|
-
colorCanvas.height = destH;
|
|
3969
|
-
const colorContext = colorCanvas.getContext("2d");
|
|
3970
|
-
colorContext.drawImage(image, srcX, srcY, srcW, srcH, 0, 0, destW, destH);
|
|
3971
|
-
const buffer = floatBufferFromCanvas(colorCanvas, FLOAT_RGBA);
|
|
3972
|
-
const data = analyzeColors(buffer, {
|
|
3973
|
-
numColors,
|
|
3974
|
-
dominantFn: (pixels, num) => dominantColorsKmeans(pixels, num, {
|
|
3975
|
-
filter: (p) => {
|
|
3976
|
-
const { alpha } = srgb(p);
|
|
3977
|
-
return alpha > 0;
|
|
3978
|
-
}
|
|
3979
|
-
}),
|
|
3980
|
-
prec: 0.01
|
|
3981
|
-
});
|
|
3982
|
-
const { lumImg, srgb: srgbData, areas: colorAreas } = data;
|
|
3983
|
-
let transparencyInfo = false;
|
|
3984
|
-
if (!skipTransparencyCheck) {
|
|
3985
|
-
const transparencyCanvas = document.createElement("canvas");
|
|
3986
|
-
transparencyCanvas.width = imageWidthScaled;
|
|
3987
|
-
transparencyCanvas.height = imageHeightScaled;
|
|
3988
|
-
const transparencyContext = transparencyCanvas.getContext("2d", { willReadFrequently: true });
|
|
3989
|
-
transparencyContext.drawImage(image, 0, 0, imageWidth, imageHeight, 0, 0, imageWidthScaled, imageHeightScaled);
|
|
3990
|
-
const imageData = transparencyContext.getImageData(0, 0, imageWidthScaled, imageHeightScaled).data;
|
|
3991
|
-
transparencyInfo = checkTransparency(imageData, imageWidthScaled, imageHeightScaled, settings);
|
|
3992
|
-
}
|
|
3993
|
-
return {
|
|
3994
|
-
isDark: lumImg.mean < lightnessThreshold,
|
|
3995
|
-
isTransparent: skipTransparencyCheck ? false : transparencyInfo?.any,
|
|
3996
|
-
transparencyInfo: skipTransparencyCheck ? null : transparencyInfo,
|
|
3997
|
-
dominantColors: srgbData.map(({ r, g, b: b2 }, index) => ({
|
|
3998
|
-
color: css([r, g, b2]),
|
|
3999
|
-
area: colorAreas?.[index],
|
|
4000
|
-
isDark: isColorDark(r * 255, g * 255, b2 * 255, lightnessThreshold)
|
|
4001
|
-
}))
|
|
4002
|
-
};
|
|
4003
|
-
} catch (error) {
|
|
4004
|
-
console.error("Error analyzing image:", error);
|
|
4005
|
-
return false;
|
|
4006
|
-
}
|
|
4007
|
-
};
|
|
4008
|
-
/**
|
|
4009
|
-
* Check image transparency by analyzing pixel alpha values.
|
|
4010
|
-
*
|
|
4011
|
-
* @param {Uint8ClampedArray} imageData - The image data array containing RGBA values.
|
|
4012
|
-
* @param {number} w - The width of the image.
|
|
4013
|
-
* @param {number} h - The height of the image.
|
|
4014
|
-
* @param {ImageAnalysisSettings} [settings] - Optional settings to customize the transparency check.
|
|
4015
|
-
*
|
|
4016
|
-
* @return {{ any: boolean, left: boolean, right: boolean, top: boolean, bottom: boolean }} An object indicating transparency on different sides of the image.
|
|
4017
|
-
*
|
|
4018
|
-
* @preserve
|
|
4019
|
-
*/
|
|
4020
|
-
const checkTransparency = (imageData, w, h, settings = {}) => {
|
|
4021
|
-
const { alphaThreshold } = { ...defaultAnalysisSettings, ...settings };
|
|
4022
|
-
const transparency = {
|
|
4023
|
-
any: true,
|
|
4024
|
-
left: true,
|
|
4025
|
-
right: true,
|
|
4026
|
-
top: true,
|
|
4027
|
-
bottom: true
|
|
4028
|
-
};
|
|
4029
|
-
let counts = {
|
|
4030
|
-
any: 0,
|
|
4031
|
-
left: 0,
|
|
4032
|
-
right: 0,
|
|
4033
|
-
top: 0,
|
|
4034
|
-
bottom: 0
|
|
4035
|
-
};
|
|
4036
|
-
const perimeterThresholdW = Math.floor(0.15 * w);
|
|
4037
|
-
const perimeterThresholdH = Math.floor((h > 100 ? 0.05 : 0.5) * h);
|
|
4038
|
-
const innerThreshold = Math.floor(w * h * 1e-3);
|
|
4039
|
-
if (w > 0 && h > 0) {
|
|
4040
|
-
for (let x = 0; x < w; x++) {
|
|
4041
|
-
const idx = (0 * w + x) * 4 + 3;
|
|
4042
|
-
if (imageData[idx] > alphaThreshold) {
|
|
4043
|
-
counts.top++;
|
|
4044
|
-
if (counts.top >= perimeterThresholdW) {
|
|
4045
|
-
transparency.top = false;
|
|
4046
|
-
break;
|
|
4047
|
-
}
|
|
4048
|
-
}
|
|
4049
|
-
}
|
|
4050
|
-
for (let x = 0; x < w; x++) {
|
|
4051
|
-
const idx = ((h - 1) * w + x) * 4 + 3;
|
|
4052
|
-
if (imageData[idx] > alphaThreshold) {
|
|
4053
|
-
counts.bottom++;
|
|
4054
|
-
if (counts.bottom >= perimeterThresholdW) {
|
|
4055
|
-
transparency.bottom = false;
|
|
4056
|
-
break;
|
|
4057
|
-
}
|
|
4058
|
-
}
|
|
4059
|
-
}
|
|
4060
|
-
for (let y = 0; y < h; y++) {
|
|
4061
|
-
const idx = (y * w + 0) * 4 + 3;
|
|
4062
|
-
if (imageData[idx] > alphaThreshold) {
|
|
4063
|
-
counts.left++;
|
|
4064
|
-
if (counts.left >= perimeterThresholdH) {
|
|
4065
|
-
transparency.left = false;
|
|
4066
|
-
break;
|
|
4067
|
-
}
|
|
4068
|
-
}
|
|
4069
|
-
}
|
|
4070
|
-
for (let y = 0; y < h; y++) {
|
|
4071
|
-
const idx = (y * w + (w - 1)) * 4 + 3;
|
|
4072
|
-
if (imageData[idx] > alphaThreshold) {
|
|
4073
|
-
counts.right++;
|
|
4074
|
-
if (counts.right >= perimeterThresholdH) {
|
|
4075
|
-
transparency.right = false;
|
|
4076
|
-
break;
|
|
4077
|
-
}
|
|
4078
|
-
}
|
|
4079
|
-
}
|
|
4080
|
-
if (!transparency.top && !transparency.bottom && !transparency.left && !transparency.right) {
|
|
4081
|
-
for (let i = 3; i < imageData.length; i += 4) {
|
|
4082
|
-
if (imageData[i] > alphaThreshold) {
|
|
4083
|
-
counts.any++;
|
|
4084
|
-
if (counts.any >= innerThreshold) {
|
|
4085
|
-
transparency.any = false;
|
|
4086
|
-
break;
|
|
4087
|
-
}
|
|
4088
|
-
}
|
|
4089
|
-
}
|
|
4090
|
-
} else {
|
|
4091
|
-
transparency.any = true;
|
|
4092
|
-
}
|
|
4093
|
-
}
|
|
4094
|
-
return transparency;
|
|
4095
|
-
};
|
|
4096
|
-
/**
|
|
4097
|
-
* Get file extension from a URL string.
|
|
4098
|
-
*
|
|
4099
|
-
* @param {string} input - The URL string to extract the file extension from.
|
|
4100
|
-
*
|
|
4101
|
-
* @returns {string|null} The file extension in lowercase, or null if not found.
|
|
4102
|
-
*
|
|
4103
|
-
* @example
|
|
4104
|
-
* getFileExtension('https://example.com/image.png'); // 'png'
|
|
4105
|
-
* getFileExtension('https://example.com/archive.tar.gz'); // 'gz'
|
|
4106
|
-
* getFileExtension('https://example.com/no-extension'); // null
|
|
4107
|
-
*
|
|
4108
|
-
* @preserve
|
|
4109
|
-
*/
|
|
4110
|
-
const getFileExtension = (input) => {
|
|
4111
|
-
const url = new URL(input);
|
|
4112
|
-
const pathname = url.pathname;
|
|
4113
|
-
const match = pathname.match(/\.([a-zA-Z0-9]+)(?:\?|#|$)/);
|
|
4114
|
-
return match ? match[1].toLowerCase() : null;
|
|
4115
|
-
};
|
|
4116
|
-
/**
|
|
4117
|
-
* Determine if a color is considered "dark" based on its RGB values and a lightness threshold.
|
|
4118
|
-
*
|
|
4119
|
-
* @param {number} r - Red component (0-255).
|
|
4120
|
-
* @param {number} g - Green component (0-255).
|
|
4121
|
-
* @param {number} b - Blue component (0-255).
|
|
4122
|
-
* @param {number} [threshold=0.5] - Lightness threshold (0.0 - 1.0) below which the color is considered dark.
|
|
4123
|
-
*
|
|
4124
|
-
* @returns {boolean} True if the color is dark, false otherwise.
|
|
4125
|
-
*
|
|
4126
|
-
* @example
|
|
4127
|
-
* isColorDark(0, 0, 0); // true (black)
|
|
4128
|
-
* isColorDark(255, 255, 255); // false (white)
|
|
4129
|
-
* isColorDark(100, 100, 100, 0.4); // false (gray with higher threshold)
|
|
4130
|
-
*
|
|
4131
|
-
* @preserve
|
|
4132
|
-
*/
|
|
4133
|
-
const isColorDark = (r, g, b2, threshold = 0.5) => {
|
|
4134
|
-
const luminance = (0.299 * r + 0.587 * g + 0.114 * b2) / 255;
|
|
4135
|
-
return luminance < threshold;
|
|
4136
|
-
};
|
|
1
|
+
import "./hash.js";
|
|
2
|
+
import { a, b, d, c, g, i } from "../general-Ck8IV7xJ.js";
|
|
4137
3
|
export {
|
|
4138
|
-
analyzeImage,
|
|
4139
|
-
|
|
4140
|
-
|
|
4141
|
-
|
|
4
|
+
a as analyzeImage,
|
|
5
|
+
b as analyzeImageAsync,
|
|
6
|
+
d as analyzeImageData,
|
|
7
|
+
c as checkTransparency,
|
|
8
|
+
g as getFileExtension,
|
|
9
|
+
i as isColorDark
|
|
4142
10
|
};
|