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.
Files changed (52) hide show
  1. package/README.md +12 -4
  2. package/dist/animation.d.ts +92 -7
  3. package/dist/animation.js +50 -20
  4. package/dist/codecs/exif.js +62 -0
  5. package/dist/codecs/gif.js +43 -27
  6. package/dist/codecs/jpeg.js +13 -1
  7. package/dist/codecs/png.js +85 -21
  8. package/dist/codecs/quantize.js +2 -2
  9. package/dist/codecs/tga.js +47 -4
  10. package/dist/codecs/vp8l.js +27 -30
  11. package/dist/codecs/webp.js +23 -10
  12. package/dist/frame.d.ts +30 -2
  13. package/dist/frame.js +20 -9
  14. package/dist/gif.d.ts +10 -7
  15. package/dist/gif.js +7 -5
  16. package/dist/image-type.d.ts +1 -0
  17. package/dist/image-type.js +1 -0
  18. package/dist/image.d.ts +231 -31
  19. package/dist/image.js +118 -53
  20. package/dist/index.d.ts +14 -4
  21. package/dist/index.js +6 -4
  22. package/dist/metadata.d.ts +35 -0
  23. package/dist/metadata.js +43 -0
  24. package/dist/render/svg.js +39 -21
  25. package/dist/util/blur.js +88 -0
  26. package/dist/util/optimize.js +264 -0
  27. package/dist/util/options.js +3 -0
  28. package/dist/util/resample.js +244 -63
  29. package/dist/util/utf8.js +4 -51
  30. package/dist/version.js +1 -1
  31. package/package.json +9 -2
  32. package/dist/codecs/crc.d.ts +0 -9
  33. package/dist/codecs/exif.d.ts +0 -11
  34. package/dist/codecs/gif.d.ts +0 -44
  35. package/dist/codecs/jpeg.d.ts +0 -35
  36. package/dist/codecs/png.d.ts +0 -97
  37. package/dist/codecs/quantize.d.ts +0 -25
  38. package/dist/codecs/tga.d.ts +0 -16
  39. package/dist/codecs/tiff.d.ts +0 -6
  40. package/dist/codecs/vp8-tables.d.ts +0 -10
  41. package/dist/codecs/vp8.d.ts +0 -8
  42. package/dist/codecs/vp8l.d.ts +0 -62
  43. package/dist/codecs/webp.d.ts +0 -67
  44. package/dist/codecs/zlib.d.ts +0 -22
  45. package/dist/render/font.d.ts +0 -92
  46. package/dist/render/hinting.d.ts +0 -110
  47. package/dist/render/svg.d.ts +0 -11
  48. package/dist/render/text.d.ts +0 -63
  49. package/dist/util/blur.d.ts +0 -13
  50. package/dist/util/resample.d.ts +0 -12
  51. package/dist/util/utf8.d.ts +0 -5
  52. 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
+ }
@@ -0,0 +1,3 @@
1
+ export function isOptions(value) {
2
+ return typeof value === 'object' && value !== null && !ArrayBuffer.isView(value);
3
+ }
@@ -12,88 +12,269 @@ export const CUBIC = {
12
12
  return 0;
13
13
  }
14
14
  };
15
- function coefficients(inSize, outSize, filter) {
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 size = Math.ceil(support) * 2 + 1;
20
- const start = new Int32Array(outSize);
21
- const count = new Int32Array(outSize);
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
- const min = Math.max(0, Math.floor(center - support + 0.5));
26
- const max = Math.min(inSize, Math.floor(center + support + 0.5));
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 x = min; x < max; x++) {
29
- const w = filter.weight((x - center + 0.5) / filterScale);
30
- weights[i * size + x - min] = w;
31
- total += w;
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 (total !== 0)
34
- for (let k = 0; k < max - min; k++)
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, count, weights, size };
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
- let plane = new Float32Array(outWidth * height * 4);
43
- const horizontal = outWidth !== width ? coefficients(width, outWidth, filter) : null;
44
- for (let y = 0; y < height; y++) {
45
- const row = y * width * 4;
46
- for (let x = 0; x < outWidth; x++) {
47
- let r = 0, g = 0, b = 0, a = 0;
48
- if (horizontal) {
49
- const { start, count, weights, size } = horizontal;
50
- for (let k = 0, s = row + start[x] * 4; k < count[x]; k++, s += 4) {
51
- const wa = weights[x * size + k] * src[s + 3];
52
- r += src[s] * wa;
53
- g += src[s + 1] * wa;
54
- b += src[s + 2] * wa;
55
- a += wa;
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
- const s = row + x * 4;
60
- a = src[s + 3];
61
- r = src[s] * a;
62
- g = src[s + 1] * a;
63
- b = src[s + 2] * a;
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
- if (outHeight !== height) {
73
- const { start, count, weights, size } = coefficients(height, outHeight, filter);
74
- const next = new Float32Array(outWidth * outHeight * 4);
75
- const stride = outWidth * 4;
76
- for (let y = 0; y < outHeight; y++) {
77
- const o = y * stride;
78
- for (let k = 0; k < count[y]; k++) {
79
- const w = weights[y * size + k];
80
- const s = (start[y] + k) * stride;
81
- for (let x = 0; x < stride; x++)
82
- next[o + x] += plane[s + x] * w;
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
- for (let i = 0; i < plane.length; i += 4) {
88
- const a = plane[i + 3];
89
- if (a < 0.5) {
90
- out[i] = out[i + 1] = out[i + 2] = out[i + 3] = 0;
91
- continue;
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
- const out = [];
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
- let out = '';
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.0';
1
+ export const VERSION = '3.2.1';