imagescript 3.2.1 → 3.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +35 -10
- package/THIRD_PARTY_NOTICES.md +298 -2
- package/dist/animation.d.ts +25 -8
- package/dist/animation.js +44 -13
- package/dist/codecs/av1/cdef.js +197 -0
- package/dist/codecs/av1/data.js +141 -0
- package/dist/codecs/av1/decode.js +1769 -0
- package/dist/codecs/av1/filmgrain.js +219 -0
- package/dist/codecs/av1/frame.js +114 -0
- package/dist/codecs/av1/ipred.js +491 -0
- package/dist/codecs/av1/itx.js +950 -0
- package/dist/codecs/av1/loopfilter.js +149 -0
- package/dist/codecs/av1/msac.js +161 -0
- package/dist/codecs/av1/obu.js +516 -0
- package/dist/codecs/av1/postfilter.js +28 -0
- package/dist/codecs/av1/restoration.js +193 -0
- package/dist/codecs/av1/tables.js +160 -0
- package/dist/codecs/avif.js +581 -0
- package/dist/codecs/bmp.js +317 -0
- package/dist/codecs/crc.js +5 -0
- package/dist/codecs/gif.js +10 -35
- package/dist/codecs/hdr.d.ts +25 -0
- package/dist/codecs/hdr.js +201 -0
- package/dist/codecs/ico.js +48 -0
- package/dist/codecs/jpeg.js +11 -28
- package/dist/codecs/jxl/bits.js +126 -0
- package/dist/codecs/jxl/blend.js +117 -0
- package/dist/codecs/jxl/color.js +116 -0
- package/dist/codecs/jxl/dct.js +404 -0
- package/dist/codecs/jxl/entropy.js +556 -0
- package/dist/codecs/jxl/features.js +325 -0
- package/dist/codecs/jxl/filters.js +119 -0
- package/dist/codecs/jxl/frame-header.js +195 -0
- package/dist/codecs/jxl/frame.js +319 -0
- package/dist/codecs/jxl/headers.js +249 -0
- package/dist/codecs/jxl/idct.js +484 -0
- package/dist/codecs/jxl/modular.js +688 -0
- package/dist/codecs/jxl/quant.js +219 -0
- package/dist/codecs/jxl/upsample.js +52 -0
- package/dist/codecs/jxl/vardct.js +472 -0
- package/dist/codecs/jxl.js +89 -0
- package/dist/codecs/netpbm.js +239 -0
- package/dist/codecs/png.js +22 -10
- package/dist/codecs/qoi.js +150 -0
- package/dist/codecs/tga.js +3 -1
- package/dist/codecs/tiff.js +7 -2
- package/dist/codecs/vp8-enc-dsp.js +932 -0
- package/dist/codecs/vp8-enc-tables.js +78 -0
- package/dist/codecs/vp8-enc.js +1930 -0
- package/dist/codecs/vp8.js +3 -1
- package/dist/codecs/vp8l.js +126 -58
- package/dist/codecs/webp.js +47 -11
- package/dist/codecs/zlib.js +81 -69
- package/dist/frame.d.ts +1 -0
- package/dist/frame.js +4 -2
- package/dist/gif.d.ts +1 -0
- package/dist/gif.js +2 -2
- package/dist/image-type.d.ts +15 -1
- package/dist/image-type.js +45 -2
- package/dist/image.d.ts +89 -13
- package/dist/image.js +266 -113
- package/dist/index.d.ts +3 -2
- package/dist/index.js +4 -4
- package/dist/render/bidi.js +350 -0
- package/dist/render/buffer.js +362 -0
- package/dist/render/color.js +164 -0
- package/dist/render/colr.js +523 -0
- package/dist/render/font.js +173 -241
- package/dist/render/hinting.js +38 -22
- package/dist/render/layout.js +1553 -0
- package/dist/render/linebreak.js +210 -0
- package/dist/render/segment.js +106 -0
- package/dist/render/shape.js +984 -0
- package/dist/render/shapers/arabic.js +284 -0
- package/dist/render/shapers/hangul.js +142 -0
- package/dist/render/shapers/hebrew.js +49 -0
- package/dist/render/shapers/index.js +52 -0
- package/dist/render/shapers/indic.js +579 -0
- package/dist/render/shapers/khmer.js +104 -0
- package/dist/render/shapers/machine.js +129 -0
- package/dist/render/shapers/myanmar.js +121 -0
- package/dist/render/shapers/syllabic.js +100 -0
- package/dist/render/shapers/thai.js +125 -0
- package/dist/render/shapers/use.js +235 -0
- package/dist/render/svg.js +102 -23
- package/dist/render/text.js +373 -103
- package/dist/render/unicode-data.js +63 -0
- package/dist/render/unicode.js +50 -0
- package/dist/text-layout.d.ts +4 -1
- package/dist/text-layout.js +2 -2
- package/dist/util/alpha.js +43 -0
- package/dist/util/blur.js +20 -33
- package/dist/util/bytes.js +40 -0
- package/dist/util/limits.js +34 -0
- package/dist/util/options.js +7 -0
- package/dist/util/resample.js +126 -7
- package/dist/util/rotate.js +43 -0
- package/dist/version.js +1 -1
- package/licenses/HarfBuzz.txt +42 -0
- package/licenses/Unicode-3.0.txt +39 -0
- package/package.json +25 -2
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import { ModularImage, channel, decodeModular } from "./modular.js";
|
|
2
|
+
const f32 = Math.fround;
|
|
3
|
+
export const MATRIX_SIZES = [[8, 8], [8, 8], [8, 8], [8, 8], [16, 16], [32, 32], [16, 8], [32, 8], [32, 16], [8, 8], [8, 8], [64, 64], [64, 32], [128, 128], [128, 64], [256, 256], [256, 128]];
|
|
4
|
+
export const MATRIX_INDEX = [0, 1, 2, 3, 4, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 10, 10, 11, 12, 12, 13, 14, 14, 15, 16, 16];
|
|
5
|
+
const SEQ_A = [-1.025, -0.78, -0.65012, -0.19041574, -0.20819396, -0.421064, -0.32733846];
|
|
6
|
+
const SEQ_B = [-0.30419582, -0.36330363, -0.3566038, -0.34430745, -0.33699593, -0.30180866, -0.27321684];
|
|
7
|
+
const SEQ_C = [-1.2, -1.2, -0.8, -0.7, -0.7, -0.4, -0.5];
|
|
8
|
+
const DCT4X8_PARAMS = [[2198.0505, -0.96269625, -0.7619425, -0.65511405], [764.36554, -0.926302, -0.967523, -0.2784529], [527.10754, -1.4594386, -1.4500821, -1.5843723]];
|
|
9
|
+
const DCT4_PARAMS = [[2200.0, 0.0, 0.0, 0.0], [392.0, 0.0, 0.0, 0.0], [112.0, -0.25, -0.25, -0.5]];
|
|
10
|
+
const common = (a, b, c) => ({ mode: 'dct', dct: [[a, ...SEQ_A], [b, ...SEQ_B], [c, ...SEQ_C]] });
|
|
11
|
+
function defaultEncoding(index) {
|
|
12
|
+
switch (index) {
|
|
13
|
+
case 0: return { mode: 'dct', dct: [[3150.0, 0.0, -0.4, -0.4, -0.4, -2.0], [560.0, 0.0, -0.3, -0.3, -0.3, -0.3], [512.0, -2.0, -1.0, 0.0, -1.0, -2.0]] };
|
|
14
|
+
case 1: return { mode: 'hornuss', params: [[280.0, 3160.0, 3160.0], [60.0, 864.0, 864.0], [18.0, 200.0, 200.0]] };
|
|
15
|
+
case 2: return { mode: 'dct2', params: [[3840.0, 2560.0, 1280.0, 640.0, 480.0, 300.0], [960.0, 640.0, 320.0, 180.0, 140.0, 120.0], [640.0, 320.0, 128.0, 64.0, 32.0, 16.0]] };
|
|
16
|
+
case 3: return { mode: 'dct4', params: [[1, 1], [1, 1], [1, 1]], dct: DCT4_PARAMS };
|
|
17
|
+
case 4: return { mode: 'dct', dct: [[8996.873, -1.3000778, -0.4942453, -0.43909377, -0.6350102, -0.9017726, -1.6162099], [3191.4836, -0.67424583, -0.80745816, -0.4492584, -0.3586544, -0.3132239, -0.37615025], [1157.504, -2.0531423, -1.4, -0.5068713, -0.4270873, -1.4856834, -4.920914]] };
|
|
18
|
+
case 5: return { mode: 'dct', dct: [[15718.408, -1.025, -0.98, -0.9012, -0.4, -0.48819396, -0.421064, -0.27], [7305.7637, -0.8041958, -0.76330364, -0.5566038, -0.49785304, -0.43699592, -0.40180868, -0.27321684], [3803.5317, -3.0607336, -2.041327, -2.023565, -0.54953897, -0.4, -0.4, -0.3]] };
|
|
19
|
+
case 6: return { mode: 'dct', dct: [[7240.7734, -0.7, -0.7, -0.2, -0.2, -0.2, -0.5], [1448.1547, -0.5, -0.5, -0.5, -0.2, -0.2, -0.2], [506.85413, -1.4, -0.2, -0.5, -0.5, -1.5, -3.6]] };
|
|
20
|
+
case 7: return { mode: 'dct', dct: [[16283.249, -1.7812846, -1.6309059, -1.0382179, -0.85, -0.7, -0.9, -1.2360638], [5089.1577, -0.3200494, -0.3536285, -0.3034, -0.61, -0.5, -0.5, -0.6], [3397.7761, -0.32132736, -0.3450762, -0.7034, -0.9, -1.0, -1.0, -1.1754606]] };
|
|
21
|
+
case 8: return { mode: 'dct', dct: [[13844.971, -0.971138, -0.658, -0.42026, -0.22712, -0.2206, -0.226, -0.6], [4798.964, -0.6112531, -0.8377079, -0.7901486, -0.26927274, -0.38272768, -0.22924222, -0.20719099], [1807.2369, -1.2, -1.2, -0.7, -0.7, -0.7, -0.4, -0.5]] };
|
|
22
|
+
case 9: return { mode: 'dct4x8', params: [[1], [1], [1]], dct: DCT4X8_PARAMS };
|
|
23
|
+
case 10: return {
|
|
24
|
+
mode: 'afv',
|
|
25
|
+
params: [[3072.0, 3072.0, 256.0, 256.0, 256.0, 414.0, 0.0, 0.0, 0.0], [1024.0, 1024.0, 50.0, 50.0, 50.0, 58.0, 0.0, 0.0, 0.0], [384.0, 384.0, 12.0, 12.0, 12.0, 22.0, -0.25, -0.25, -0.25]],
|
|
26
|
+
dct: DCT4X8_PARAMS, dct4x4: DCT4_PARAMS
|
|
27
|
+
};
|
|
28
|
+
case 11: return common(23966.166, 8380.191, 4493.024);
|
|
29
|
+
case 12: return common(15358.898, 5597.3604, 2919.9617);
|
|
30
|
+
case 13: return common(47932.332, 16760.383, 8986.048);
|
|
31
|
+
case 14: return common(30717.797, 11194.721, 5839.9233);
|
|
32
|
+
case 15: return common(95864.664, 33520.766, 17972.096);
|
|
33
|
+
default: return common(61435.594, 24209.441, 12979.847);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function interpolate(pos, max, bands) {
|
|
37
|
+
if (bands.length === 1)
|
|
38
|
+
return bands[0];
|
|
39
|
+
const scaled = f32(pos * (bands.length - 1) / max), index = Math.trunc(scaled), frac = f32(scaled - index);
|
|
40
|
+
const a = bands[index], b = bands[index + 1];
|
|
41
|
+
return f32(a * f32((b / a) ** frac));
|
|
42
|
+
}
|
|
43
|
+
const mult = (x) => x > 0 ? 1 + x : 1 / (1 - x);
|
|
44
|
+
function dctWeights(params, w, h) {
|
|
45
|
+
const bands = [params[0]];
|
|
46
|
+
for (let i = 1; i < params.length; i++) {
|
|
47
|
+
const band = f32(bands[i - 1] * f32(mult(params[i])));
|
|
48
|
+
if (band <= 0)
|
|
49
|
+
throw new Error('JPEG XL: invalid dequantization matrix');
|
|
50
|
+
bands.push(band);
|
|
51
|
+
}
|
|
52
|
+
const out = new Float32Array(w * h);
|
|
53
|
+
for (let y = 0; y < h; y++) {
|
|
54
|
+
for (let x = 0; x < w; x++) {
|
|
55
|
+
const dx = f32(x / (w - 1)), dy = f32(y / (h - 1));
|
|
56
|
+
out[y * w + x] = interpolate(f32(Math.sqrt(f32(dx * dx + dy * dy))), f32(Math.SQRT2 + 1e-6), bands);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return out;
|
|
60
|
+
}
|
|
61
|
+
function weights(e, index) {
|
|
62
|
+
const [w, h] = MATRIX_SIZES[index];
|
|
63
|
+
switch (e.mode) {
|
|
64
|
+
case 'dct': return e.dct.map(p => dctWeights(p, w, h));
|
|
65
|
+
case 'hornuss': return e.params.map(p => {
|
|
66
|
+
const m = new Float32Array(64).fill(p[0]);
|
|
67
|
+
m[0] = 1;
|
|
68
|
+
m[1] = m[8] = p[1];
|
|
69
|
+
m[9] = p[2];
|
|
70
|
+
return m;
|
|
71
|
+
});
|
|
72
|
+
case 'dct2': return e.params.map(p => {
|
|
73
|
+
const m = new Float32Array(64);
|
|
74
|
+
m[0] = 1;
|
|
75
|
+
p.forEach((v, i) => {
|
|
76
|
+
const dim = 1 << (i >> 1);
|
|
77
|
+
if (i % 2 === 0) {
|
|
78
|
+
for (let y = 0; y < dim; y++)
|
|
79
|
+
for (let x = dim; x < 2 * dim; x++)
|
|
80
|
+
m[y * 8 + x] = m[x * 8 + y] = v;
|
|
81
|
+
}
|
|
82
|
+
else
|
|
83
|
+
for (let y = dim; y < 2 * dim; y++)
|
|
84
|
+
for (let x = dim; x < 2 * dim; x++)
|
|
85
|
+
m[y * 8 + x] = v;
|
|
86
|
+
});
|
|
87
|
+
return m;
|
|
88
|
+
});
|
|
89
|
+
case 'dct4': return e.params.map((p, c) => {
|
|
90
|
+
const mat = dctWeights(e.dct[c], 4, 4), m = new Float32Array(64);
|
|
91
|
+
for (let y = 0; y < 4; y++) {
|
|
92
|
+
for (let x = 0; x < 4; x++) {
|
|
93
|
+
const v = mat[y * 4 + x];
|
|
94
|
+
m[y * 16 + x * 2] = m[y * 16 + x * 2 + 1] = m[(y * 2 + 1) * 8 + x * 2] = m[(y * 2 + 1) * 8 + x * 2 + 1] = v;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
m[1] /= p[0];
|
|
98
|
+
m[8] /= p[0];
|
|
99
|
+
m[9] /= p[1];
|
|
100
|
+
return m;
|
|
101
|
+
});
|
|
102
|
+
case 'dct4x8': return e.params.map((p, c) => {
|
|
103
|
+
const mat = dctWeights(e.dct[c], 8, 4), m = new Float32Array(64);
|
|
104
|
+
for (let y = 0; y < 4; y++)
|
|
105
|
+
for (let k = 0; k < 2; k++)
|
|
106
|
+
m.set(mat.subarray(y * 8, y * 8 + 8), (y * 2 + k) * 8);
|
|
107
|
+
m[8] /= p[0];
|
|
108
|
+
return m;
|
|
109
|
+
});
|
|
110
|
+
case 'afv': return e.params.map((p, c) => {
|
|
111
|
+
const FREQS = [0, 0, 0.8517779, 5.3777843, 0, 0, 4.734748, 5.4492455, 1.659827, 4.0, 7.275749, 10.423227, 2.6629324, 7.6306577, 8.962389, 12.971662];
|
|
112
|
+
const lo = FREQS[2], hi = FREQS[15];
|
|
113
|
+
const w4x8 = dctWeights(e.dct[c], 8, 4), w4x4 = dctWeights(e.dct4x4[c], 4, 4);
|
|
114
|
+
const bands = [p[5]];
|
|
115
|
+
for (let i = 1; i < 4; i++)
|
|
116
|
+
bands.push(f32(bands[i - 1] * f32(mult(p[5 + i]))));
|
|
117
|
+
const m = new Float32Array(64);
|
|
118
|
+
for (let y = 0; y < 4; y++) {
|
|
119
|
+
for (let x = 0; x < 4; x++) {
|
|
120
|
+
m[16 * y + 2 * x] = x === 0 && y === 0 ? 1 : x === 0 && y === 1 ? p[2] : x === 1 && y === 0 ? p[3] : x === 1 && y === 1 ? p[4] :
|
|
121
|
+
interpolate(f32(FREQS[y * 4 + x] - lo), f32(hi - lo + 1e-6), bands);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
for (let y = 0; y < 4; y++) {
|
|
125
|
+
for (let x = 0; x < 8; x++)
|
|
126
|
+
m[16 * y + 8 + x] = y === 0 && x === 0 ? p[0] : w4x8[y * 8 + x];
|
|
127
|
+
for (let x = 0; x < 4; x++)
|
|
128
|
+
m[16 * y + 2 * x + 1] = y === 0 && x === 0 ? p[1] : w4x4[y * 4 + x];
|
|
129
|
+
}
|
|
130
|
+
return m;
|
|
131
|
+
});
|
|
132
|
+
default: return e.values.map(v => Float32Array.from(v, q => q * e.denominator));
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
export function readDequantMatrices(r, bitDepth, stream, tree) {
|
|
136
|
+
const encodings = [];
|
|
137
|
+
const allDefault = r.bool();
|
|
138
|
+
for (let i = 0; i < 17; i++) {
|
|
139
|
+
if (allDefault) {
|
|
140
|
+
encodings.push(DEFAULTS[i]);
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
const mode = r.bits(3);
|
|
144
|
+
if (mode >= 1 && mode <= 5 && ![0, 1, 2, 3, 9, 10].includes(i))
|
|
145
|
+
throw new Error('JPEG XL: invalid dequantization matrix encoding');
|
|
146
|
+
const fixed = (n) => [0, 1, 2].map(() => Array.from({ length: n }, () => r.f16()));
|
|
147
|
+
const dctParams = () => {
|
|
148
|
+
const n = r.bits(4) + 1;
|
|
149
|
+
const p = [0, 1, 2].map(() => Array.from({ length: n }, () => r.f16()));
|
|
150
|
+
for (const c of p)
|
|
151
|
+
c[0] *= 64;
|
|
152
|
+
return p;
|
|
153
|
+
};
|
|
154
|
+
switch (mode) {
|
|
155
|
+
case 0:
|
|
156
|
+
encodings.push(DEFAULTS[i]);
|
|
157
|
+
break;
|
|
158
|
+
case 1:
|
|
159
|
+
encodings.push({ mode: 'hornuss', params: fixed(3) });
|
|
160
|
+
break;
|
|
161
|
+
case 2:
|
|
162
|
+
encodings.push({ mode: 'dct2', params: fixed(6) });
|
|
163
|
+
break;
|
|
164
|
+
case 3:
|
|
165
|
+
encodings.push({ mode: 'dct4', params: fixed(2), dct: dctParams() });
|
|
166
|
+
break;
|
|
167
|
+
case 4:
|
|
168
|
+
encodings.push({ mode: 'dct4x8', params: fixed(1), dct: dctParams() });
|
|
169
|
+
break;
|
|
170
|
+
case 5: {
|
|
171
|
+
const params = fixed(9);
|
|
172
|
+
for (const c of params)
|
|
173
|
+
for (let k = 0; k < 6; k++)
|
|
174
|
+
c[k] *= 64;
|
|
175
|
+
encodings.push({ mode: 'afv', params, dct: dctParams(), dct4x4: dctParams() });
|
|
176
|
+
break;
|
|
177
|
+
}
|
|
178
|
+
case 6:
|
|
179
|
+
encodings.push({ mode: 'dct', dct: dctParams() });
|
|
180
|
+
break;
|
|
181
|
+
case 7: {
|
|
182
|
+
const [w, h] = MATRIX_SIZES[i], denominator = r.f16();
|
|
183
|
+
const image = new ModularImage([channel(w, h), channel(w, h), channel(w, h)], bitDepth);
|
|
184
|
+
decodeModular(r, image, stream + i, tree, Infinity, true);
|
|
185
|
+
encodings.push({ mode: 'raw', denominator, values: image.channels.map(c => c.data) });
|
|
186
|
+
break;
|
|
187
|
+
}
|
|
188
|
+
default: throw new Error('JPEG XL: invalid dequantization matrix encoding');
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
const matrices = [], transposed = [];
|
|
192
|
+
encodings.forEach((e, i) => {
|
|
193
|
+
const [m, t] = e === DEFAULTS[i] ? defaultMatrices(i) : matrix(e, i);
|
|
194
|
+
matrices.push(m);
|
|
195
|
+
transposed.push(t);
|
|
196
|
+
});
|
|
197
|
+
return { matrices, transposed };
|
|
198
|
+
}
|
|
199
|
+
function matrix(e, i) {
|
|
200
|
+
const m = weights(e, i);
|
|
201
|
+
if (e.mode !== 'raw')
|
|
202
|
+
for (const c of m)
|
|
203
|
+
for (let k = 0; k < c.length; k++)
|
|
204
|
+
c[k] = 1 / c[k];
|
|
205
|
+
for (const c of m)
|
|
206
|
+
for (const v of c)
|
|
207
|
+
if (!(v > 0 && v < 1e8))
|
|
208
|
+
throw new Error('JPEG XL: invalid dequantization matrix');
|
|
209
|
+
const [w, h] = MATRIX_SIZES[i];
|
|
210
|
+
return [m, m.map(c => {
|
|
211
|
+
const t = new Float32Array(c.length);
|
|
212
|
+
for (let k = 0; k < c.length; k++)
|
|
213
|
+
t[k] = c[(k % h) * w + Math.floor(k / h)];
|
|
214
|
+
return t;
|
|
215
|
+
})];
|
|
216
|
+
}
|
|
217
|
+
const DEFAULTS = Array.from({ length: 17 }, (_, i) => defaultEncoding(i));
|
|
218
|
+
const defaultCache = [];
|
|
219
|
+
const defaultMatrices = (i) => defaultCache[i] ??= matrix(DEFAULTS[i], i);
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
export function mirror(i, len) {
|
|
2
|
+
for (;;) {
|
|
3
|
+
if (i < 0)
|
|
4
|
+
i = -i - 1;
|
|
5
|
+
else if (i >= len)
|
|
6
|
+
i = 2 * len - i - 1;
|
|
7
|
+
else
|
|
8
|
+
return i;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
export function upsample(src, w, h, factor, image, outW, outH) {
|
|
12
|
+
const weights = factor === 2 ? image.up2 : factor === 4 ? image.up4 : image.up8;
|
|
13
|
+
const half = factor / 2;
|
|
14
|
+
const kernels = new Float32Array(half * half * 25);
|
|
15
|
+
let k = 0;
|
|
16
|
+
for (let y = 0; y < 5 * half; y++) {
|
|
17
|
+
for (let x = y; x < 5 * half; x++) {
|
|
18
|
+
const v = weights[k++];
|
|
19
|
+
kernels[(Math.floor(y / 5) * half + Math.floor(x / 5)) * 25 + (y % 5) * 5 + x % 5] = v;
|
|
20
|
+
kernels[(Math.floor(x / 5) * half + Math.floor(y / 5)) * 25 + (x % 5) * 5 + y % 5] = v;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
const pw = w + 4, padded = new Float32Array(pw * (h + 4));
|
|
24
|
+
for (let y = 0; y < h + 4; y++) {
|
|
25
|
+
const sy = mirror(y - 2, h);
|
|
26
|
+
for (let x = 0; x < pw; x++)
|
|
27
|
+
padded[y * pw + x] = src[sy * w + mirror(x - 2, w)];
|
|
28
|
+
}
|
|
29
|
+
const out = new Float32Array(outW * outH), window = new Float32Array(25);
|
|
30
|
+
for (let y = 0; y < outH; y++) {
|
|
31
|
+
const ry = Math.floor(y / factor), fy = y % factor, my = Math.min(fy, factor - fy - 1), flipV = fy >= half;
|
|
32
|
+
for (let x = 0; x < outW; x++) {
|
|
33
|
+
const rx = Math.floor(x / factor), fx = x % factor, mx = Math.min(fx, factor - fx - 1), flipH = fx >= half;
|
|
34
|
+
const kernel = (my * half + mx) * 25;
|
|
35
|
+
let sum = 0, min = Infinity, max = -Infinity;
|
|
36
|
+
for (let iy = 0; iy < 5; iy++) {
|
|
37
|
+
const ky = flipV ? 4 - iy : iy, row = (ry + iy) * pw + rx;
|
|
38
|
+
for (let ix = 0; ix < 5; ix++) {
|
|
39
|
+
const kx = flipH ? 4 - ix : ix, v = padded[row + ix];
|
|
40
|
+
sum += kernels[kernel + ky * 5 + kx] * v;
|
|
41
|
+
if (v < min)
|
|
42
|
+
min = v;
|
|
43
|
+
if (v > max)
|
|
44
|
+
max = v;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
out[y * outW + x] = min > max ? NaN : sum < min ? min : sum > max ? max : sum;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
void window;
|
|
51
|
+
return out;
|
|
52
|
+
}
|