imagescript 3.3.0 → 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.
Files changed (59) hide show
  1. package/README.md +28 -8
  2. package/THIRD_PARTY_NOTICES.md +167 -2
  3. package/dist/animation.d.ts +18 -8
  4. package/dist/animation.js +23 -2
  5. package/dist/codecs/av1/cdef.js +197 -0
  6. package/dist/codecs/av1/data.js +141 -0
  7. package/dist/codecs/av1/decode.js +1769 -0
  8. package/dist/codecs/av1/filmgrain.js +219 -0
  9. package/dist/codecs/av1/frame.js +114 -0
  10. package/dist/codecs/av1/ipred.js +491 -0
  11. package/dist/codecs/av1/itx.js +950 -0
  12. package/dist/codecs/av1/loopfilter.js +149 -0
  13. package/dist/codecs/av1/msac.js +161 -0
  14. package/dist/codecs/av1/obu.js +516 -0
  15. package/dist/codecs/av1/postfilter.js +28 -0
  16. package/dist/codecs/av1/restoration.js +193 -0
  17. package/dist/codecs/av1/tables.js +160 -0
  18. package/dist/codecs/avif.js +581 -0
  19. package/dist/codecs/bmp.js +317 -0
  20. package/dist/codecs/hdr.d.ts +25 -0
  21. package/dist/codecs/hdr.js +201 -0
  22. package/dist/codecs/ico.js +48 -0
  23. package/dist/codecs/jpeg.js +2 -1
  24. package/dist/codecs/jxl/bits.js +126 -0
  25. package/dist/codecs/jxl/blend.js +117 -0
  26. package/dist/codecs/jxl/color.js +116 -0
  27. package/dist/codecs/jxl/dct.js +404 -0
  28. package/dist/codecs/jxl/entropy.js +556 -0
  29. package/dist/codecs/jxl/features.js +325 -0
  30. package/dist/codecs/jxl/filters.js +119 -0
  31. package/dist/codecs/jxl/frame-header.js +195 -0
  32. package/dist/codecs/jxl/frame.js +319 -0
  33. package/dist/codecs/jxl/headers.js +249 -0
  34. package/dist/codecs/jxl/idct.js +484 -0
  35. package/dist/codecs/jxl/modular.js +688 -0
  36. package/dist/codecs/jxl/quant.js +219 -0
  37. package/dist/codecs/jxl/upsample.js +52 -0
  38. package/dist/codecs/jxl/vardct.js +472 -0
  39. package/dist/codecs/jxl.js +89 -0
  40. package/dist/codecs/netpbm.js +239 -0
  41. package/dist/codecs/qoi.js +150 -0
  42. package/dist/codecs/vp8-enc-dsp.js +932 -0
  43. package/dist/codecs/vp8-enc-tables.js +78 -0
  44. package/dist/codecs/vp8-enc.js +1930 -0
  45. package/dist/codecs/webp.js +36 -2
  46. package/dist/image-type.d.ts +15 -1
  47. package/dist/image-type.js +45 -2
  48. package/dist/image.d.ts +47 -6
  49. package/dist/image.js +49 -3
  50. package/dist/index.d.ts +3 -2
  51. package/dist/index.js +2 -2
  52. package/dist/render/hinting.js +26 -18
  53. package/dist/render/layout.js +1 -1
  54. package/dist/render/svg.js +1 -1
  55. package/dist/render/unicode.js +1 -9
  56. package/dist/util/bytes.js +9 -0
  57. package/dist/util/resample.js +4 -2
  58. package/dist/version.js +1 -1
  59. package/package.json +25 -2
