imagescript 3.1.0 → 3.2.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/README.md +12 -4
- package/dist/animation.d.ts +92 -7
- package/dist/animation.js +50 -20
- package/dist/codecs/exif.js +62 -0
- package/dist/codecs/gif.js +43 -27
- package/dist/codecs/jpeg.js +13 -1
- package/dist/codecs/png.js +85 -21
- package/dist/codecs/quantize.js +2 -2
- package/dist/codecs/tga.js +47 -4
- package/dist/codecs/vp8l.js +27 -30
- package/dist/codecs/webp.js +23 -10
- package/dist/frame.d.ts +30 -2
- package/dist/frame.js +20 -9
- package/dist/gif.d.ts +10 -7
- package/dist/gif.js +7 -5
- package/dist/image-type.d.ts +1 -0
- package/dist/image-type.js +1 -0
- package/dist/image.d.ts +231 -31
- package/dist/image.js +118 -53
- package/dist/index.d.ts +14 -4
- package/dist/index.js +6 -4
- package/dist/metadata.d.ts +35 -0
- package/dist/metadata.js +43 -0
- package/dist/render/svg.js +39 -21
- package/dist/util/blur.js +88 -0
- package/dist/util/optimize.js +264 -0
- package/dist/util/options.js +3 -0
- package/dist/util/resample.js +244 -63
- package/dist/util/utf8.js +4 -51
- package/dist/version.js +1 -1
- package/package.json +9 -2
- package/dist/codecs/crc.d.ts +0 -9
- package/dist/codecs/exif.d.ts +0 -11
- package/dist/codecs/gif.d.ts +0 -44
- package/dist/codecs/jpeg.d.ts +0 -35
- package/dist/codecs/png.d.ts +0 -97
- package/dist/codecs/quantize.d.ts +0 -25
- package/dist/codecs/tga.d.ts +0 -16
- package/dist/codecs/tiff.d.ts +0 -6
- package/dist/codecs/vp8-tables.d.ts +0 -10
- package/dist/codecs/vp8.d.ts +0 -8
- package/dist/codecs/vp8l.d.ts +0 -62
- package/dist/codecs/webp.d.ts +0 -67
- package/dist/codecs/zlib.d.ts +0 -22
- package/dist/render/font.d.ts +0 -92
- package/dist/render/hinting.d.ts +0 -110
- package/dist/render/svg.d.ts +0 -11
- package/dist/render/text.d.ts +0 -63
- package/dist/util/blur.d.ts +0 -13
- package/dist/util/resample.d.ts +0 -12
- package/dist/util/utf8.d.ts +0 -5
- package/dist/version.d.ts +0 -1
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
const ALPHA = new Int32Array(new Uint8Array([0, 0, 0, 255]).buffer)[0];
|
|
2
|
+
const ALPHA_COST = 4 / 3;
|
|
3
|
+
export function optimize(frames, width, height, { replace, even, alpha, palette, cover }) {
|
|
4
|
+
const size = width * height * 4;
|
|
5
|
+
const canvas = new Uint8Array(size), canvas32 = new Int32Array(canvas.buffer);
|
|
6
|
+
const shown = new Uint8Array(size), shown32 = new Int32Array(shown.buffer);
|
|
7
|
+
const output = [];
|
|
8
|
+
const state = { canvas32, shown32, width, replace };
|
|
9
|
+
let opaque = true, denseTotal = 0, chosenTotal = 0;
|
|
10
|
+
const add = (duration) => {
|
|
11
|
+
let changed = bounds(state, { x: 0, y: 0, width, height });
|
|
12
|
+
if (!changed) {
|
|
13
|
+
if (output.length)
|
|
14
|
+
output[output.length - 1].duration += duration;
|
|
15
|
+
else {
|
|
16
|
+
output.push(empty(duration));
|
|
17
|
+
opaque = false;
|
|
18
|
+
}
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
if (even)
|
|
22
|
+
changed = evenArea(changed);
|
|
23
|
+
let area = sparse(state, changed);
|
|
24
|
+
let blend = true;
|
|
25
|
+
if (area.unblendable && replace)
|
|
26
|
+
blend = false;
|
|
27
|
+
else if (area.unblendable) {
|
|
28
|
+
const last = output[output.length - 1];
|
|
29
|
+
grow(last, union(last, area.unblendable));
|
|
30
|
+
last.dispose = true;
|
|
31
|
+
clear(shown, width, last);
|
|
32
|
+
changed = bounds(state, { x: 0, y: 0, width, height });
|
|
33
|
+
if (!changed)
|
|
34
|
+
return void output.push(empty(duration));
|
|
35
|
+
if (even)
|
|
36
|
+
changed = evenArea(changed);
|
|
37
|
+
area = sparse(state, changed);
|
|
38
|
+
}
|
|
39
|
+
const { x, y, width: w, height: h } = changed;
|
|
40
|
+
const pixels = area.pixels;
|
|
41
|
+
if (!output.length && (w !== width || h !== height))
|
|
42
|
+
opaque = false;
|
|
43
|
+
if (!area.denseOpaque)
|
|
44
|
+
opaque = false;
|
|
45
|
+
const sparseCost = alpha === 'frame' && area.denseOpaque ? area.sparseChanges * ALPHA_COST : area.sparseChanges;
|
|
46
|
+
const dense = !blend || area.denseChanges < sparseCost
|
|
47
|
+
|| (palette !== undefined && colors(new Int32Array(pixels.buffer), w, { x: 0, y: 0, width: w, height: h }, palette + 1) > palette
|
|
48
|
+
&& colors(canvas32, width, changed, palette + 1) <= palette);
|
|
49
|
+
denseTotal += area.denseChanges;
|
|
50
|
+
chosenTotal += dense ? area.denseChanges : area.sparseChanges;
|
|
51
|
+
if (dense) {
|
|
52
|
+
for (let row = 0; row < h; row++)
|
|
53
|
+
pixels.set(canvas.subarray(((y + row) * width + x) * 4, ((y + row) * width + x + w) * 4), row * w * 4);
|
|
54
|
+
if (replace)
|
|
55
|
+
blend = false;
|
|
56
|
+
}
|
|
57
|
+
for (let row = 0; row < h; row++) {
|
|
58
|
+
const start = ((y + row) * width + x) * 4;
|
|
59
|
+
shown.set(canvas.subarray(start, start + w * 4), start);
|
|
60
|
+
}
|
|
61
|
+
output.push({ x, y, width: w, height: h, duration, dispose: false, blend, pixels });
|
|
62
|
+
};
|
|
63
|
+
let cleared = { x: 0, y: 0, width, height };
|
|
64
|
+
for (const f of frames) {
|
|
65
|
+
const saved = f.dispose === 2 ? canvas.slice() : null;
|
|
66
|
+
const area = clip(f, width, height);
|
|
67
|
+
if (cleared && contains(cleared, area))
|
|
68
|
+
copy(canvas, width, f, area);
|
|
69
|
+
else
|
|
70
|
+
draw(canvas, width, height, f);
|
|
71
|
+
cleared = null;
|
|
72
|
+
add(f.duration);
|
|
73
|
+
if (f.dispose === 1) {
|
|
74
|
+
clear(canvas, width, area);
|
|
75
|
+
cleared = area;
|
|
76
|
+
}
|
|
77
|
+
else if (saved)
|
|
78
|
+
canvas.set(saved);
|
|
79
|
+
}
|
|
80
|
+
if (typeof alpha === 'function' && opaque && output.some(f => f.blend) && denseTotal < chosenTotal * alpha(output)) {
|
|
81
|
+
shown.fill(0);
|
|
82
|
+
for (const f of output) {
|
|
83
|
+
const pixels32 = new Int32Array(f.pixels.buffer, f.pixels.byteOffset, f.width * f.height);
|
|
84
|
+
for (let row = 0, k = 0; row < f.height; row++, k += f.width) {
|
|
85
|
+
const start = (f.y + row) * width + f.x;
|
|
86
|
+
if (!f.blend)
|
|
87
|
+
shown32.set(pixels32.subarray(k, k + f.width), start);
|
|
88
|
+
else
|
|
89
|
+
for (let i = k, p = start, end = k + f.width; i < end; i++, p++) {
|
|
90
|
+
if ((pixels32[i] & ALPHA) === 0)
|
|
91
|
+
pixels32[i] = shown32[p];
|
|
92
|
+
else
|
|
93
|
+
shown32[p] = pixels32[i];
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
f.blend = false;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
if (cover && output.length)
|
|
100
|
+
grow(output[0], { x: 0, y: 0, width, height });
|
|
101
|
+
return output;
|
|
102
|
+
}
|
|
103
|
+
function colors(image32, width, { x, y, width: w, height: h }, limit) {
|
|
104
|
+
const seen = new Set();
|
|
105
|
+
for (let row = y; row < y + h; row++) {
|
|
106
|
+
let previous;
|
|
107
|
+
for (let p = row * width + x, end = p + w; p < end; p++) {
|
|
108
|
+
const value = image32[p];
|
|
109
|
+
if (value === previous)
|
|
110
|
+
continue;
|
|
111
|
+
previous = value;
|
|
112
|
+
seen.add(value);
|
|
113
|
+
if (seen.size >= limit)
|
|
114
|
+
return seen.size;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return seen.size;
|
|
118
|
+
}
|
|
119
|
+
const empty = (duration) => ({ x: 0, y: 0, width: 1, height: 1, duration, dispose: false, blend: true, pixels: new Uint8Array(4) });
|
|
120
|
+
function clip(r, width, height) {
|
|
121
|
+
const x = Math.max(0, r.x), y = Math.max(0, r.y);
|
|
122
|
+
return { x, y, width: Math.max(0, Math.min(width, r.x + r.width) - x), height: Math.max(0, Math.min(height, r.y + r.height) - y) };
|
|
123
|
+
}
|
|
124
|
+
function contains(a, b) {
|
|
125
|
+
return b.x >= a.x && b.y >= a.y && b.x + b.width <= a.x + a.width && b.y + b.height <= a.y + a.height;
|
|
126
|
+
}
|
|
127
|
+
function union(a, b) {
|
|
128
|
+
const x = Math.min(a.x, b.x), y = Math.min(a.y, b.y);
|
|
129
|
+
return { x, y, width: Math.max(a.x + a.width, b.x + b.width) - x, height: Math.max(a.y + a.height, b.y + b.height) - y };
|
|
130
|
+
}
|
|
131
|
+
function evenArea({ x, y, width, height }) {
|
|
132
|
+
return { x: x & ~1, y: y & ~1, width: width + (x & 1), height: height + (y & 1) };
|
|
133
|
+
}
|
|
134
|
+
function sparse({ canvas32, shown32, width, replace }, { x, y, width: w, height: h }) {
|
|
135
|
+
const pixels = new Uint8Array(w * h * 4), pixels32 = new Int32Array(pixels.buffer);
|
|
136
|
+
let sparseChanges = 0, denseChanges = 0, lastSparse = -1, lastDense = -1;
|
|
137
|
+
let left = w, right = -1, top = h, bottom = -1, translucent = 0;
|
|
138
|
+
for (let row = 0, k = 0; row < h; row++) {
|
|
139
|
+
const start = (y + row) * width + x;
|
|
140
|
+
for (let i = 0, p = start; i < w; i++, p++, k++) {
|
|
141
|
+
const value = canvas32[p], before = shown32[p];
|
|
142
|
+
if (value === before || ((value | before) & ALPHA) === 0) {
|
|
143
|
+
if (lastSparse !== 0)
|
|
144
|
+
sparseChanges++;
|
|
145
|
+
lastSparse = 0;
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
pixels32[k] = value;
|
|
149
|
+
if (value !== lastSparse)
|
|
150
|
+
sparseChanges++;
|
|
151
|
+
lastSparse = value;
|
|
152
|
+
if ((value & ALPHA) !== ALPHA && (replace || (before & ALPHA) !== 0)) {
|
|
153
|
+
if (i < left)
|
|
154
|
+
left = i;
|
|
155
|
+
if (i > right)
|
|
156
|
+
right = i;
|
|
157
|
+
if (row < top)
|
|
158
|
+
top = row;
|
|
159
|
+
bottom = row;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
if (value !== lastDense) {
|
|
163
|
+
denseChanges++;
|
|
164
|
+
translucent |= ~value & ALPHA;
|
|
165
|
+
}
|
|
166
|
+
lastDense = value;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
const unblendable = right < 0 ? null : { x: x + left, y: y + top, width: right - left + 1, height: bottom - top + 1 };
|
|
170
|
+
return { pixels, sparseChanges, denseChanges, unblendable, denseOpaque: translucent === 0 };
|
|
171
|
+
}
|
|
172
|
+
function bounds({ canvas32, shown32, width }, area) {
|
|
173
|
+
const x0 = area.x, x1 = area.x + area.width, y0 = area.y, y1 = area.y + area.height;
|
|
174
|
+
const test = (p) => {
|
|
175
|
+
const c = canvas32[p], s = shown32[p];
|
|
176
|
+
return c !== s && ((c | s) & ALPHA) !== 0;
|
|
177
|
+
};
|
|
178
|
+
const rowHas = (y, from, to) => {
|
|
179
|
+
for (let x = from, p = y * width + from; x < to; x++, p++)
|
|
180
|
+
if (test(p))
|
|
181
|
+
return x;
|
|
182
|
+
return -1;
|
|
183
|
+
};
|
|
184
|
+
let top = y0, first = -1;
|
|
185
|
+
for (; top < y1; top++)
|
|
186
|
+
if ((first = rowHas(top, x0, x1)) >= 0)
|
|
187
|
+
break;
|
|
188
|
+
if (top === y1)
|
|
189
|
+
return null;
|
|
190
|
+
let bottom = y1 - 1;
|
|
191
|
+
while (bottom > top && rowHas(bottom, x0, x1) < 0)
|
|
192
|
+
bottom--;
|
|
193
|
+
let left = first, right = first;
|
|
194
|
+
for (let y = top; y <= bottom; y++) {
|
|
195
|
+
if (left > x0) {
|
|
196
|
+
const x = rowHas(y, x0, left);
|
|
197
|
+
if (x >= 0)
|
|
198
|
+
left = x;
|
|
199
|
+
}
|
|
200
|
+
for (let x = x1 - 1, p = y * width + x; x > right; x--, p--)
|
|
201
|
+
if (test(p)) {
|
|
202
|
+
right = x;
|
|
203
|
+
break;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
return { x: left, y: top, width: right - left + 1, height: bottom - top + 1 };
|
|
207
|
+
}
|
|
208
|
+
function draw(canvas, width, height, f) {
|
|
209
|
+
const { x: x0, y: y0, width: w, height: h } = clip(f, width, height);
|
|
210
|
+
const pixels = f.pixels.byteOffset % 4 ? f.pixels.slice() : f.pixels;
|
|
211
|
+
const src = new Int32Array(pixels.buffer, pixels.byteOffset, f.width * f.height);
|
|
212
|
+
const dst = new Int32Array(canvas.buffer, canvas.byteOffset, width * height);
|
|
213
|
+
for (let y = y0; y < y0 + h; y++)
|
|
214
|
+
for (let x = x0, s = (y - f.y) * f.width + x - f.x, d = y * width + x; x < x0 + w; x++, s++, d++) {
|
|
215
|
+
let n = 0;
|
|
216
|
+
while (n < x0 + w - x && (src[s + n] & ALPHA) === ALPHA)
|
|
217
|
+
n++;
|
|
218
|
+
if (n) {
|
|
219
|
+
if (n >= 16)
|
|
220
|
+
dst.set(src.subarray(s, s + n), d);
|
|
221
|
+
else
|
|
222
|
+
for (let i = 0; i < n; i++)
|
|
223
|
+
dst[d + i] = src[s + i];
|
|
224
|
+
x += n - 1;
|
|
225
|
+
s += n - 1;
|
|
226
|
+
d += n - 1;
|
|
227
|
+
continue;
|
|
228
|
+
}
|
|
229
|
+
const value = src[s], alpha = value & ALPHA;
|
|
230
|
+
if (alpha === 0)
|
|
231
|
+
continue;
|
|
232
|
+
if (alpha === ALPHA || (dst[d] & ALPHA) === 0)
|
|
233
|
+
dst[d] = value;
|
|
234
|
+
else {
|
|
235
|
+
const sa = pixels[s * 4 + 3], da = canvas[d * 4 + 3];
|
|
236
|
+
const u = sa * 255, v = (255 - sa) * da, al = u + v;
|
|
237
|
+
for (let c = 0; c < 3; c++)
|
|
238
|
+
canvas[d * 4 + c] = (pixels[s * 4 + c] * u + canvas[d * 4 + c] * v) / al | 0;
|
|
239
|
+
canvas[d * 4 + 3] = al / 255 | 0;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
function copy(canvas, width, f, { x, y, width: w, height: h }) {
|
|
244
|
+
const canvas32 = new Int32Array(canvas.buffer, canvas.byteOffset, width * (y + h));
|
|
245
|
+
for (let row = y; row < y + h; row++) {
|
|
246
|
+
const s = ((row - f.y) * f.width + x - f.x) * 4, d = row * width + x;
|
|
247
|
+
canvas.set(f.pixels.subarray(s, s + w * 4), d * 4);
|
|
248
|
+
for (let p = d; p < d + w; p++)
|
|
249
|
+
if ((canvas32[p] & ALPHA) === 0)
|
|
250
|
+
canvas32[p] = 0;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
function clear(canvas, width, r) {
|
|
254
|
+
for (let y = r.y; y < r.y + r.height; y++)
|
|
255
|
+
canvas.fill(0, (y * width + r.x) * 4, (y * width + r.x + r.width) * 4);
|
|
256
|
+
}
|
|
257
|
+
function grow(frame, area) {
|
|
258
|
+
if (area.x === frame.x && area.y === frame.y && area.width === frame.width && area.height === frame.height)
|
|
259
|
+
return;
|
|
260
|
+
const pixels = new Uint8Array(area.width * area.height * 4);
|
|
261
|
+
for (let row = 0; row < frame.height; row++)
|
|
262
|
+
pixels.set(frame.pixels.subarray(row * frame.width * 4, (row + 1) * frame.width * 4), ((frame.y - area.y + row) * area.width + frame.x - area.x) * 4);
|
|
263
|
+
Object.assign(frame, area, { pixels });
|
|
264
|
+
}
|
package/dist/util/resample.js
CHANGED
|
@@ -12,88 +12,269 @@ export const CUBIC = {
|
|
|
12
12
|
return 0;
|
|
13
13
|
}
|
|
14
14
|
};
|
|
15
|
-
|
|
15
|
+
const BITS = 14;
|
|
16
|
+
const ONE = 1 << BITS;
|
|
17
|
+
function coefficients(inSize, outSize, filter, bits) {
|
|
16
18
|
const scale = inSize / outSize;
|
|
17
19
|
const filterScale = Math.max(1, scale);
|
|
18
20
|
const support = filter.support * filterScale;
|
|
19
|
-
const
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
const weights = new Float64Array(outSize * size);
|
|
21
|
+
const one = 1 << bits;
|
|
22
|
+
const mins = new Int32Array(outSize), maxs = new Int32Array(outSize);
|
|
23
|
+
let taps = 0;
|
|
23
24
|
for (let i = 0; i < outSize; i++) {
|
|
24
25
|
const center = (i + 0.5) * scale;
|
|
25
|
-
|
|
26
|
-
|
|
26
|
+
mins[i] = Math.max(0, Math.floor(center - support + 0.5));
|
|
27
|
+
maxs[i] = Math.min(inSize, Math.floor(center + support + 0.5));
|
|
28
|
+
taps = Math.max(taps, maxs[i] - mins[i]);
|
|
29
|
+
}
|
|
30
|
+
const start = new Int32Array(outSize);
|
|
31
|
+
const weights = new Int32Array(outSize * taps);
|
|
32
|
+
const w = new Float64Array(taps);
|
|
33
|
+
for (let i = 0; i < outSize; i++) {
|
|
34
|
+
const center = (i + 0.5) * scale, min = mins[i], n = maxs[i] - min;
|
|
27
35
|
let total = 0;
|
|
28
|
-
for (let
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
36
|
+
for (let k = 0; k < n; k++)
|
|
37
|
+
total += w[k] = filter.weight((min + k - center + 0.5) / filterScale);
|
|
38
|
+
const shift = Math.max(0, min + taps - inSize), o = i * taps + shift;
|
|
39
|
+
start[i] = min - shift;
|
|
40
|
+
let sum = 0, largest = 0;
|
|
41
|
+
for (let k = 0; k < n; k++) {
|
|
42
|
+
sum += weights[o + k] = Math.round(total ? w[k] / total * one : 0);
|
|
43
|
+
if (Math.abs(w[k]) > Math.abs(w[largest]))
|
|
44
|
+
largest = k;
|
|
32
45
|
}
|
|
33
|
-
if (
|
|
34
|
-
|
|
35
|
-
weights[i * size + k] /= total;
|
|
36
|
-
start[i] = min;
|
|
37
|
-
count[i] = max - min;
|
|
46
|
+
if (n)
|
|
47
|
+
weights[o + largest] += one - sum;
|
|
38
48
|
}
|
|
39
|
-
return { start,
|
|
49
|
+
return { start, weights, taps };
|
|
40
50
|
}
|
|
51
|
+
const littleEndian = new Uint8Array(new Uint32Array([1]).buffer)[0] === 1;
|
|
41
52
|
export function resample(src, width, height, outWidth, outHeight, filter, out) {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
53
|
+
if (littleEndian && filter.support <= 1 && resampleOpaque(src, width, height, outWidth, outHeight, filter, out))
|
|
54
|
+
return;
|
|
55
|
+
resamplePremultiplied(src, width, height, outWidth, outHeight, filter, out);
|
|
56
|
+
}
|
|
57
|
+
function resampleOpaque(src, width, height, outWidth, outHeight, filter, out) {
|
|
58
|
+
const pixels = new Int32Array(src.buffer, src.byteOffset, width * height);
|
|
59
|
+
let all = -1;
|
|
60
|
+
for (let x = 0, last = (height - 1) * width; x < width; x++)
|
|
61
|
+
all &= pixels[x] & pixels[last + x];
|
|
62
|
+
if (all >>> 24 !== 255)
|
|
63
|
+
return false;
|
|
64
|
+
const lanes = new Int32Array(width * outHeight * 2);
|
|
65
|
+
if (outHeight === height) {
|
|
66
|
+
for (let i = 0, o = 0; i < pixels.length; i++, o += 2) {
|
|
67
|
+
const p = pixels[i];
|
|
68
|
+
all &= p;
|
|
69
|
+
lanes[o] = (p & 0xff00ff) << 8;
|
|
70
|
+
lanes[o + 1] = (p & 0xff00) | 0;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
let coefficientsV = coefficients(height, outHeight, filter, 8);
|
|
75
|
+
const swar = coefficientsV.taps <= 4;
|
|
76
|
+
if (!swar)
|
|
77
|
+
coefficientsV = coefficients(height, outHeight, filter, BITS);
|
|
78
|
+
const { start, weights, taps } = coefficientsV;
|
|
79
|
+
for (let y = 0, o = 0; y < outHeight; y++) {
|
|
80
|
+
const w = y * taps, r0 = start[y] * width;
|
|
81
|
+
if (swar && taps === 4) {
|
|
82
|
+
const w0 = weights[w], w1 = weights[w + 1], w2 = weights[w + 2], w3 = weights[w + 3];
|
|
83
|
+
const r1 = r0 + width, r2 = r1 + width, r3 = r2 + width;
|
|
84
|
+
for (let x = 0; x < width; x++, o += 2) {
|
|
85
|
+
const p0 = pixels[r0 + x], p1 = pixels[r1 + x], p2 = pixels[r2 + x], p3 = pixels[r3 + x];
|
|
86
|
+
all &= p0 & p1 & p2 & p3;
|
|
87
|
+
lanes[o] = Math.imul(p0 & 0xff00ff, w0) + Math.imul(p1 & 0xff00ff, w1) + Math.imul(p2 & 0xff00ff, w2) + Math.imul(p3 & 0xff00ff, w3);
|
|
88
|
+
lanes[o + 1] = (p0 >> 8 & 255) * w0 + (p1 >> 8 & 255) * w1 + (p2 >> 8 & 255) * w2 + (p3 >> 8 & 255) * w3;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
else if (swar && taps === 3) {
|
|
92
|
+
const w0 = weights[w], w1 = weights[w + 1], w2 = weights[w + 2], r1 = r0 + width, r2 = r1 + width;
|
|
93
|
+
for (let x = 0; x < width; x++, o += 2) {
|
|
94
|
+
const p0 = pixels[r0 + x], p1 = pixels[r1 + x], p2 = pixels[r2 + x];
|
|
95
|
+
all &= p0 & p1 & p2;
|
|
96
|
+
lanes[o] = Math.imul(p0 & 0xff00ff, w0) + Math.imul(p1 & 0xff00ff, w1) + Math.imul(p2 & 0xff00ff, w2);
|
|
97
|
+
lanes[o + 1] = (p0 >> 8 & 255) * w0 + (p1 >> 8 & 255) * w1 + (p2 >> 8 & 255) * w2;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
else if (swar && taps === 2) {
|
|
101
|
+
const w0 = weights[w], w1 = weights[w + 1], r1 = r0 + width;
|
|
102
|
+
for (let x = 0; x < width; x++, o += 2) {
|
|
103
|
+
const p0 = pixels[r0 + x], p1 = pixels[r1 + x];
|
|
104
|
+
all &= p0 & p1;
|
|
105
|
+
lanes[o] = Math.imul(p0 & 0xff00ff, w0) + Math.imul(p1 & 0xff00ff, w1);
|
|
106
|
+
lanes[o + 1] = (p0 >> 8 & 255) * w0 + (p1 >> 8 & 255) * w1;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
else if (swar) {
|
|
110
|
+
for (let x = 0; x < width; x++, o += 2) {
|
|
111
|
+
let rb = 0, g = 0;
|
|
112
|
+
for (let k = 0, s = r0 + x; k < taps; k++, s += width) {
|
|
113
|
+
const p = pixels[s], wk = weights[w + k];
|
|
114
|
+
all &= p;
|
|
115
|
+
rb += Math.imul(p & 0xff00ff, wk);
|
|
116
|
+
g += (p >> 8 & 255) * wk;
|
|
117
|
+
}
|
|
118
|
+
lanes[o] = rb;
|
|
119
|
+
lanes[o + 1] = g;
|
|
56
120
|
}
|
|
57
121
|
}
|
|
58
122
|
else {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
123
|
+
for (let x = 0; x < width; x++, o += 2) {
|
|
124
|
+
let r = 0, g = 0, b = 0, k = 0, s = r0 + x;
|
|
125
|
+
for (; k + 1 < taps; k += 2, s += width * 2) {
|
|
126
|
+
const p = pixels[s], q = pixels[s + width], w0 = weights[w + k], w1 = weights[w + k + 1];
|
|
127
|
+
all &= p & q;
|
|
128
|
+
r += (p & 255) * w0 + (q & 255) * w1;
|
|
129
|
+
g += (p >> 8 & 255) * w0 + (q >> 8 & 255) * w1;
|
|
130
|
+
b += (p >> 16 & 255) * w0 + (q >> 16 & 255) * w1;
|
|
131
|
+
}
|
|
132
|
+
if (k < taps) {
|
|
133
|
+
const p = pixels[s], w0 = weights[w + k];
|
|
134
|
+
all &= p;
|
|
135
|
+
r += (p & 255) * w0;
|
|
136
|
+
g += (p >> 8 & 255) * w0;
|
|
137
|
+
b += (p >> 16 & 255) * w0;
|
|
138
|
+
}
|
|
139
|
+
lanes[o] = (r + 32 >> 6) | (b + 32 >> 6) << 16;
|
|
140
|
+
lanes[o + 1] = g + 32 >> 6;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
if (all >>> 24 !== 255)
|
|
146
|
+
return false;
|
|
147
|
+
const result = new Int32Array(out.buffer, out.byteOffset, outWidth * outHeight);
|
|
148
|
+
if (outWidth === width) {
|
|
149
|
+
for (let i = 0, o = 0; i < result.length; i++, o += 2) {
|
|
150
|
+
const rb = lanes[o], g = lanes[o + 1];
|
|
151
|
+
result[i] = ((rb & 0xffff) + 128 >> 8) | (g + 128 >> 8) << 8 | ((rb >>> 16) + 128 >> 8) << 16 | 0xff000000;
|
|
152
|
+
}
|
|
153
|
+
return true;
|
|
154
|
+
}
|
|
155
|
+
const R = 1 << 7 + BITS, S = 8 + BITS;
|
|
156
|
+
const { start, weights, taps } = coefficients(width, outWidth, filter, BITS);
|
|
157
|
+
for (let y = 0, o = 0; y < outHeight; y++) {
|
|
158
|
+
const row = y * width * 2;
|
|
159
|
+
if (taps === 4) {
|
|
160
|
+
for (let x = 0; x < outWidth; x++, o++) {
|
|
161
|
+
const s = row + start[x] * 2, w = x * 4;
|
|
162
|
+
const a0 = lanes[s], a1 = lanes[s + 2], a2 = lanes[s + 4], a3 = lanes[s + 6];
|
|
163
|
+
const w0 = weights[w], w1 = weights[w + 1], w2 = weights[w + 2], w3 = weights[w + 3];
|
|
164
|
+
const r = (a0 & 0xffff) * w0 + (a1 & 0xffff) * w1 + (a2 & 0xffff) * w2 + (a3 & 0xffff) * w3;
|
|
165
|
+
const b = (a0 >>> 16) * w0 + (a1 >>> 16) * w1 + (a2 >>> 16) * w2 + (a3 >>> 16) * w3;
|
|
166
|
+
const g = lanes[s + 1] * w0 + lanes[s + 3] * w1 + lanes[s + 5] * w2 + lanes[s + 7] * w3;
|
|
167
|
+
result[o] = (r + R >> S) | (g + R >> S) << 8 | (b + R >> S) << 16 | 0xff000000;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
else if (taps === 2) {
|
|
171
|
+
for (let x = 0; x < outWidth; x++, o++) {
|
|
172
|
+
const s = row + start[x] * 2, w = x * 2;
|
|
173
|
+
const a0 = lanes[s], a1 = lanes[s + 2], w0 = weights[w], w1 = weights[w + 1];
|
|
174
|
+
const r = (a0 & 0xffff) * w0 + (a1 & 0xffff) * w1;
|
|
175
|
+
const b = (a0 >>> 16) * w0 + (a1 >>> 16) * w1;
|
|
176
|
+
const g = lanes[s + 1] * w0 + lanes[s + 3] * w1;
|
|
177
|
+
result[o] = (r + R >> S) | (g + R >> S) << 8 | (b + R >> S) << 16 | 0xff000000;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
for (let x = 0; x < outWidth; x++, o++) {
|
|
182
|
+
let r = 0, g = 0, b = 0, k = 0, s = row + start[x] * 2, w = x * taps;
|
|
183
|
+
for (; k + 1 < taps; k += 2, s += 4) {
|
|
184
|
+
const a0 = lanes[s], a1 = lanes[s + 2], w0 = weights[w + k], w1 = weights[w + k + 1];
|
|
185
|
+
r += (a0 & 0xffff) * w0 + (a1 & 0xffff) * w1;
|
|
186
|
+
b += (a0 >>> 16) * w0 + (a1 >>> 16) * w1;
|
|
187
|
+
g += lanes[s + 1] * w0 + lanes[s + 3] * w1;
|
|
188
|
+
}
|
|
189
|
+
if (k < taps) {
|
|
190
|
+
const a0 = lanes[s], w0 = weights[w + k];
|
|
191
|
+
r += (a0 & 0xffff) * w0;
|
|
192
|
+
b += (a0 >>> 16) * w0;
|
|
193
|
+
g += lanes[s + 1] * w0;
|
|
194
|
+
}
|
|
195
|
+
result[o] = (r + R >> S) | (g + R >> S) << 8 | (b + R >> S) << 16 | 0xff000000;
|
|
64
196
|
}
|
|
65
|
-
const o = (y * outWidth + x) * 4;
|
|
66
|
-
plane[o] = r / 255;
|
|
67
|
-
plane[o + 1] = g / 255;
|
|
68
|
-
plane[o + 2] = b / 255;
|
|
69
|
-
plane[o + 3] = a;
|
|
70
197
|
}
|
|
71
198
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
199
|
+
return true;
|
|
200
|
+
}
|
|
201
|
+
function resamplePremultiplied(src, width, height, outWidth, outHeight, filter, out) {
|
|
202
|
+
const plane = new Int32Array(width * outHeight * 4);
|
|
203
|
+
if (outHeight === height) {
|
|
204
|
+
for (let s = 0; s < src.length; s += 4) {
|
|
205
|
+
const a = src[s + 3];
|
|
206
|
+
plane[s] = src[s] * a;
|
|
207
|
+
plane[s + 1] = src[s + 1] * a;
|
|
208
|
+
plane[s + 2] = src[s + 2] * a;
|
|
209
|
+
plane[s + 3] = a * 255;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
else {
|
|
213
|
+
const { start, weights, taps } = coefficients(height, outHeight, filter, BITS);
|
|
214
|
+
const stride = width * 4, H = ONE >> 1;
|
|
215
|
+
for (let y = 0, o = 0; y < outHeight; y++) {
|
|
216
|
+
const w = y * taps, r0 = start[y] * stride;
|
|
217
|
+
for (let x = 0; x < stride; x += 4, o += 4) {
|
|
218
|
+
let r = 0, g = 0, b = 0, a = 0, k = 0, s = r0 + x;
|
|
219
|
+
for (; k + 1 < taps; k += 2, s += stride * 2) {
|
|
220
|
+
const t = s + stride, wa = weights[w + k] * src[s + 3], wb = weights[w + k + 1] * src[t + 3];
|
|
221
|
+
r += src[s] * wa + src[t] * wb;
|
|
222
|
+
g += src[s + 1] * wa + src[t + 1] * wb;
|
|
223
|
+
b += src[s + 2] * wa + src[t + 2] * wb;
|
|
224
|
+
a += wa + wb;
|
|
225
|
+
}
|
|
226
|
+
if (k < taps) {
|
|
227
|
+
const wa = weights[w + k] * src[s + 3];
|
|
228
|
+
r += src[s] * wa;
|
|
229
|
+
g += src[s + 1] * wa;
|
|
230
|
+
b += src[s + 2] * wa;
|
|
231
|
+
a += wa;
|
|
232
|
+
}
|
|
233
|
+
plane[o] = r + H >> BITS;
|
|
234
|
+
plane[o + 1] = g + H >> BITS;
|
|
235
|
+
plane[o + 2] = b + H >> BITS;
|
|
236
|
+
plane[o + 3] = a * 255 + H >> BITS;
|
|
83
237
|
}
|
|
84
238
|
}
|
|
85
|
-
plane = next;
|
|
86
239
|
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
240
|
+
const { start, weights, taps } = outWidth === width ? { start: null, weights: null, taps: 0 } : coefficients(width, outWidth, filter, BITS);
|
|
241
|
+
for (let y = 0, o = 0; y < outHeight; y++) {
|
|
242
|
+
const row = y * width * 4;
|
|
243
|
+
for (let x = 0; x < outWidth; x++, o += 4) {
|
|
244
|
+
let r = 0, g = 0, b = 0, a = 0;
|
|
245
|
+
if (!start || !weights) {
|
|
246
|
+
const s = row + x * 4;
|
|
247
|
+
r = plane[s] * ONE;
|
|
248
|
+
g = plane[s + 1] * ONE;
|
|
249
|
+
b = plane[s + 2] * ONE;
|
|
250
|
+
a = plane[s + 3] * ONE;
|
|
251
|
+
}
|
|
252
|
+
else {
|
|
253
|
+
let k = 0, s = row + start[x] * 4, w = x * taps;
|
|
254
|
+
for (; k + 1 < taps; k += 2, s += 8) {
|
|
255
|
+
const w0 = weights[w + k], w1 = weights[w + k + 1];
|
|
256
|
+
r += plane[s] * w0 + plane[s + 4] * w1;
|
|
257
|
+
g += plane[s + 1] * w0 + plane[s + 5] * w1;
|
|
258
|
+
b += plane[s + 2] * w0 + plane[s + 6] * w1;
|
|
259
|
+
a += plane[s + 3] * w0 + plane[s + 7] * w1;
|
|
260
|
+
}
|
|
261
|
+
if (k < taps) {
|
|
262
|
+
const w0 = weights[w + k];
|
|
263
|
+
r += plane[s] * w0;
|
|
264
|
+
g += plane[s + 1] * w0;
|
|
265
|
+
b += plane[s + 2] * w0;
|
|
266
|
+
a += plane[s + 3] * w0;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
if (a < 127.5 * ONE) {
|
|
270
|
+
out[o] = out[o + 1] = out[o + 2] = out[o + 3] = 0;
|
|
271
|
+
continue;
|
|
272
|
+
}
|
|
273
|
+
const f = 255 / Math.min(a, 65025 * ONE);
|
|
274
|
+
out[o] = r * f;
|
|
275
|
+
out[o + 1] = g * f;
|
|
276
|
+
out[o + 2] = b * f;
|
|
277
|
+
out[o + 3] = a / (255 * ONE);
|
|
92
278
|
}
|
|
93
|
-
const f = 255 / Math.min(255, a);
|
|
94
|
-
out[i] = plane[i] * f;
|
|
95
|
-
out[i + 1] = plane[i + 1] * f;
|
|
96
|
-
out[i + 2] = plane[i + 2] * f;
|
|
97
|
-
out[i + 3] = a;
|
|
98
279
|
}
|
|
99
280
|
}
|
package/dist/util/utf8.js
CHANGED
|
@@ -1,55 +1,8 @@
|
|
|
1
|
+
const encoder = new TextEncoder();
|
|
2
|
+
const decoder = new TextDecoder();
|
|
1
3
|
export function encode(text) {
|
|
2
|
-
|
|
3
|
-
for (const char of text) {
|
|
4
|
-
const c = char.codePointAt(0);
|
|
5
|
-
if (c < 0x80)
|
|
6
|
-
out.push(c);
|
|
7
|
-
else if (c < 0x800)
|
|
8
|
-
out.push(0xc0 | c >> 6, 0x80 | c & 63);
|
|
9
|
-
else if (c < 0x10000)
|
|
10
|
-
out.push(0xe0 | c >> 12, 0x80 | c >> 6 & 63, 0x80 | c & 63);
|
|
11
|
-
else
|
|
12
|
-
out.push(0xf0 | c >> 18, 0x80 | c >> 12 & 63, 0x80 | c >> 6 & 63, 0x80 | c & 63);
|
|
13
|
-
}
|
|
14
|
-
return Uint8Array.from(out);
|
|
4
|
+
return encoder.encode(text);
|
|
15
5
|
}
|
|
16
6
|
export function decode(bytes) {
|
|
17
|
-
|
|
18
|
-
let i = bytes[0] === 0xef && bytes[1] === 0xbb && bytes[2] === 0xbf ? 3 : 0;
|
|
19
|
-
while (i < bytes.length) {
|
|
20
|
-
const b = bytes[i++];
|
|
21
|
-
let c, extra;
|
|
22
|
-
if (b < 0x80) {
|
|
23
|
-
c = b;
|
|
24
|
-
extra = 0;
|
|
25
|
-
}
|
|
26
|
-
else if (b >= 0xc2 && b < 0xe0) {
|
|
27
|
-
c = b & 31;
|
|
28
|
-
extra = 1;
|
|
29
|
-
}
|
|
30
|
-
else if (b >= 0xe0 && b < 0xf0) {
|
|
31
|
-
c = b & 15;
|
|
32
|
-
extra = 2;
|
|
33
|
-
}
|
|
34
|
-
else if (b >= 0xf0 && b < 0xf5) {
|
|
35
|
-
c = b & 7;
|
|
36
|
-
extra = 3;
|
|
37
|
-
}
|
|
38
|
-
else {
|
|
39
|
-
out += '�';
|
|
40
|
-
continue;
|
|
41
|
-
}
|
|
42
|
-
let valid = true;
|
|
43
|
-
for (let k = 0; k < extra; k++) {
|
|
44
|
-
const next = bytes[i];
|
|
45
|
-
if (next === undefined || (next & 0xc0) !== 0x80) {
|
|
46
|
-
valid = false;
|
|
47
|
-
break;
|
|
48
|
-
}
|
|
49
|
-
c = c << 6 | next & 63;
|
|
50
|
-
i++;
|
|
51
|
-
}
|
|
52
|
-
out += valid && c <= 0x10ffff ? String.fromCodePoint(c) : '�';
|
|
53
|
-
}
|
|
54
|
-
return out;
|
|
7
|
+
return decoder.decode(bytes);
|
|
55
8
|
}
|
package/dist/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const VERSION = '3.1
|
|
1
|
+
export const VERSION = '3.2.1';
|