imagescript 3.2.1 → 3.3.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 +8 -3
- package/THIRD_PARTY_NOTICES.md +131 -0
- package/dist/animation.d.ts +7 -0
- package/dist/animation.js +21 -11
- package/dist/codecs/crc.js +5 -0
- package/dist/codecs/gif.js +10 -35
- package/dist/codecs/jpeg.js +9 -27
- package/dist/codecs/png.js +22 -10
- package/dist/codecs/tga.js +3 -1
- package/dist/codecs/tiff.js +7 -2
- package/dist/codecs/vp8.js +3 -1
- package/dist/codecs/vp8l.js +126 -58
- package/dist/codecs/webp.js +11 -9
- 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.d.ts +42 -7
- package/dist/image.js +217 -110
- 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 +12 -4
- 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 +101 -22
- package/dist/render/text.js +373 -103
- package/dist/render/unicode-data.js +63 -0
- package/dist/render/unicode.js +58 -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 +31 -0
- package/dist/util/limits.js +34 -0
- package/dist/util/options.js +7 -0
- package/dist/util/resample.js +122 -5
- 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 +1 -1
package/README.md
CHANGED
|
@@ -28,12 +28,15 @@ deno add jsr:@matmen/imagescript # Deno (npm:imagescript works too)
|
|
|
28
28
|
- WebPs (lossy, lossless and with alpha; bit-exact with libwebp)
|
|
29
29
|
- TGAs (color mapped, truecolor and greyscale; uncompressed and run length encoded)
|
|
30
30
|
- JPEGs, TIFFs, PNGs and WebPs are rotated as their Exif (or, for PNGs, XMP) orientation says
|
|
31
|
+
- images larger than 268 megapixels (`maxPixels`) are rejected before decoding, so small files declaring huge images
|
|
32
|
+
can't exhaust the memory
|
|
31
33
|
- [Decoding animations](https://imagescript.matmen.dev/classes/Animation.html#decode) (GIF, APNG and WebP) with all
|
|
32
34
|
frames, durations and disposal modes
|
|
33
35
|
- [Rendering SVGs](https://imagescript.matmen.dev/classes/Image.html#rendersvg) (shapes, paths, gradients, strokes, clip paths,
|
|
34
36
|
masks, CSS; no text, images or filters)
|
|
35
|
-
- [Rendering vector fonts](https://imagescript.matmen.dev/classes/Image.html#rendertext) (TrueType and OpenType, with
|
|
36
|
-
|
|
37
|
+
- [Rendering vector fonts](https://imagescript.matmen.dev/classes/Image.html#rendertext) (TrueType and OpenType, with
|
|
38
|
+
complex text shaping in every script, right to left and bidirectional text, outlines, TrueType hinting, fallback
|
|
39
|
+
fonts and color emoji)
|
|
37
40
|
- [Resizing](https://imagescript.matmen.dev/classes/Image.html#resize) (bilinear, bicubic, area averaging and nearest neighbor)
|
|
38
41
|
- Image manipulation functions ([crop](https://imagescript.matmen.dev/classes/Image.html#crop)
|
|
39
42
|
, [rotate](https://imagescript.matmen.dev/classes/Image.html#rotate)
|
|
@@ -101,7 +104,9 @@ The JPEG codec is based in part on the work of the Independent JPEG Group (libjp
|
|
|
101
104
|
[pdf.js](https://github.com/mozilla/pdf.js), the glyph rasterizer is translated from
|
|
102
105
|
[font-rs](https://github.com/raphlinus/font-rs). The WebP codecs follow [RFC 9649](https://www.rfc-editor.org/rfc/rfc9649) and [RFC 6386](https://www.rfc-editor.org/rfc/rfc6386)
|
|
103
106
|
and reproduce [libwebp](https://chromium.googlesource.com/webm/libwebp)'s color conversion, the TrueType hinting follows
|
|
104
|
-
[FreeType](https://freetype.org)'s interpreter (portions of this software are copyright © 2026 The FreeType Project)
|
|
107
|
+
[FreeType](https://freetype.org)'s interpreter (portions of this software are copyright © 2026 The FreeType Project),
|
|
108
|
+
the text shaping is ported from [HarfBuzz](https://github.com/harfbuzz/harfbuzz) and uses data of the
|
|
109
|
+
[Unicode Character Database](https://www.unicode.org/ucd/).
|
|
105
110
|
See [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md) for their licenses.
|
|
106
111
|
|
|
107
112
|
---
|
package/THIRD_PARTY_NOTICES.md
CHANGED
|
@@ -14,6 +14,10 @@ following projects, under their own licenses. Each derived file says so in its h
|
|
|
14
14
|
| [RFC 6386](https://www.rfc-editor.org/rfc/rfc6386) (VP8 Data Format and Decoding Guide, with the libvpx reference decoder) | `src/codecs/vp8-tables.ts` (probability and quantizer tables), `src/codecs/vp8.ts` (decoding procedures) | BSD-3-Clause |
|
|
15
15
|
| [libwebp](https://chromium.googlesource.com/webm/libwebp) | `src/codecs/vp8.ts` (YUV to RGB conversion, "fancy" chroma upsampling), `src/codecs/webp.ts` (animation frame blending) | BSD-3-Clause |
|
|
16
16
|
| [FreeType](https://freetype.org) | `src/render/hinting.ts` (behavior and parts of the logic of the TrueType interpreter) | FreeType License |
|
|
17
|
+
| [Pillow](https://github.com/python-pillow/Pillow) | `src/util/resample.ts` (filter coefficients, box, bilinear and bicubic filters) | MIT-CMU |
|
|
18
|
+
| [HarfBuzz](https://github.com/harfbuzz/harfbuzz) | `src/render/buffer.ts`, `src/render/layout.ts`, `src/render/shape.ts`, `src/render/shapers/*` (OpenType shaping: buffer, GSUB/GPOS, normalization, fallback positioning, the script shapers and syllable grammars), `scripts/unicode.js` (shaping category tables) | Old MIT |
|
|
19
|
+
| [Universal Shaping Engine data](https://github.com/harfbuzz/harfbuzz/tree/main/src/ms-use) by Microsoft | `scripts/ms-use` (category overrides, invalid vowel sequences), the tables generated from them in `src/render/unicode-data.ts` | MIT |
|
|
20
|
+
| [Unicode Character Database](https://www.unicode.org/ucd/) | `src/render/unicode-data.ts` (character properties, generated by `scripts/unicode.js`) | Unicode License v3 |
|
|
17
21
|
|
|
18
22
|
## fflate, Fast CRC32 in JavaScript
|
|
19
23
|
|
|
@@ -154,3 +158,130 @@ Where the specification leaves details open, its behavior and parts of its logic
|
|
|
154
158
|
interpolation of untouched points (IUP), the handling of near-perpendicular freedom and projection vectors, and the
|
|
155
159
|
tolerance of invalid references. FreeType is used under the FreeType License, included as
|
|
156
160
|
[licenses/FTL.txt](licenses/FTL.txt).
|
|
161
|
+
|
|
162
|
+
## Pillow
|
|
163
|
+
|
|
164
|
+
```
|
|
165
|
+
The Python Imaging Library (PIL) is
|
|
166
|
+
|
|
167
|
+
Copyright © 1997-2011 by Secret Labs AB
|
|
168
|
+
Copyright © 1995-2011 by Fredrik Lundh and contributors
|
|
169
|
+
|
|
170
|
+
Pillow is the friendly PIL fork. It is
|
|
171
|
+
|
|
172
|
+
Copyright © 2010 by Jeffrey 'Alex' Clark and contributors
|
|
173
|
+
|
|
174
|
+
Like PIL, Pillow is licensed under the open source MIT-CMU License:
|
|
175
|
+
|
|
176
|
+
By obtaining, using, and/or copying this software and/or its associated
|
|
177
|
+
documentation, you agree that you have read, understood, and will comply
|
|
178
|
+
with the following terms and conditions:
|
|
179
|
+
|
|
180
|
+
Permission to use, copy, modify and distribute this software and its
|
|
181
|
+
documentation for any purpose and without fee is hereby granted,
|
|
182
|
+
provided that the above copyright notice appears in all copies, and that
|
|
183
|
+
both that copyright notice and this permission notice appear in supporting
|
|
184
|
+
documentation, and that the name of Secret Labs AB or the author not be
|
|
185
|
+
used in advertising or publicity pertaining to distribution of the software
|
|
186
|
+
without specific, written prior permission.
|
|
187
|
+
|
|
188
|
+
SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
|
|
189
|
+
SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
|
|
190
|
+
IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR BE LIABLE FOR ANY SPECIAL,
|
|
191
|
+
INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
192
|
+
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
|
193
|
+
OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
194
|
+
PERFORMANCE OF THIS SOFTWARE.
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
The resampling in `src/util/resample.ts` computes its filter coefficients as Pillow's `precompute_coeffs` does (the
|
|
198
|
+
filter stretched by the downscaling factor, the source range rounded around each output pixel's center, the weights
|
|
199
|
+
normalized) and uses Pillow's box, bilinear and bicubic (a = -0.5) filter functions. The integer passes, the fast
|
|
200
|
+
paths and the premultiplied alpha handling are ImageScript's own.
|
|
201
|
+
|
|
202
|
+
## Unicode Character Database
|
|
203
|
+
|
|
204
|
+
Copyright © 1991-2026 Unicode, Inc.
|
|
205
|
+
|
|
206
|
+
`src/render/unicode-data.ts` is generated by `scripts/unicode.js` from data files of the Unicode Character Database
|
|
207
|
+
(character properties for the bidirectional algorithm, line breaking, text segmentation and shaping). They are used
|
|
208
|
+
under the Unicode License v3, included as [licenses/Unicode-3.0.txt](licenses/Unicode-3.0.txt). The bidirectional
|
|
209
|
+
algorithm (`src/render/bidi.ts`) and the line breaking (`src/render/linebreak.ts`) are written after UAX #9 and
|
|
210
|
+
UAX #14.
|
|
211
|
+
|
|
212
|
+
## HarfBuzz
|
|
213
|
+
|
|
214
|
+
The shaping engine is ported from HarfBuzz 14.6.0; its license is included as
|
|
215
|
+
[licenses/HarfBuzz.txt](licenses/HarfBuzz.txt). The copyright holders of the ported files are listed in the headers
|
|
216
|
+
of the files derived from them.
|
|
217
|
+
|
|
218
|
+
```
|
|
219
|
+
HarfBuzz is licensed under the so-called "Old MIT" license. Details follow.
|
|
220
|
+
For parts of HarfBuzz that are licensed under different licenses see individual
|
|
221
|
+
files names COPYING in subdirectories where applicable.
|
|
222
|
+
|
|
223
|
+
Copyright © 2010-2022 Google, Inc.
|
|
224
|
+
Copyright © 2015-2020 Ebrahim Byagowi
|
|
225
|
+
Copyright © 2019,2020 Facebook, Inc.
|
|
226
|
+
Copyright © 2012,2015 Mozilla Foundation
|
|
227
|
+
Copyright © 2011 Codethink Limited
|
|
228
|
+
Copyright © 2008,2010 Nokia Corporation and/or its subsidiary(-ies)
|
|
229
|
+
Copyright © 2009 Keith Stribley
|
|
230
|
+
Copyright © 2011 Martin Hosken and SIL International
|
|
231
|
+
Copyright © 2007 Chris Wilson
|
|
232
|
+
Copyright © 2005,2006,2020,2021,2022,2023 Behdad Esfahbod
|
|
233
|
+
Copyright © 2004,2007,2008,2009,2010,2013,2021,2022,2023 Red Hat, Inc.
|
|
234
|
+
Copyright © 1998-2005 David Turner and Werner Lemberg
|
|
235
|
+
Copyright © 2016 Igalia S.L.
|
|
236
|
+
Copyright © 2022 Matthias Clasen
|
|
237
|
+
Copyright © 2018,2021 Khaled Hosny
|
|
238
|
+
Copyright © 2018,2019,2020 Adobe, Inc
|
|
239
|
+
Copyright © 2013-2015 Alexei Podtelezhnikov
|
|
240
|
+
|
|
241
|
+
For full copyright notices consult the individual files in the package.
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
Permission is hereby granted, without written agreement and without
|
|
245
|
+
license or royalty fees, to use, copy, modify, and distribute this
|
|
246
|
+
software and its documentation for any purpose, provided that the
|
|
247
|
+
above copyright notice and the following two paragraphs appear in
|
|
248
|
+
all copies of this software.
|
|
249
|
+
|
|
250
|
+
IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
|
251
|
+
DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
|
252
|
+
ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
|
253
|
+
IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
|
254
|
+
DAMAGE.
|
|
255
|
+
|
|
256
|
+
THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
|
257
|
+
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
258
|
+
FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
|
259
|
+
ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
|
260
|
+
PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
## Universal Shaping Engine data
|
|
264
|
+
|
|
265
|
+
```
|
|
266
|
+
MIT License
|
|
267
|
+
|
|
268
|
+
Copyright (c) Microsoft Corporation.
|
|
269
|
+
|
|
270
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
271
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
272
|
+
in the Software without restriction, including without limitation the rights
|
|
273
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
274
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
275
|
+
furnished to do so, subject to the following conditions:
|
|
276
|
+
|
|
277
|
+
The above copyright notice and this permission notice shall be included in all
|
|
278
|
+
copies or substantial portions of the Software.
|
|
279
|
+
|
|
280
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
281
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
282
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
283
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
284
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
285
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
286
|
+
SOFTWARE
|
|
287
|
+
```
|
package/dist/animation.d.ts
CHANGED
|
@@ -11,6 +11,12 @@ export interface AnimationOptions {
|
|
|
11
11
|
export interface AnimationDecodeOptions {
|
|
12
12
|
/** Whether to stop decoding after the first frame. Default: `false` */
|
|
13
13
|
onlyFirstFrame?: boolean;
|
|
14
|
+
/**
|
|
15
|
+
* The most pixels to decode, of all frames together (every frame is a full canvas): larger animations throw a
|
|
16
|
+
* RangeError before anything that size is allocated, so small files declaring huge animations (decompression
|
|
17
|
+
* bombs) can't exhaust the memory. Default: `268402689` (16383², like sharp), `Infinity` for no limit
|
|
18
|
+
*/
|
|
19
|
+
maxPixels?: number;
|
|
14
20
|
}
|
|
15
21
|
/** Options of {@link Animation.encodeWebP}, and those all animation encoders have */
|
|
16
22
|
export interface AnimationEncodeOptions {
|
|
@@ -68,6 +74,7 @@ export declare class Animation extends Array<Frame> {
|
|
|
68
74
|
get height(): number;
|
|
69
75
|
/** The animation's duration (in ms) */
|
|
70
76
|
get duration(): number;
|
|
77
|
+
/** A short description for debugging, e.g. `Animation<64x64x1000ms>` */
|
|
71
78
|
toString(): string;
|
|
72
79
|
/**
|
|
73
80
|
* Returns a new animation of the same class containing a range of this one's frames
|
package/dist/animation.js
CHANGED
|
@@ -7,7 +7,8 @@ import { Frame } from "./frame.js";
|
|
|
7
7
|
import { ImageType } from "./image-type.js";
|
|
8
8
|
import { optimize } from "./util/optimize.js";
|
|
9
9
|
import { resolveMetadata, pngText, exifData, gifComments } from "./metadata.js";
|
|
10
|
-
import { isOptions } from "./util/options.js";
|
|
10
|
+
import { isOptions, finite } from "./util/options.js";
|
|
11
|
+
import { MAX_PIXELS, decoding } from "./util/limits.js";
|
|
11
12
|
const toPlays = (loopCount) => loopCount < 0 ? 0 : loopCount + 1;
|
|
12
13
|
const fromPlays = (plays) => plays === 0 ? -1 : plays - 1;
|
|
13
14
|
function canvasFrames(width, height, frames) {
|
|
@@ -27,7 +28,7 @@ export class Animation extends Array {
|
|
|
27
28
|
for (let i = 0; i < this.length; i++)
|
|
28
29
|
if (!(this[i] instanceof Frame))
|
|
29
30
|
throw new TypeError(`Frame ${i} is not an instance of Frame`);
|
|
30
|
-
if (loopCount < -1
|
|
31
|
+
if (finite(loopCount, 'loop count') < -1)
|
|
31
32
|
throw new RangeError('Invalid loop count');
|
|
32
33
|
this.loopCount = loopCount;
|
|
33
34
|
}
|
|
@@ -73,7 +74,6 @@ export class Animation extends Array {
|
|
|
73
74
|
return new Class(Array.prototype.slice.call(this, start, end), this.loopCount);
|
|
74
75
|
}
|
|
75
76
|
resize(width, height, modeOrOptions) {
|
|
76
|
-
const mode = (isOptions(modeOrOptions) ? modeOrOptions.mode : modeOrOptions) ?? Image.RESIZE_BILINEAR;
|
|
77
77
|
const originalWidth = this.width, originalHeight = this.height;
|
|
78
78
|
if (width === Image.RESIZE_AUTO && height === Image.RESIZE_AUTO)
|
|
79
79
|
throw new Error('RESIZE_AUTO can only be used for either width or height, not for both');
|
|
@@ -85,7 +85,7 @@ export class Animation extends Array {
|
|
|
85
85
|
for (const frame of this) {
|
|
86
86
|
const left = Math.round(frame.xOffset * sx), top = Math.round(frame.yOffset * sy);
|
|
87
87
|
const right = Math.round((frame.xOffset + frame.width) * sx), bottom = Math.round((frame.yOffset + frame.height) * sy);
|
|
88
|
-
Image.prototype.resize.call(frame, Math.max(1, right - left), Math.max(1, bottom - top),
|
|
88
|
+
Image.prototype.resize.call(frame, Math.max(1, right - left), Math.max(1, bottom - top), modeOrOptions);
|
|
89
89
|
frame.xOffset = left;
|
|
90
90
|
frame.yOffset = top;
|
|
91
91
|
}
|
|
@@ -170,27 +170,37 @@ export class Animation extends Array {
|
|
|
170
170
|
}));
|
|
171
171
|
}
|
|
172
172
|
static async decode(input, onlyFirstFrameOrOptions = false) {
|
|
173
|
-
|
|
173
|
+
return decoding(() => Animation.__decode__(input, onlyFirstFrameOrOptions));
|
|
174
|
+
}
|
|
175
|
+
static async __decode__(input, onlyFirstFrameOrOptions) {
|
|
176
|
+
const { onlyFirstFrame: onlyExtractFirstFrame = false, maxPixels = MAX_PIXELS } = isOptions(onlyFirstFrameOrOptions) ? onlyFirstFrameOrOptions : { onlyFirstFrame: onlyFirstFrameOrOptions };
|
|
174
177
|
const data = view(input);
|
|
175
178
|
const type = ImageType.getType(data);
|
|
176
179
|
if (type === 'gif')
|
|
177
|
-
return Animation.__fromGIF__(data, onlyExtractFirstFrame, Animation);
|
|
180
|
+
return Animation.__fromGIF__(data, onlyExtractFirstFrame, Animation, maxPixels);
|
|
178
181
|
if (type === 'webp') {
|
|
179
|
-
const decoded = webp.decodeAnimation(data, onlyExtractFirstFrame);
|
|
182
|
+
const decoded = webp.decodeAnimation(data, onlyExtractFirstFrame, maxPixels);
|
|
180
183
|
const frames = canvasFrames(decoded.width, decoded.height, webp.composite(decoded));
|
|
181
184
|
return new Animation(frames, fromPlays(decoded.loopCount));
|
|
182
185
|
}
|
|
186
|
+
if (type === 'png' && !png.isAnimated(data)) {
|
|
187
|
+
const image = await Image.decode(data, { maxPixels, applyOrientation: false });
|
|
188
|
+
return new Animation(canvasFrames(image.width, image.height, [{ pixels: image.bitmap, duration: 0 }]), -1);
|
|
189
|
+
}
|
|
183
190
|
if (type === 'png') {
|
|
184
|
-
const decoded = await png.decodeAnimation(data, onlyExtractFirstFrame);
|
|
191
|
+
const decoded = await png.decodeAnimation(data, onlyExtractFirstFrame, maxPixels);
|
|
185
192
|
const frames = canvasFrames(decoded.width, decoded.height, png.compositeAnimation(decoded));
|
|
186
193
|
return new Animation(frames, decoded.frames.length > 1 ? fromPlays(decoded.plays) : -1);
|
|
187
194
|
}
|
|
188
195
|
if (type)
|
|
189
|
-
return new Animation([Frame.from(await Image.decode(data), 0)]);
|
|
196
|
+
return new Animation([Frame.from(await Image.decode(data, { maxPixels }), 0)]);
|
|
190
197
|
throw new Error('Unsupported image type');
|
|
191
198
|
}
|
|
192
|
-
static __fromGIF__(data, onlyExtractFirstFrame, Class) {
|
|
193
|
-
|
|
199
|
+
static __fromGIF__(data, onlyExtractFirstFrame, Class, maxPixels = MAX_PIXELS) {
|
|
200
|
+
return decoding(() => Animation.__gifFrames__(data, onlyExtractFirstFrame, Class, maxPixels));
|
|
201
|
+
}
|
|
202
|
+
static __gifFrames__(data, onlyExtractFirstFrame, Class, maxPixels) {
|
|
203
|
+
const decoded = gifCodec.decode(data, onlyExtractFirstFrame, maxPixels);
|
|
194
204
|
const frames = gifCodec.composite(decoded).map(({ pixels, delay }) => ({ pixels, duration: 10 * delay }));
|
|
195
205
|
return new Class(canvasFrames(decoded.width, decoded.height, frames), decoded.loopCount);
|
|
196
206
|
}
|
package/dist/codecs/crc.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* Slice-by-16 CRC-32, derived from "Fast CRC32 in JavaScript" (https://gist.github.com/101arrowz/e58695f7ccfdf74f60ba22018093edea)
|
|
3
3
|
* Copyright (c) 2021 Arjun Barrett, MIT License (see THIRD_PARTY_NOTICES.md)
|
|
4
4
|
*/
|
|
5
|
+
import { nodeZlib } from "./zlib.js";
|
|
5
6
|
const TABLE = new Int32Array(16 * 256);
|
|
6
7
|
for (let n = 0; n < 256; n++) {
|
|
7
8
|
let c = n;
|
|
@@ -14,7 +15,11 @@ for (let n = 0; n < 256; n++) {
|
|
|
14
15
|
for (let k = 256; k < TABLE.length; k += 256)
|
|
15
16
|
c = TABLE[k + n] = TABLE[c & 0xff] ^ c >>> 8;
|
|
16
17
|
}
|
|
18
|
+
const native = nodeZlib && nodeZlib.crc32 ? nodeZlib.crc32.bind(nodeZlib) : null;
|
|
19
|
+
const NATIVE_MIN = 64;
|
|
17
20
|
export function crc32(buffer) {
|
|
21
|
+
if (native && buffer.length >= NATIVE_MIN)
|
|
22
|
+
return native(buffer) >>> 0;
|
|
18
23
|
let crc = -1, i = 0;
|
|
19
24
|
for (const end = buffer.length - 16; i <= end; i += 16) {
|
|
20
25
|
crc = TABLE[3840 + ((buffer[i] ^ crc) & 0xff)] ^ TABLE[3584 + ((buffer[i + 1] ^ crc >> 8) & 0xff)]
|
package/dist/codecs/gif.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
|
+
import { ByteWriter } from "../util/bytes.js";
|
|
1
2
|
import { quantize } from "./quantize.js";
|
|
3
|
+
import { MAX_PIXELS, PixelBudget, checkPixels } from "../util/limits.js";
|
|
2
4
|
const DISPOSAL_TO_GIF = [0, 1, 3, 2];
|
|
3
5
|
const DISPOSAL_FROM_GIF = [0, 1, 3, 2, 0, 0, 0, 0];
|
|
4
6
|
const MAX_CODE = 4095;
|
|
5
7
|
const UNEXPECTED_END = new Error('GIF: unexpected end of data');
|
|
6
8
|
export function encode({ width, height, loopCount = -1, frames }, quality = 95, comments = []) {
|
|
7
|
-
const out = new
|
|
9
|
+
const out = new GIFWriter();
|
|
8
10
|
out.bytes(0x47, 0x49, 0x46, 0x38, 0x39, 0x61);
|
|
9
11
|
out.u16(width);
|
|
10
12
|
out.u16(height);
|
|
@@ -47,7 +49,7 @@ export function encode({ width, height, loopCount = -1, frames }, quality = 95,
|
|
|
47
49
|
return out.finish();
|
|
48
50
|
}
|
|
49
51
|
function lzwEncode(indices, minCodeSize) {
|
|
50
|
-
const out = new
|
|
52
|
+
const out = new GIFWriter(indices.length);
|
|
51
53
|
const clear = 1 << minCodeSize;
|
|
52
54
|
const eoi = clear + 1;
|
|
53
55
|
const dictionary = new Int16Array(4096 * 256);
|
|
@@ -110,7 +112,7 @@ function writeSubBlocks(out, data) {
|
|
|
110
112
|
}
|
|
111
113
|
out.byte(0x00);
|
|
112
114
|
}
|
|
113
|
-
export function decode(data, onlyFirstFrame = false) {
|
|
115
|
+
export function decode(data, onlyFirstFrame = false, maxPixels = MAX_PIXELS) {
|
|
114
116
|
const reader = new ByteReader(data);
|
|
115
117
|
const signature = reader.string(6);
|
|
116
118
|
if (signature !== 'GIF87a' && signature !== 'GIF89a')
|
|
@@ -123,6 +125,7 @@ export function decode(data, onlyFirstFrame = false) {
|
|
|
123
125
|
const frames = [];
|
|
124
126
|
let loopCount = 0;
|
|
125
127
|
let control = null;
|
|
128
|
+
const budget = new PixelBudget(maxPixels);
|
|
126
129
|
try {
|
|
127
130
|
parse();
|
|
128
131
|
}
|
|
@@ -130,6 +133,7 @@ export function decode(data, onlyFirstFrame = false) {
|
|
|
130
133
|
if (err !== UNEXPECTED_END)
|
|
131
134
|
throw err;
|
|
132
135
|
}
|
|
136
|
+
checkPixels(width, height, maxPixels, Math.max(1, frames.length));
|
|
133
137
|
return { width, height, loopCount, frames };
|
|
134
138
|
function parse() {
|
|
135
139
|
while (reader.offset < data.length) {
|
|
@@ -183,6 +187,7 @@ export function decode(data, onlyFirstFrame = false) {
|
|
|
183
187
|
const table = localTable || globalTable;
|
|
184
188
|
const minCodeSize = reader.u8();
|
|
185
189
|
const compressed = readSubBlocks(reader);
|
|
190
|
+
budget.take(fw, fh);
|
|
186
191
|
const indices = lzwDecode(compressed, minCodeSize, fw * fh);
|
|
187
192
|
const { dispose = 0, delay = 0, transparentIndex = -1 } = control || {};
|
|
188
193
|
control = null;
|
|
@@ -376,42 +381,12 @@ class ByteReader {
|
|
|
376
381
|
return String.fromCharCode(...this.slice(length));
|
|
377
382
|
}
|
|
378
383
|
}
|
|
379
|
-
class ByteWriter {
|
|
380
|
-
buffer;
|
|
381
|
-
length;
|
|
382
|
-
constructor(capacity = 1024) {
|
|
383
|
-
this.buffer = new Uint8Array(Math.max(16, capacity));
|
|
384
|
-
this.length = 0;
|
|
385
|
-
}
|
|
386
|
-
reserve(size) {
|
|
387
|
-
if (this.length + size <= this.buffer.length)
|
|
388
|
-
return;
|
|
389
|
-
const buffer = new Uint8Array(Math.max(this.buffer.length * 2, this.length + size));
|
|
390
|
-
buffer.set(this.buffer.subarray(0, this.length));
|
|
391
|
-
this.buffer = buffer;
|
|
392
|
-
}
|
|
393
|
-
byte(value) {
|
|
394
|
-
this.reserve(1);
|
|
395
|
-
this.buffer[this.length++] = value;
|
|
396
|
-
}
|
|
397
|
-
bytes(...values) {
|
|
398
|
-
for (const value of values)
|
|
399
|
-
this.byte(value);
|
|
400
|
-
}
|
|
384
|
+
class GIFWriter extends ByteWriter {
|
|
401
385
|
u16(value) {
|
|
402
|
-
this.
|
|
403
|
-
this.byte(value >> 8 & 0xff);
|
|
386
|
+
this.bytes(value & 0xff, value >> 8 & 0xff);
|
|
404
387
|
}
|
|
405
388
|
string(value) {
|
|
406
389
|
for (let i = 0; i < value.length; i++)
|
|
407
390
|
this.byte(value.charCodeAt(i));
|
|
408
391
|
}
|
|
409
|
-
array(values) {
|
|
410
|
-
this.reserve(values.length);
|
|
411
|
-
this.buffer.set(values, this.length);
|
|
412
|
-
this.length += values.length;
|
|
413
|
-
}
|
|
414
|
-
finish() {
|
|
415
|
-
return this.buffer.slice(0, this.length);
|
|
416
|
-
}
|
|
417
392
|
}
|
package/dist/codecs/jpeg.js
CHANGED
|
@@ -4,13 +4,15 @@
|
|
|
4
4
|
* (IJG license, see licenses/README.ijg). The scan decoder follows the structure of pdf.js' jpg.js
|
|
5
5
|
* (Copyright 2014 Mozilla Foundation, Apache License 2.0). See THIRD_PARTY_NOTICES.md
|
|
6
6
|
*/
|
|
7
|
+
import { ByteWriter } from "../util/bytes.js";
|
|
8
|
+
import { MAX_PIXELS, checkPixels } from "../util/limits.js";
|
|
7
9
|
import { orientation as exifOrientation } from "./exif.js";
|
|
8
10
|
import { concat } from "../util/mem.js";
|
|
9
11
|
const ZIGZAG = Int32Array.of(0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, 12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, 35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51, 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63);
|
|
10
12
|
function clamp8(v) {
|
|
11
13
|
return v < 0 ? 0 : v > 255 ? 255 : v;
|
|
12
14
|
}
|
|
13
|
-
export function decode(data, { transform } = {}) {
|
|
15
|
+
export function decode(data, { transform, maxPixels = MAX_PIXELS } = {}) {
|
|
14
16
|
if (data[0] !== 0xff || data[1] !== 0xd8)
|
|
15
17
|
throw new Error('JPEG: invalid signature');
|
|
16
18
|
const quantizationTables = [];
|
|
@@ -84,6 +86,7 @@ export function decode(data, { transform } = {}) {
|
|
|
84
86
|
throw new Error('JPEG: multiple frames are not supported');
|
|
85
87
|
if (data[start] !== 8)
|
|
86
88
|
throw new Error(`JPEG: ${data[start]}-bit precision is not supported`);
|
|
89
|
+
checkPixels(u16(start + 3), u16(start + 1), maxPixels);
|
|
87
90
|
frame = createFrame(marker === 0xc2, u16(start + 1), u16(start + 3), data.subarray(start + 5, end));
|
|
88
91
|
break;
|
|
89
92
|
}
|
|
@@ -158,6 +161,8 @@ function createFrame(progressive, height, width, componentData) {
|
|
|
158
161
|
}
|
|
159
162
|
if (!width || !sampling.length)
|
|
160
163
|
throw new Error('JPEG: invalid dimensions');
|
|
164
|
+
if (sampling.length > 4)
|
|
165
|
+
throw new Error(`JPEG: ${sampling.length} components are not supported`);
|
|
161
166
|
const hmax = Math.max(...sampling.map(c => c.h));
|
|
162
167
|
const vmax = Math.max(...sampling.map(c => c.v));
|
|
163
168
|
const mcusPerLine = Math.ceil(width / (8 * hmax));
|
|
@@ -946,29 +951,9 @@ function fdctPass(d, o, s) {
|
|
|
946
951
|
d[o + s] = z11 + z4;
|
|
947
952
|
d[o + 7 * s] = z11 - z4;
|
|
948
953
|
}
|
|
949
|
-
class BitWriter {
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
bits;
|
|
953
|
-
count;
|
|
954
|
-
constructor(capacity) {
|
|
955
|
-
this.buffer = new Uint8Array(Math.max(1024, capacity));
|
|
956
|
-
this.length = 0;
|
|
957
|
-
this.bits = 0;
|
|
958
|
-
this.count = 0;
|
|
959
|
-
}
|
|
960
|
-
reserve(size) {
|
|
961
|
-
if (this.length + size <= this.buffer.length)
|
|
962
|
-
return;
|
|
963
|
-
const buffer = new Uint8Array(Math.max(this.buffer.length * 2, this.length + size));
|
|
964
|
-
buffer.set(this.buffer.subarray(0, this.length));
|
|
965
|
-
this.buffer = buffer;
|
|
966
|
-
}
|
|
967
|
-
bytes(...values) {
|
|
968
|
-
this.reserve(values.length);
|
|
969
|
-
for (const value of values)
|
|
970
|
-
this.buffer[this.length++] = value;
|
|
971
|
-
}
|
|
954
|
+
class BitWriter extends ByteWriter {
|
|
955
|
+
bits = 0;
|
|
956
|
+
count = 0;
|
|
972
957
|
write(value, size) {
|
|
973
958
|
this.bits = this.bits << size | value & (1 << size) - 1;
|
|
974
959
|
this.count += size;
|
|
@@ -986,7 +971,4 @@ class BitWriter {
|
|
|
986
971
|
if (this.count)
|
|
987
972
|
this.write((1 << 8 - this.count) - 1, 8 - this.count);
|
|
988
973
|
}
|
|
989
|
-
finish() {
|
|
990
|
-
return this.buffer.slice(0, this.length);
|
|
991
|
-
}
|
|
992
974
|
}
|
package/dist/codecs/png.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { crc32 } from "./crc.js";
|
|
2
|
+
import { MAX_PIXELS, checkPixels } from "../util/limits.js";
|
|
2
3
|
import { concat } from "../util/mem.js";
|
|
3
4
|
import { encode as utf8, decode as utf8Decode } from "../util/utf8.js";
|
|
4
5
|
import { orientation as exifOrientation, xmpOrientation } from "./exif.js";
|
|
@@ -437,15 +438,16 @@ async function decodeImageData(p, chunks, width, height) {
|
|
|
437
438
|
continue;
|
|
438
439
|
const rowBytes = Math.ceil(pw * bitsPerPixel / 8);
|
|
439
440
|
const size = ph * rowBytes;
|
|
440
|
-
const pixels = unfilter(data, dataOffset, ph, rowBytes, bpp);
|
|
441
|
+
const pixels = unfilter(data, dataOffset, ph, rowBytes, bpp, !interlace);
|
|
441
442
|
dataOffset += size + ph;
|
|
442
443
|
toRGBA(pixels, rowBytes, pw, ph, rgba, { row: y => ((ys + y * dy) * width + xs) * 4, step: dx * 4 });
|
|
443
444
|
}
|
|
444
445
|
return rgba;
|
|
445
446
|
}
|
|
446
|
-
export async function decode(array) {
|
|
447
|
+
export async function decode(array, maxPixels = MAX_PIXELS) {
|
|
447
448
|
const p = parse(array);
|
|
448
449
|
const { width, height } = p.header;
|
|
450
|
+
checkPixels(width, height, maxPixels);
|
|
449
451
|
const pixels = await decodeImageData(p, p.idat, width, height);
|
|
450
452
|
return { width, height, pixels, orientation: p.exif ? exifOrientation(p.exif) : await textOrientation(p.text) };
|
|
451
453
|
}
|
|
@@ -458,9 +460,10 @@ export function isAnimated(array) {
|
|
|
458
460
|
return false;
|
|
459
461
|
}
|
|
460
462
|
}
|
|
461
|
-
export async function decodeAnimation(array, onlyFirstFrame = false) {
|
|
463
|
+
export async function decodeAnimation(array, onlyFirstFrame = false, maxPixels = MAX_PIXELS) {
|
|
462
464
|
const p = parse(array);
|
|
463
465
|
const { width, height } = p.header;
|
|
466
|
+
checkPixels(width, height, maxPixels, !p.animation || p.animationError || onlyFirstFrame ? 1 : Math.max(1, p.frames.length));
|
|
464
467
|
if (!p.animation || p.animationError) {
|
|
465
468
|
const pixels = await decodeImageData(p, p.idat, width, height);
|
|
466
469
|
return { width, height, plays: 0, frames: [{ x: 0, y: 0, width, height, duration: 0, dispose: 0, blend: 0, pixels }] };
|
|
@@ -485,13 +488,21 @@ export function compositeAnimation({ width, height, frames }) {
|
|
|
485
488
|
const output = [];
|
|
486
489
|
for (const f of frames) {
|
|
487
490
|
const previous = f.dispose === 2 ? canvas.slice() : null;
|
|
488
|
-
for (let y = 0; y < f.height; y++)
|
|
491
|
+
for (let y = 0; y < f.height; y++) {
|
|
492
|
+
if (f.blend === 0) {
|
|
493
|
+
canvas.set(f.pixels.subarray(y * f.width * 4, (y + 1) * f.width * 4), ((f.y + y) * width + f.x) * 4);
|
|
494
|
+
continue;
|
|
495
|
+
}
|
|
489
496
|
for (let x = 0; x < f.width; x++) {
|
|
490
497
|
const s = (y * f.width + x) * 4, d = ((f.y + y) * width + f.x + x) * 4;
|
|
491
498
|
const sa = f.pixels[s + 3], da = canvas[d + 3];
|
|
492
|
-
if (
|
|
493
|
-
if (
|
|
494
|
-
canvas
|
|
499
|
+
if (sa === 255 || da === 0) {
|
|
500
|
+
if (sa !== 0) {
|
|
501
|
+
canvas[d] = f.pixels[s];
|
|
502
|
+
canvas[d + 1] = f.pixels[s + 1];
|
|
503
|
+
canvas[d + 2] = f.pixels[s + 2];
|
|
504
|
+
canvas[d + 3] = sa;
|
|
505
|
+
}
|
|
495
506
|
}
|
|
496
507
|
else if (sa !== 0) {
|
|
497
508
|
const u = sa * 255, v = (255 - sa) * da, al = u + v;
|
|
@@ -500,6 +511,7 @@ export function compositeAnimation({ width, height, frames }) {
|
|
|
500
511
|
canvas[d + 3] = al / 255 | 0;
|
|
501
512
|
}
|
|
502
513
|
}
|
|
514
|
+
}
|
|
503
515
|
output.push({ pixels: canvas.slice(), duration: f.duration });
|
|
504
516
|
if (f.dispose === 1)
|
|
505
517
|
for (let y = 0; y < f.height; y++)
|
|
@@ -550,11 +562,11 @@ function hexProfile(text) {
|
|
|
550
562
|
const digits = match[2].replace(/\s+/g, '');
|
|
551
563
|
const out = new Uint8Array(Math.min(+match[1], digits.length >> 1));
|
|
552
564
|
for (let i = 0; i < out.length; i++)
|
|
553
|
-
out[i] = parseInt(digits.
|
|
565
|
+
out[i] = parseInt(digits.slice(i * 2, i * 2 + 2), 16);
|
|
554
566
|
return out;
|
|
555
567
|
}
|
|
556
|
-
function unfilter(data, offset, height, rowBytes, bpp) {
|
|
557
|
-
const out = new Uint8Array(height * rowBytes);
|
|
568
|
+
function unfilter(data, offset, height, rowBytes, bpp, inPlace = false) {
|
|
569
|
+
const out = inPlace ? data.subarray(offset, offset + height * rowBytes) : new Uint8Array(height * rowBytes);
|
|
558
570
|
const first = Math.min(bpp, rowBytes);
|
|
559
571
|
for (let y = 0; y < height; y++) {
|
|
560
572
|
const filter = data[offset++];
|
package/dist/codecs/tga.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { encode as utf8 } from "../util/utf8.js";
|
|
2
|
+
import { MAX_PIXELS, checkPixels } from "../util/limits.js";
|
|
2
3
|
const SIGNATURE = 'TRUEVISION-XFILE.\0';
|
|
3
4
|
function readHeader(d) {
|
|
4
5
|
if (d.length < 18)
|
|
@@ -69,11 +70,12 @@ function readColor(d, o, bits, alphaBits, out, p) {
|
|
|
69
70
|
out[p + 3] = bits === 32 && alphaBits ? d[o + 3] : 255;
|
|
70
71
|
}
|
|
71
72
|
}
|
|
72
|
-
export function decode(d) {
|
|
73
|
+
export function decode(d, maxPixels = MAX_PIXELS) {
|
|
73
74
|
const h = readHeader(d);
|
|
74
75
|
if (!h || !isTGA(d))
|
|
75
76
|
throw new Error('TGA: invalid header');
|
|
76
77
|
const { width, height, depth } = h;
|
|
78
|
+
checkPixels(width, height, maxPixels);
|
|
77
79
|
const base = h.imageType & ~8, rle = (h.imageType & 8) !== 0;
|
|
78
80
|
const bytesPerPixel = Math.ceil(depth / 8);
|
|
79
81
|
let offset = 18 + h.idLength;
|
package/dist/codecs/tiff.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { decompressAsync } from "./zlib.js";
|
|
2
2
|
import * as jpeg from "./jpeg.js";
|
|
3
|
+
import { MAX_PIXELS, checkPixels, checkBytes } from "../util/limits.js";
|
|
3
4
|
const TYPE_SIZES = { 1: 1, 2: 1, 3: 2, 4: 4, 5: 8, 6: 1, 7: 1, 8: 2, 9: 4, 10: 8, 11: 4, 12: 8, 13: 4, 16: 8, 17: 8, 18: 8 };
|
|
4
5
|
const TAGS = {
|
|
5
6
|
ImageWidth: 256,
|
|
@@ -28,7 +29,7 @@ const TAGS = {
|
|
|
28
29
|
ReferenceBlackWhite: 532
|
|
29
30
|
};
|
|
30
31
|
const COMPRESSION_NAMES = { 2: 'CCITT RLE', 3: 'CCITT fax 3', 4: 'CCITT fax 4', 6: 'old-style JPEG', 32809: 'ThunderScan', 34676: 'SGI LogLuv', 34677: 'SGI LogL' };
|
|
31
|
-
export async function decode(data) {
|
|
32
|
+
export async function decode(data, maxPixels = MAX_PIXELS) {
|
|
32
33
|
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
33
34
|
let little;
|
|
34
35
|
if (data[0] === 0x49 && data[1] === 0x49)
|
|
@@ -154,9 +155,13 @@ export async function decode(data) {
|
|
|
154
155
|
throw new Error('TIFF: missing image data');
|
|
155
156
|
return data.subarray(offset, Math.min(data.length, offset + count));
|
|
156
157
|
};
|
|
158
|
+
checkPixels(width, height, maxPixels);
|
|
159
|
+
checkPixels(segmentWidth, segmentHeight, Math.max(4 * width * height, 1 << 20));
|
|
160
|
+
checkBytes(Math.ceil(width * samplesPerPixel * bps / 8) * height, maxPixels);
|
|
157
161
|
const pixels = new Uint8Array(width * height * 4);
|
|
158
162
|
if (compression === 7) {
|
|
159
|
-
const
|
|
163
|
+
const jpegTables = tags.get(TAGS.JPEGTables);
|
|
164
|
+
const tables = jpegTables ? data.subarray(jpegTables.offset, jpegTables.offset + jpegTables.count) : null;
|
|
160
165
|
const transform = photometric === 6 ? 'ycc' : photometric === 2 ? 'rgb' : photometric === 5 ? 'cmyk' : null;
|
|
161
166
|
for (let s = 0; s < segmentsPerPlane; s++) {
|
|
162
167
|
let stream = segment(s);
|
package/dist/codecs/vp8.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { KF_BMODE_PROBS, COEFF_UPDATE_PROBS, DEFAULT_COEFF_PROBS, DC_QLOOKUP, AC_QLOOKUP, PCAT } from "./vp8-tables.js";
|
|
2
|
+
import { MAX_PIXELS, checkPixels } from "../util/limits.js";
|
|
2
3
|
class BoolDecoder {
|
|
3
4
|
data;
|
|
4
5
|
pos;
|
|
@@ -161,9 +162,10 @@ function readHeader(data) {
|
|
|
161
162
|
};
|
|
162
163
|
}
|
|
163
164
|
const clamp255 = (v) => v < 0 ? 0 : v > 255 ? 255 : v;
|
|
164
|
-
export function decode(data) {
|
|
165
|
+
export function decode(data, maxPixels = MAX_PIXELS) {
|
|
165
166
|
const { header: h, first: d } = readHeader(data);
|
|
166
167
|
const { width, height } = h;
|
|
168
|
+
checkPixels(width, height, maxPixels);
|
|
167
169
|
const mbw = (width + 15) >> 4, mbh = (height + 15) >> 4;
|
|
168
170
|
const ys = mbw * 16 + 1, cs = mbw * 8 + 1;
|
|
169
171
|
const Y = new Uint8Array(ys * (mbh * 16 + 1));
|