@@ -0,0 +1,581 @@
1
+ /*!
2
+ * AVIF (AV1 images in HEIF containers, https://aomediacodec.github.io/av1-avif/): the primary item (an AV1 image or a
3
+ * grid of them), its alpha, crop, rotation and mirroring, or the first frame of an image sequence; converted to RGB like
4
+ * libavif converts (its reference path, src/reformat.c, with bilinear chroma upsampling; src/read.c, src/alpha.c), HDR
5
+ * (PQ, HLG) tone mapped. Copyright 2019 Joe Drago, BSD-2-Clause License (see THIRD_PARTY_NOTICES.md)
6
+ */
7
+ import { MAX_PIXELS, checkPixels } from "../util/limits.js";
8
+ import { decodeAV1 } from "./av1/frame.js";
9
+ import { toSRGB, hdrToLinear } from "./hdr.js";
10
+ const fourcc = (d, o) => String.fromCharCode(d[o], d[o + 1], d[o + 2], d[o + 3]);
11
+ function* boxes(d, start, end) {
12
+ const view = new DataView(d.buffer, d.byteOffset, d.byteLength);
13
+ let o = start;
14
+ while (o + 8 <= end) {
15
+ let size = view.getUint32(o);
16
+ const type = fourcc(d, o + 4);
17
+ let header = 8;
18
+ if (size === 1) {
19
+ if (o + 16 > end)
20
+ throw new Error('AVIF: truncated box');
21
+ size = view.getUint32(o + 8) * 2 ** 32 + view.getUint32(o + 12);
22
+ header = 16;
23
+ }
24
+ else if (size === 0)
25
+ size = end - o;
26
+ if (size < header || o + size > end)
27
+ throw new Error(`AVIF: invalid ${type} box`);
28
+ yield { type, start: o + header, end: o + size };
29
+ o += size;
30
+ }
31
+ }
32
+ const child = (d, box, type, offset = 0) => {
33
+ for (const b of boxes(d, box.start + offset, box.end))
34
+ if (b.type === type)
35
+ return b;
36
+ return undefined;
37
+ };
38
+ export function isAVIF(d) {
39
+ if (d.length < 16 || fourcc(d, 4) !== 'ftyp')
40
+ return false;
41
+ const size = new DataView(d.buffer, d.byteOffset, d.byteLength).getUint32(0);
42
+ for (let o = 8; o + 4 <= Math.min(size, d.length); o += o === 8 ? 8 : 4) {
43
+ const brand = fourcc(d, o);
44
+ if (brand === 'avif' || brand === 'avis')
45
+ return true;
46
+ }
47
+ return false;
48
+ }
49
+ function parseMeta(d, meta) {
50
+ const view = new DataView(d.buffer, d.byteOffset, d.byteLength);
51
+ const items = new Map();
52
+ const item = (id) => {
53
+ let it = items.get(id);
54
+ if (!it)
55
+ items.set(id, it = { id, type: '', extents: [], method: 0, props: [], refs: new Map() });
56
+ return it;
57
+ };
58
+ let primary = -1;
59
+ const uint = (o, size) => size === 8 ? view.getUint32(o) * 2 ** 32 + view.getUint32(o + 4) : size === 4 ? view.getUint32(o) : size === 2 ? view.getUint16(o) : size === 1 ? d[o] : 0;
60
+ const idat = child(d, meta, 'idat', 4);
61
+ for (const box of boxes(d, meta.start + 4, meta.end)) {
62
+ const version = d[box.start];
63
+ let o = box.start + 4;
64
+ if (box.type === 'pitm')
65
+ primary = version ? view.getUint32(o) : view.getUint16(o);
66
+ else if (box.type === 'iinf') {
67
+ o += version ? 4 : 2;
68
+ for (const infe of boxes(d, o, box.end)) {
69
+ if (infe.type !== 'infe')
70
+ continue;
71
+ const v = d[infe.start];
72
+ if (v < 2)
73
+ continue;
74
+ let p = infe.start + 4;
75
+ const id = v === 2 ? view.getUint16(p) : view.getUint32(p);
76
+ p += v === 2 ? 2 : 4;
77
+ p += 2;
78
+ item(id).type = fourcc(d, p);
79
+ }
80
+ }
81
+ else if (box.type === 'iloc') {
82
+ const offsetSize = d[o] >> 4, lengthSize = d[o] & 15, baseSize = d[o + 1] >> 4, indexSize = version ? d[o + 1] & 15 : 0;
83
+ o += 2;
84
+ const count = version < 2 ? view.getUint16(o) : view.getUint32(o);
85
+ o += version < 2 ? 2 : 4;
86
+ for (let i = 0; i < count; i++) {
87
+ const id = version < 2 ? view.getUint16(o) : view.getUint32(o);
88
+ o += version < 2 ? 2 : 4;
89
+ const it = item(id);
90
+ if (version) {
91
+ it.method = view.getUint16(o) & 15;
92
+ o += 2;
93
+ }
94
+ o += 2;
95
+ const base = uint(o, baseSize);
96
+ o += baseSize;
97
+ const extents = view.getUint16(o);
98
+ o += 2;
99
+ for (let e = 0; e < extents; e++) {
100
+ o += indexSize;
101
+ const offset = uint(o, offsetSize);
102
+ o += offsetSize;
103
+ const length = uint(o, lengthSize);
104
+ o += lengthSize;
105
+ it.extents.push({ offset: base + offset, length });
106
+ }
107
+ }
108
+ }
109
+ else if (box.type === 'iref') {
110
+ for (const ref of boxes(d, o, box.end)) {
111
+ let p = ref.start;
112
+ const from = version ? view.getUint32(p) : view.getUint16(p);
113
+ p += version ? 4 : 2;
114
+ const count = view.getUint16(p);
115
+ p += 2;
116
+ const to = [];
117
+ for (let i = 0; i < count; i++, p += version ? 4 : 2)
118
+ to.push(version ? view.getUint32(p) : view.getUint16(p));
119
+ item(from).refs.set(ref.type, (item(from).refs.get(ref.type) ?? []).concat(to));
120
+ }
121
+ }
122
+ else if (box.type === 'iprp') {
123
+ const ipco = child(d, box, 'ipco');
124
+ const properties = ipco ? [...boxes(d, ipco.start, ipco.end)] : [];
125
+ for (const ipma of boxes(d, box.start, box.end)) {
126
+ if (ipma.type !== 'ipma')
127
+ continue;
128
+ const v = d[ipma.start], flags = d[ipma.start + 3];
129
+ let p = ipma.start + 4;
130
+ const count = view.getUint32(p);
131
+ p += 4;
132
+ for (let i = 0; i < count; i++) {
133
+ const id = v < 1 ? view.getUint16(p) : view.getUint32(p);
134
+ p += v < 1 ? 2 : 4;
135
+ const n = d[p++];
136
+ for (let k = 0; k < n; k++) {
137
+ let index, essential;
138
+ if (flags & 1) {
139
+ essential = !!(d[p] & 0x80);
140
+ index = view.getUint16(p) & 0x7fff;
141
+ p += 2;
142
+ }
143
+ else {
144
+ essential = !!(d[p] & 0x80);
145
+ index = d[p++] & 0x7f;
146
+ }
147
+ if (index && properties[index - 1])
148
+ item(id).props.push({ box: properties[index - 1], essential });
149
+ }
150
+ }
151
+ }
152
+ }
153
+ }
154
+ return { items, primary, idat };
155
+ }
156
+ function itemData(d, it, idat) {
157
+ const parts = it.extents.map(({ offset, length }) => {
158
+ const base = it.method === 1 ? (idat ? idat.start : 0) : 0, end = it.method === 1 ? idat?.end ?? 0 : d.length;
159
+ if (it.method > 1)
160
+ throw new Error('AVIF: unsupported item construction method');
161
+ const start = base + offset, stop = length ? start + length : end;
162
+ if (start > end || stop > end)
163
+ throw new Error('AVIF: item data outside the file');
164
+ return d.subarray(start, stop);
165
+ });
166
+ if (parts.length === 1)
167
+ return parts[0];
168
+ const out = new Uint8Array(parts.reduce((n, p) => n + p.length, 0));
169
+ let o = 0;
170
+ for (const p of parts) {
171
+ out.set(p, o);
172
+ o += p.length;
173
+ }
174
+ return out;
175
+ }
176
+ const property = (it, type) => it.props.find(p => p.box.type === type)?.box;
177
+ function fromFrame(f) {
178
+ return {
179
+ width: f.hdr.upscaledWidth, height: f.height, bitdepth: f.bitdepth, layout: f.layout, planes: f.planes, strides: f.strides,
180
+ fullRange: f.seq.fullRange, matrix: f.seq.matrixCoefficients, transfer: f.seq.transferCharacteristics,
181
+ primaries: f.seq.colorPrimaries
182
+ };
183
+ }
184
+ function decodeAV1Item(d, it, idat, maxPixels) {
185
+ let data = itemData(d, it, idat);
186
+ const av1C = property(it, 'av1C');
187
+ if (av1C && av1C.end - av1C.start > 4 && (data[0] >> 3 & 15) !== 1) {
188
+ const config = d.subarray(av1C.start + 4, av1C.end);
189
+ const joined = new Uint8Array(config.length + data.length);
190
+ joined.set(config);
191
+ joined.set(data, config.length);
192
+ data = joined;
193
+ }
194
+ const a1op = property(it, 'a1op'), lsel = property(it, 'lsel');
195
+ const layer = lsel ? d[lsel.start] << 8 | d[lsel.start + 1] : 0xffff;
196
+ const frame = decodeAV1(data, 0, data.length, { maxPixels, operatingPoint: a1op ? d[a1op.start] : 0, layer: layer === 0xffff ? -1 : layer });
197
+ if (frame.incomplete) {
198
+ const ispe = property(it, 'ispe');
199
+ const view = new DataView(d.buffer, d.byteOffset, d.byteLength);
200
+ if (!ispe || view.getUint32(ispe.start + 4) !== frame.hdr.upscaledWidth || view.getUint32(ispe.start + 8) !== frame.height)
201
+ throw new Error('AVIF: layered images with inter predicted layers are not supported');
202
+ }
203
+ return fromFrame(frame);
204
+ }
205
+ function decodeGrid(d, it, items, idat, maxPixels, tiles = it.refs.get('dimg') ?? []) {
206
+ const g = itemData(d, it, idat);
207
+ const view = new DataView(g.buffer, g.byteOffset, g.byteLength);
208
+ const wide = g[1] & 1;
209
+ const rows = g[2] + 1, cols = g[3] + 1;
210
+ const width = wide ? view.getUint32(4) : view.getUint16(4), height = wide ? view.getUint32(8) : view.getUint16(6);
211
+ checkPixels(width, height, maxPixels);
212
+ if (tiles.length !== rows * cols)
213
+ throw new Error('AVIF: the grid has the wrong number of tiles');
214
+ if (new Set(tiles).size !== tiles.length)
215
+ throw new Error('AVIF: the grid repeats tiles');
216
+ let out = null;
217
+ for (let r = 0; r < rows; r++) {
218
+ for (let c = 0; c < cols; c++) {
219
+ const tileItem = items.get(tiles[r * cols + c]);
220
+ if (!tileItem || tileItem.type !== 'av01')
221
+ throw new Error('AVIF: invalid grid tile');
222
+ const tile = decodeAV1Item(d, tileItem, idat, maxPixels);
223
+ if (!out) {
224
+ if (tile.width * cols < width || tile.height * rows < height)
225
+ throw new Error('AVIF: the grid\'s tiles are too small');
226
+ out = { ...tile, width, height, planes: [], strides: [] };
227
+ for (let p = 0; p < tile.planes.length; p++) {
228
+ const sx = p && tile.layout < 3 ? 1 : 0, sy = p && tile.layout === 1 ? 1 : 0;
229
+ const stride = (width + sx) >> sx;
230
+ out.strides.push(stride);
231
+ out.planes.push(new Uint16Array(stride * ((height + sy) >> sy)));
232
+ }
233
+ }
234
+ else if (tile.layout !== out.layout || tile.bitdepth !== out.bitdepth)
235
+ throw new Error('AVIF: the grid\'s tiles differ');
236
+ for (let p = 0; p < out.planes.length; p++) {
237
+ const sx = p && out.layout < 3 ? 1 : 0, sy = p && out.layout === 1 ? 1 : 0;
238
+ const tw = (tile.width + sx) >> sx, th = (tile.height + sy) >> sy;
239
+ const x0 = c * tw, y0 = r * th;
240
+ const pw = (width + sx) >> sx, ph = (height + sy) >> sy;
241
+ for (let y = 0; y < th && y0 + y < ph; y++) {
242
+ const n = Math.min(tw, pw - x0);
243
+ if (n <= 0)
244
+ break;
245
+ out.planes[p].set(tile.planes[p].subarray(y * tile.strides[p], y * tile.strides[p] + n), (y0 + y) * out.strides[p] + x0);
246
+ }
247
+ }
248
+ }
249
+ }
250
+ return out;
251
+ }
252
+ function decodeItem(d, it, items, idat, maxPixels) {
253
+ if (it.type === 'av01')
254
+ return decodeAV1Item(d, it, idat, maxPixels);
255
+ if (it.type === 'grid')
256
+ return decodeGrid(d, it, items, idat, maxPixels);
257
+ throw new Error(`AVIF: unsupported item type ${it.type}`);
258
+ }
259
+ function coefficients(matrix) {
260
+ switch (matrix) {
261
+ case 1: return [0.2126, 0.0722];
262
+ case 4: return [0.30, 0.11];
263
+ case 7: return [0.212, 0.087];
264
+ case 9:
265
+ case 10: return [0.2627, 0.0593];
266
+ default: return [0.299, 0.114];
267
+ }
268
+ }
269
+ const TRANSFER_PQ = 16, TRANSFER_HLG = 18;
270
+ const f32 = Math.fround;
271
+ const toByte = (v) => v <= 0 ? 0 : v >= 1 ? 255 : Math.trunc(f32(0.5 + f32(v * 255)));
272
+ function convertRow444(c, j) {
273
+ const { Y, U, V, tableY, out, n } = c, red = c.red, blue = c.blue, gTerm = c.gTerm;
274
+ const yRow = j * c.ys, uvRow = j * c.cs;
275
+ for (let i = 0, p = j * c.width * 4; i < c.width; i++, p += 4) {
276
+ const y = Y[yRow + i], u = U[uvRow + i], v = V[uvRow + i];
277
+ out[p] = red[y * n + v];
278
+ out[p + 1] = toByte(f32(tableY[y] - gTerm[u * n + v]));
279
+ out[p + 2] = blue[y * n + u];
280
+ out[p + 3] = 255;
281
+ }
282
+ }
283
+ function convertRow(c, j) {
284
+ const { width, height, layout, color, identity, ycgco, Y, U, V, cs, sx, sy, tableY, tableUV, out, rgb, unmultiply, cr2, cb2, crg, cbg, kgInverse } = c;
285
+ const uvRow = (j >> sy) * cs, yRow = j * c.ys;
286
+ let adjRow = 0;
287
+ if (color && layout === 1 && !(j === 0 || j === height - 1 && j % 2))
288
+ adjRow = j % 2 ? cs : -cs;
289
+ for (let i = 0, p = j * width * 4; i < width; i++, p += 4) {
290
+ const lum = tableY[Y[yRow + i]];
291
+ out[p + 3] = 255;
292
+ if (!color) {
293
+ if (rgb)
294
+ rgb[p / 4 * 3] = rgb[p / 4 * 3 + 1] = rgb[p / 4 * 3 + 2] = lum;
295
+ else
296
+ out[p] = out[p + 1] = out[p + 2] = toByte(lum);
297
+ continue;
298
+ }
299
+ const o = uvRow + (i >> sx);
300
+ let cb, cr;
301
+ if (layout === 3) {
302
+ cb = tableUV[U[o]];
303
+ cr = tableUV[V[o]];
304
+ }
305
+ else {
306
+ const adjCol = i === 0 || i === width - 1 && i % 2 ? 0 : i % 2 ? 1 : -1;
307
+ cb = f32(f32(f32(f32(tableUV[U[o]] * 0.5625) + f32(tableUV[U[o + adjCol]] * 0.1875)) +
308
+ f32(tableUV[U[o + adjRow]] * 0.1875)) + f32(tableUV[U[o + adjCol + adjRow]] * 0.0625));
309
+ cr = f32(f32(f32(f32(tableUV[V[o]] * 0.5625) + f32(tableUV[V[o + adjCol]] * 0.1875)) +
310
+ f32(tableUV[V[o + adjRow]] * 0.1875)) + f32(tableUV[V[o + adjCol + adjRow]] * 0.0625));
311
+ }
312
+ let r, g, b;
313
+ if (identity) {
314
+ g = lum;
315
+ b = cb;
316
+ r = cr;
317
+ }
318
+ else if (ycgco) {
319
+ const t = lum - cb;
320
+ g = lum + cb;
321
+ b = t - cr;
322
+ r = t + cr;
323
+ }
324
+ else {
325
+ r = f32(lum + f32(cr2 * cr));
326
+ b = f32(lum + f32(cb2 * cb));
327
+ g = f32(lum - f32(f32(2 * f32(f32(crg * cr) + f32(cbg * cb))) * kgInverse));
328
+ }
329
+ if (rgb) {
330
+ const q = p / 4 * 3;
331
+ rgb[q] = r;
332
+ rgb[q + 1] = g;
333
+ rgb[q + 2] = b;
334
+ continue;
335
+ }
336
+ if (unmultiply) {
337
+ const a = unmultiply[p >> 2];
338
+ if (a === 0)
339
+ r = g = b = 0;
340
+ else if (a < 1) {
341
+ r = Math.min(f32((r <= 0 ? 0 : r >= 1 ? 1 : r) / a), 1);
342
+ g = Math.min(f32((g <= 0 ? 0 : g >= 1 ? 1 : g) / a), 1);
343
+ b = Math.min(f32((b <= 0 ? 0 : b >= 1 ? 1 : b) / a), 1);
344
+ }
345
+ }
346
+ out[p] = toByte(r);
347
+ out[p + 1] = toByte(g);
348
+ out[p + 2] = toByte(b);
349
+ }
350
+ }
351
+ function toRgba(y, alpha, toneMapping, premultiplied = false) {
352
+ const { width, height, bitdepth, layout } = y;
353
+ const max = (1 << bitdepth) - 1;
354
+ const [kr, kb] = coefficients(y.matrix).map(f32), kg = f32(f32(1 - kr) - kb);
355
+ const identity = y.matrix === 0, ycgco = y.matrix === 8;
356
+ const biasY = y.fullRange ? 0 : 16 << (bitdepth - 8), rangeY = y.fullRange ? max : 219 << (bitdepth - 8);
357
+ const biasUV = 1 << (bitdepth - 1), rangeUV = y.fullRange ? max : 224 << (bitdepth - 8);
358
+ const tableY = new Float32Array(max + 1), tableUV = new Float32Array(max + 1);
359
+ for (let i = 0; i <= max; i++) {
360
+ tableY[i] = (i - biasY) / rangeY;
361
+ tableUV[i] = identity ? tableY[i] : (i - biasUV) / rangeUV;
362
+ }
363
+ let out = new Uint8Array(width * height * 4);
364
+ const hdr = y.transfer === TRANSFER_PQ || y.transfer === TRANSFER_HLG;
365
+ const rgb = hdr ? new Float32Array(width * height * 3) : null;
366
+ const Y = y.planes[0], ys = y.strides[0];
367
+ const color = layout !== 0 && y.planes.length === 3;
368
+ const U = y.planes[1], V = y.planes[2], cs = y.strides[1];
369
+ const sx = layout < 3 ? 1 : 0, sy = layout === 1 ? 1 : 0;
370
+ const alphas = alpha ? new Float32Array(width * height).fill(1) : null;
371
+ if (alpha && alphas) {
372
+ const A = alpha.planes[0], as = alpha.strides[0], amax = (1 << alpha.bitdepth) - 1;
373
+ const lo = 16 << (alpha.bitdepth - 8), span = 219 << (alpha.bitdepth - 8);
374
+ for (let j = 0; j < Math.min(height, alpha.height); j++) {
375
+ for (let i = 0; i < Math.min(width, alpha.width); i++) {
376
+ let v = Math.min(A[j * as + i], amax);
377
+ if (!alpha.fullRange)
378
+ v = Math.min(amax, Math.max(0, Math.trunc(((v - lo) * amax + (span >> 1)) / span)));
379
+ alphas[j * width + i] = v / amax;
380
+ }
381
+ }
382
+ }
383
+ const unmultiply = premultiplied && !hdr ? alphas : null;
384
+ const c = {
385
+ width, height, layout, color, identity, ycgco, Y, U, V, ys, cs, sx, sy, tableY, tableUV, out, rgb, unmultiply,
386
+ cr2: f32(2 * f32(1 - kr)), cb2: f32(2 * f32(1 - kb)), crg: f32(kr * f32(1 - kr)), cbg: f32(kb * f32(1 - kb)), kgInverse: 1 / kg,
387
+ n: max + 1, red: null, blue: null, gTerm: null
388
+ };
389
+ const n = max + 1;
390
+ if (layout === 3 && color && !identity && !ycgco && !rgb && !unmultiply && n * n * 2 <= width * height) {
391
+ const red = c.red = new Uint8Array(n * n), blue = c.blue = new Uint8Array(n * n), gTerm = c.gTerm = new Float32Array(n * n);
392
+ for (let v = 0; v < n; v++) {
393
+ const rTerm = f32(c.cr2 * tableUV[v]), bTerm = f32(c.cb2 * tableUV[v]);
394
+ for (let y = 0; y < n; y++) {
395
+ red[y * n + v] = toByte(f32(tableY[y] + rTerm));
396
+ blue[y * n + v] = toByte(f32(tableY[y] + bTerm));
397
+ }
398
+ }
399
+ for (let u = 0; u < n; u++) {
400
+ const cbTerm = f32(c.cbg * tableUV[u]);
401
+ for (let v = 0; v < n; v++)
402
+ gTerm[u * n + v] = f32(f32(2 * f32(f32(c.crg * tableUV[v]) + cbTerm)) * c.kgInverse);
403
+ }
404
+ for (let j = 0; j < height; j++)
405
+ convertRow444(c, j);
406
+ }
407
+ else
408
+ for (let j = 0; j < height; j++)
409
+ convertRow(c, j);
410
+ if (rgb)
411
+ out = toSRGB(hdrToLinear(rgb, y.transfer, y.primaries), toneMapping);
412
+ if (alphas)
413
+ for (let i = 0; i < alphas.length; i++)
414
+ out[i * 4 + 3] = Math.round(alphas[i] * 255);
415
+ return out;
416
+ }
417
+ export function decode(d, maxPixels = MAX_PIXELS, toneMapping = 'reinhard') {
418
+ if (!isAVIF(d))
419
+ throw new Error('AVIF: invalid header');
420
+ let meta, moov;
421
+ for (const box of boxes(d, 0, d.length)) {
422
+ if (box.type === 'meta')
423
+ meta = box;
424
+ else if (box.type === 'moov')
425
+ moov = box;
426
+ }
427
+ if (meta) {
428
+ const { items, primary, idat } = parseMeta(d, meta);
429
+ const it = items.get(primary);
430
+ if (it) {
431
+ const alphaOf = (id) => {
432
+ for (const candidate of items.values()) {
433
+ if (!(candidate.refs.get('auxl') ?? []).includes(id))
434
+ continue;
435
+ const auxC = property(candidate, 'auxC');
436
+ const type = auxC ? String.fromCharCode(...d.subarray(auxC.start + 4, auxC.end)).replace(/\0.*$/s, '') : '';
437
+ if (type === 'urn:mpeg:mpegB:cicp:systems:auxiliary:alpha' || type === 'urn:mpeg:hevc:2015:auxid:1')
438
+ return candidate;
439
+ }
440
+ return undefined;
441
+ };
442
+ const alphaItem = alphaOf(primary);
443
+ const color = decodeItem(d, it, items, idat, maxPixels);
444
+ applyColr(d, it, color);
445
+ let alpha = alphaItem ? decodeItem(d, alphaItem, items, idat, maxPixels) : null;
446
+ if (!alphaItem && it.type === 'grid') {
447
+ const tiles = (it.refs.get('dimg') ?? []).map(alphaOf);
448
+ if (tiles.length && tiles.every(t => t))
449
+ alpha = decodeGrid(d, it, items, idat, maxPixels, tiles.map(t => t.id));
450
+ }
451
+ let pixels = toRgba(color, alpha, toneMapping, alphaItem && (it.refs.get('prem') ?? []).includes(alphaItem.id));
452
+ let { width, height } = color;
453
+ for (const { box } of it.props) {
454
+ if (box.type === 'clap')
455
+ ({ width, height, pixels } = clap(d, box, width, height, pixels));
456
+ else if (box.type === 'irot')
457
+ ({ width, height, pixels } = rotate(pixels, width, height, d[box.start] & 3));
458
+ else if (box.type === 'imir')
459
+ pixels = mirror(pixels, width, height, d[box.start] & 1);
460
+ }
461
+ return { width, height, pixels };
462
+ }
463
+ }
464
+ if (moov)
465
+ return decodeSequence(d, moov, maxPixels, toneMapping);
466
+ throw new Error('AVIF: no image');
467
+ }
468
+ function applyColr(d, it, yuv) {
469
+ for (const { box } of it.props) {
470
+ if (box.type !== 'colr' || fourcc(d, box.start) !== 'nclx')
471
+ continue;
472
+ const view = new DataView(d.buffer, d.byteOffset, d.byteLength);
473
+ yuv.primaries = view.getUint16(box.start + 4);
474
+ yuv.transfer = view.getUint16(box.start + 6);
475
+ yuv.matrix = view.getUint16(box.start + 8);
476
+ yuv.fullRange = !!(d[box.start + 10] & 0x80);
477
+ }
478
+ }
479
+ function clap(d, box, width, height, pixels) {
480
+ const view = new DataView(d.buffer, d.byteOffset, d.byteLength);
481
+ const v = [0, 1, 2, 3, 4, 5, 6, 7].map(i => view.getInt32(box.start + i * 4));
482
+ const [wN, wD, hN, hD, xN, xD, yN, yD] = v;
483
+ if (wD <= 0 || hD <= 0 || xD <= 0 || yD <= 0)
484
+ throw new Error('AVIF: invalid clap');
485
+ const cw = wN / wD, ch = hN / hD;
486
+ const left = xN / xD + (width - 1) / 2 - (cw - 1) / 2, top = yN / yD + (height - 1) / 2 - (ch - 1) / 2;
487
+ if (!Number.isInteger(cw) || !Number.isInteger(ch) || !Number.isInteger(left) || !Number.isInteger(top) ||
488
+ left < 0 || top < 0 || cw < 1 || ch < 1 || left + cw > width || top + ch > height)
489
+ throw new Error('AVIF: invalid clap');
490
+ const out = new Uint8Array(cw * ch * 4);
491
+ for (let y = 0; y < ch; y++)
492
+ out.set(pixels.subarray(((top + y) * width + left) * 4, ((top + y) * width + left + cw) * 4), y * cw * 4);
493
+ return { width: cw, height: ch, pixels: out };
494
+ }
495
+ function rotate(pixels, width, height, steps) {
496
+ if (!steps)
497
+ return { width, height, pixels };
498
+ const src = new Uint32Array(pixels.buffer, pixels.byteOffset, width * height);
499
+ const w = steps === 2 ? width : height, h = steps === 2 ? height : width;
500
+ const out = new Uint8Array(w * h * 4), dst = new Uint32Array(out.buffer);
501
+ for (let y = 0; y < h; y++) {
502
+ for (let x = 0; x < w; x++) {
503
+ let sx, sy;
504
+ if (steps === 1) {
505
+ sx = width - 1 - y;
506
+ sy = x;
507
+ }
508
+ else if (steps === 2) {
509
+ sx = width - 1 - x;
510
+ sy = height - 1 - y;
511
+ }
512
+ else {
513
+ sx = y;
514
+ sy = height - 1 - x;
515
+ }
516
+ dst[y * w + x] = src[sy * width + sx];
517
+ }
518
+ }
519
+ return { width: w, height: h, pixels: out };
520
+ }
521
+ function mirror(pixels, width, height, axis) {
522
+ const src = new Uint32Array(pixels.buffer, pixels.byteOffset, width * height);
523
+ const out = new Uint8Array(width * height * 4), dst = new Uint32Array(out.buffer);
524
+ for (let y = 0; y < height; y++) {
525
+ for (let x = 0; x < width; x++)
526
+ dst[y * width + x] = axis ? src[y * width + width - 1 - x] : src[(height - 1 - y) * width + x];
527
+ }
528
+ return out;
529
+ }
530
+ function decodeSequence(d, moov, maxPixels, toneMapping) {
531
+ const view = new DataView(d.buffer, d.byteOffset, d.byteLength);
532
+ const tracks = [];
533
+ for (const trak of boxes(d, moov.start, moov.end)) {
534
+ if (trak.type !== 'trak')
535
+ continue;
536
+ const tkhd = child(d, trak, 'tkhd');
537
+ const id = tkhd ? view.getUint32(tkhd.start + (d[tkhd.start] ? 20 : 12)) : 0;
538
+ const tref = child(d, trak, 'tref');
539
+ const auxlBox = tref && child(d, tref, 'auxl');
540
+ const auxl = [];
541
+ if (auxlBox)
542
+ for (let o = auxlBox.start; o + 4 <= auxlBox.end; o += 4)
543
+ auxl.push(view.getUint32(o));
544
+ const mdia = child(d, trak, 'mdia');
545
+ const hdlr = mdia && child(d, mdia, 'hdlr');
546
+ const minf = mdia && child(d, mdia, 'minf');
547
+ const stbl = minf && child(d, minf, 'stbl');
548
+ if (!hdlr || !stbl)
549
+ continue;
550
+ const handler = fourcc(d, hdlr.start + 8);
551
+ const stsd = child(d, stbl, 'stsd'), stsz = child(d, stbl, 'stsz');
552
+ const stco = child(d, stbl, 'stco') ?? child(d, stbl, 'co64');
553
+ if (!stsd || !stsz || !stco)
554
+ continue;
555
+ const entry = [...boxes(d, stsd.start + 8, stsd.end)][0];
556
+ if (!entry || entry.type !== 'av01')
557
+ continue;
558
+ const av1C = child(d, entry, 'av1C', 78);
559
+ const size = view.getUint32(stsz.start + 4) || view.getUint32(stsz.start + 12);
560
+ const offset = stco.type === 'stco' ? view.getUint32(stco.start + 8) : view.getUint32(stco.start + 8) * 2 ** 32 + view.getUint32(stco.start + 12);
561
+ if (offset + size > d.length)
562
+ throw new Error('AVIF: sample outside the file');
563
+ tracks.push({ id, handler, auxl, sample: d.subarray(offset, offset + size), config: av1C && av1C.end - av1C.start > 4 ? d.subarray(av1C.start + 4, av1C.end) : null });
564
+ }
565
+ const colorTrack = tracks.find(t => t.handler === 'pict' || t.handler === 'vide') ?? tracks[0];
566
+ if (!colorTrack)
567
+ throw new Error('AVIF: no image');
568
+ const alphaTrack = tracks.find(t => t !== colorTrack && (t.auxl.includes(colorTrack.id) || t.handler === 'auxv'));
569
+ const frame = (t) => {
570
+ let data = t.sample;
571
+ if (t.config && (data[0] >> 3 & 15) !== 1) {
572
+ const joined = new Uint8Array(t.config.length + data.length);
573
+ joined.set(t.config);
574
+ joined.set(data, t.config.length);
575
+ data = joined;
576
+ }
577
+ return fromFrame(decodeAV1(data, 0, data.length, { maxPixels }));
578
+ };
579
+ const color = frame(colorTrack);
580
+ return { width: color.width, height: color.height, pixels: toRgba(color, alphaTrack ? frame(alphaTrack) : null, toneMapping) };
581
+ }