@graysonlang/slim-webp-enc 1.0.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/LICENSE.md ADDED
@@ -0,0 +1,30 @@
1
+ Copyright 2026 Grayson Lang
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
8
+
9
+ ---
10
+
11
+ ## Third-party notices
12
+
13
+ Portions of this software are derived from [libwebp](https://github.com/webmproject/libwebp):
14
+
15
+ - The bitstream constant tables in `src/tables.ts` (coefficient probabilities, quantization lookups, category probabilities, the VP8L plane-code table, and related data) are generated from libwebp sources and are bitstream constants specified by RFC 6386 and the WebP specifications.
16
+ - The integer transform implementations in `src/transform.ts`, the boolean coder in `src/boolcoder.ts`, and parts of the token/probability coding logic in `src/vp8.ts` are TypeScript translations of the corresponding libwebp C code (`src/dsp/`, `src/utils/bit_writer_utils.c`, `src/enc/frame_enc.c`, `src/enc/tree_enc.c`).
17
+
18
+ libwebp is distributed under the following license, and with an additional intellectual property rights grant (see the [PATENTS](https://github.com/webmproject/libwebp/blob/main/PATENTS) file in the libwebp distribution):
19
+
20
+ Copyright (c) 2010, Google Inc. All rights reserved.
21
+
22
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
23
+
24
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
25
+
26
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
27
+
28
+ * Neither the name of Google nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
29
+
30
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package/README.md ADDED
@@ -0,0 +1,78 @@
1
+ # slim-webp-enc
2
+
3
+ A pure-TypeScript lossy WebP encoder with alpha support, purpose-built for **thumbnail generation** — no WASM, no loader complexity, zero runtime dependencies. Motivated by WebKit/Safari's lack of native `canvas.toBlob('image/webp')` support.
4
+
5
+ - **32 KB minified** (10.9 KB gzip) vs ~200–300 KB for a WASM libwebp build
6
+ - Single-digit-millisecond encodes at thumbnail sizes (256² ≈ 4–6 ms)
7
+ - Semi-lossy alpha (16-level reduction, 0/255 pinned exactly) compressed with a built-in mini-VP8L coder — typically **smaller total files than `cwebp -m 0`** on alpha-carrying thumbnails
8
+
9
+ ## Usage
10
+
11
+ ```ts
12
+ import { encodeWebP, hasNativeWebPEncoder } from "@graysonlang/slim-webp-enc";
13
+
14
+ // Prefer the native encoder where it exists (everything but WebKit).
15
+ // Safari accepts 'image/webp' but silently returns PNG — the helper checks.
16
+ if (!(await hasNativeWebPEncoder())) {
17
+ const ctx = canvas.getContext("2d")!;
18
+ const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
19
+ const webp: Uint8Array = encodeWebP(imageData, { quality: 80 });
20
+ const blob = new Blob([webp], { type: "image/webp" });
21
+ }
22
+ ```
23
+
24
+ `data` must be RGBA, i.e. at least `width × height × 4` bytes. `encodeWebP` throws a `RangeError` if the dimensions are non-integer, `< 1`, or `> 16383` (the 14-bit WebP header limit), or if `data` is shorter than that.
25
+
26
+ ### Options
27
+
28
+ | Option | Default | Notes |
29
+ |---|---|---|
30
+ | `quality` | `80` | 0–100, same scale as cwebp; default matches the browsers' native WebP encoder default |
31
+ | `alphaLevels` | `16` | 8 / 16 / 32 semi-lossy alpha levels; 0 and 255 always exact |
32
+ | `alphaDither` | `1` | Ordered-dither strength 0–1 for the alpha level reduction. Hides banding on smooth alpha gradients at some alpha-payload cost; exact 0/255 pixels never dither. `0` disables |
33
+ | `alphaAdaptive` | `true` | Pick alpha level values by Lloyd-Max (like libwebp's `-alpha_q`) instead of a uniform grid. Min/max stay exact; masks with ≤ `alphaLevels` distinct values pass through losslessly |
34
+ | `lossless` | `"auto"` | Images with ≤ 256 distinct colors are also encoded losslessly (palette VP8L) and the smaller file wins, so `quality` acts as a floor. `true` forces lossless when representable; `false` disables |
35
+
36
+ **`quality: 100` is still lossy.** Browsers special-case `canvas.toBlob('image/webp', 1.0)` to fully lossless output; this encoder does not — 100 means the finest lossy quantization (still 4:2:0 chroma). Alpha is independent of `quality` and stays bit-exact whenever the untouched plane compresses no larger than the level-reduced one (typical for smooth masks). For guaranteed pixel-exact output use `lossless: true` (representable up to 256 distinct colors) — or PNG, which WebKit encodes natively.
37
+
38
+ ## Scope
39
+
40
+ Encodes a single lossy VP8 keyframe (16×16 intra modes, single segment, flat quantization, adaptive token probabilities) in a RIFF/VP8X/ALPH container. Alpha is level-reduced, prediction-filtered, and coded as a minimal VP8L stream (ALPH method 1). Flat-color images (≤ 256 distinct colors) are also tried as palette-based lossless VP8L and the smaller file is kept — `quality` is a floor, never a ceiling. Non-goals: animation, metadata, general-purpose lossless RGB (only the palette subset above), decode, rate control. Files run roughly 10–25 % larger than `cwebp -m 0` for opaque RGB at matched SSIM; alpha-heavy thumbnails usually come out *smaller* thanks to the semi-lossy alpha strategy.
41
+
42
+ ## Performance
43
+
44
+ Median encode times in headless Chrome (Apple Silicon, q80; `node harness/bench-browser.ts`) against the two alternatives: the native `canvas.toBlob('image/webp')` (Chrome only), and WASM libwebp (`@jsquash/webp`, method 0, SIMD) — the apples-to-apples option for browsers without native WebP encoding:
45
+
46
+ | content | size | ours | native | WASM |
47
+ |---|---|---|---|---|
48
+ | photo (opaque) | 256² | 3.9 ms | 2.6 ms | 0.9 ms |
49
+ | photo (opaque) | 512² | 12.6 ms | 8.6 ms | 2.9 ms |
50
+ | avatar (alpha) | 256² | 6.3 ms | 5.8 ms | 2.2 ms |
51
+ | avatar (alpha) | 512² | 21.2 ms | **31.0 ms** | 7.4 ms |
52
+ | sprite (lossless path) | 256² | 4.5 ms | 2.3 ms | 1.1 ms |
53
+ | sprite (lossless path) | 512² | 17.3 ms | 7.8 ms | 3.6 ms |
54
+
55
+ Per encode: 1–2× native (faster than native on 512² alpha content), and 3–5× slower than WASM libwebp. The trade is the payload: WASM costs a **337 KB download plus ~24 ms compile/init** before the first encode, vs this library's 32 KB bundle with none — and our output was smaller than both in nearly every cell (sprite 512²: 1.6 KB vs 7–10 KB, thanks to the lossless path). Benchmark content is the harness corpus itself (`harness/content.ts`), so these rows measure the same images the quality metrics do. For a page encoding a handful of thumbnails, the WASM speed advantage never pays back its startup cost; sustained bulk encoding is where WASM wins.
56
+
57
+ ## Example app
58
+
59
+ `demo/` is a side-by-side comparison demo (slim-webp-enc vs the browser's native `canvas.toBlob('image/webp')` vs PNG, with bytes, encode time, and alpha-aware PSNR per cell; drag/drop your own images). Built with [@graysonlang/esp](https://github.com/graysonlang/esp):
60
+
61
+ ```
62
+ npm run dev # watch + dev server + Chrome launch (http://localhost:8000)
63
+ npm run build # one-shot demo build into www/
64
+ ```
65
+
66
+ In VS Code, the **Debug in Chrome** launch configuration starts the dev server and attaches the debugger with source maps into `src/` and the app.
67
+
68
+ ## Development
69
+
70
+ ```
71
+ npm run harness # encode corpus → webpinfo → dwebp → PSNR/SSIM (needs libwebp tools)
72
+ npm run compare # size vs cwebp -m 0 at matched SSIM
73
+ npm run size # 55 KB minified-bundle hard gate
74
+ npm run dist # library build (dist/index.js + declarations)
75
+ npm run typecheck
76
+ ```
77
+
78
+ `harness/gen-tables.ts` regenerates `src/tables.ts` (bitstream constants per RFC 6386) from a libwebp checkout vendored at `vendor/libwebp`.
@@ -0,0 +1,55 @@
1
+ export type AlphaLevels = 8 | 16 | 32;
2
+ /**
3
+ * Semi-lossy level reduction. Uniform levels with 0 and 255 representable
4
+ * exactly (step = 255/(levels-1)); quantize BEFORE the prediction filter.
5
+ *
6
+ * `dither` (0..1) applies ordered dithering scaled to the quantization step,
7
+ * trading banding on smooth alpha gradients for a fine 4x4 pattern. Pixels
8
+ * sitting exactly on a level (in particular 0 and 255) are unaffected at any
9
+ * strength, so hard transparent/opaque regions never speckle.
10
+ */
11
+ export declare function quantizeAlpha(alpha: Uint8Array, width: number, levels?: AlphaLevels, dither?: number): Uint8Array;
12
+ /**
13
+ * Adaptive (Lloyd-Max / k-means) level reduction, the same scheme libwebp's
14
+ * alpha_quality uses: pick the N level values that minimize squared error for
15
+ * this plane's histogram, instead of a uniform grid. Min and max observed
16
+ * values are pinned exactly (usually 0 and 255). If the plane already has at
17
+ * most N distinct values it is passed through untouched (lossless).
18
+ *
19
+ * `dither` works as in quantizeAlpha, scaled to the local gap between the
20
+ * two bracketing levels; pixels exactly on a level never move.
21
+ */
22
+ export declare function quantizeAlphaAdaptive(alpha: Uint8Array, width: number, levels?: AlphaLevels, dither?: number): Uint8Array;
23
+ export declare const FILTER_NONE = 0;
24
+ export declare const FILTER_HORIZONTAL = 1;
25
+ export declare const FILTER_VERTICAL = 2;
26
+ export declare const FILTER_GRADIENT = 3;
27
+ /** Apply prediction filter (residual = actual - prediction, mod 256). */
28
+ export declare function applyAlphaFilter(a: Uint8Array, width: number, height: number, filter: number): Uint8Array;
29
+ export interface AlphaEncodeResult {
30
+ /** ALPH chunk payload: header byte + filtered plane. */
31
+ payload: Uint8Array;
32
+ filter: number;
33
+ /** The quantized plane a compliant decoder will reconstruct exactly. */
34
+ quantized: Uint8Array;
35
+ }
36
+ /**
37
+ * Build a method-0 (uncompressed) ALPH payload. Tries all four prediction
38
+ * filters and keeps the one with the smallest post-filter entropy estimate.
39
+ */
40
+ export declare function encodeAlphaMethod0(alpha: Uint8Array, width: number, height: number, levels?: AlphaLevels, dither?: number): AlphaEncodeResult;
41
+ /**
42
+ * Build the best ALPH payload: method 1 (mini-VP8L) over BOTH the level-
43
+ * reduced plane and the untouched lossless plane, each with all four
44
+ * prediction filters, picking the smallest actual encoding. Smooth alpha
45
+ * gradients compress nearly for free losslessly (constant residuals after
46
+ * prediction — pure run-length), so on such content lossless wins on size AND
47
+ * quality; on mask-like content the quantized plane wins as usual. The
48
+ * method-0 (uncompressed) payload remains as a final fallback.
49
+ *
50
+ * `levels` is therefore a cap, not a promise: the encoder keeps the plane
51
+ * lossless whenever that is not larger.
52
+ */
53
+ export declare function encodeAlpha(alpha: Uint8Array, width: number, height: number, levels?: AlphaLevels, dither?: number, adaptive?: boolean): AlphaEncodeResult;
54
+ /** Extract the alpha plane from interleaved RGBA. */
55
+ export declare function alphaPlane(rgba: Uint8Array | Uint8ClampedArray): Uint8Array;
@@ -0,0 +1,17 @@
1
+ export declare class BoolEncoder {
2
+ private range;
3
+ private value;
4
+ private run;
5
+ private nbBits;
6
+ private buf;
7
+ private flush;
8
+ /** Code one bool with probability `prob` (of a 0) out of 256. */
9
+ putBit(bit: number | boolean, prob: number): boolean;
10
+ /** Code one bool with probability 1/2. */
11
+ putBitUniform(bit: number | boolean): boolean;
12
+ /** Write a literal value MSB-first, each bit at probability 1/2. */
13
+ putBits(value: number, nbBits: number): void;
14
+ /** flag + sign + magnitude, as used for quantizer/filter deltas. */
15
+ putSignedBits(value: number, nbBits: number): void;
16
+ finish(): Uint8Array;
17
+ }
@@ -0,0 +1,20 @@
1
+ export interface ContainerParts {
2
+ width: number;
3
+ height: number;
4
+ /** VP8 bitstream (payload of the "VP8 " chunk). */
5
+ vp8: Uint8Array;
6
+ /** ALPH chunk payload (header byte + data). Omit for opaque images. */
7
+ alph?: Uint8Array;
8
+ }
9
+ /**
10
+ * Assemble a WebP file. With alpha: RIFF > VP8X + ALPH + "VP8 ".
11
+ * Without: the simple format, RIFF > "VP8 " only.
12
+ */
13
+ export declare function buildWebP(parts: ContainerParts): Uint8Array;
14
+ /**
15
+ * Assemble a lossless WebP file: RIFF > "VP8L" only (the simple lossless
16
+ * format; dimensions and the alpha hint live inside the VP8L header).
17
+ */
18
+ export declare function buildWebPLossless(vp8l: Uint8Array): Uint8Array;
19
+ /** Extract a chunk payload by fourcc from a WebP file. Returns null if absent. */
20
+ export declare function extractChunk(webp: Uint8Array, cc: string): Uint8Array | null;
@@ -0,0 +1,2 @@
1
+ /** True if the browser's canvas.toBlob natively produces image/webp. */
2
+ export declare function hasNativeWebPEncoder(): Promise<boolean>;
@@ -0,0 +1,43 @@
1
+ export { hasNativeWebPEncoder } from "./detect.ts";
2
+ import { type AlphaLevels } from "./alpha.ts";
3
+ export interface ImageDataLike {
4
+ data: Uint8Array | Uint8ClampedArray;
5
+ width: number;
6
+ height: number;
7
+ }
8
+ export interface EncodeOptions {
9
+ /**
10
+ * 0–100, like cwebp. Default 80, matching the browsers' native encoder
11
+ * default. Note: unlike `canvas.toBlob('image/webp', 1.0)`, which browsers
12
+ * special-case to fully lossless output, 100 here is still lossy (finest
13
+ * quantization, 4:2:0 chroma) — use `lossless` for pixel-exact output.
14
+ */
15
+ quality?: number;
16
+ /**
17
+ * Alpha level-reduction cap. Default 16. The encoder also tries the
18
+ * untouched lossless plane and keeps whichever encoding is smaller, so
19
+ * smooth alpha gradients stay lossless automatically.
20
+ */
21
+ alphaLevels?: AlphaLevels;
22
+ /**
23
+ * Ordered-dither strength (0–1) for alpha level reduction. Reduces banding
24
+ * on smooth alpha gradients at some alpha-payload cost; exact 0/255 pixels
25
+ * are never affected. Default 1; pass 0 to disable.
26
+ */
27
+ alphaDither?: number;
28
+ /**
29
+ * Choose the alpha level values adaptively (Lloyd-Max, like libwebp's
30
+ * alpha_quality) instead of a uniform grid. Min/max stay exact, and planes
31
+ * with ≤ alphaLevels distinct values pass through losslessly. Default true.
32
+ */
33
+ alphaAdaptive?: boolean;
34
+ /**
35
+ * Lossless (VP8L, palette-based) candidate selection. With "auto" (the
36
+ * default), images with ≤ 256 distinct colors are also encoded losslessly
37
+ * and the smaller file wins — `quality` acts as a floor, since lossless
38
+ * only replaces lossy when it is not larger. `true` forces lossless when
39
+ * representable (falling back to lossy above 256 colors); `false` disables.
40
+ */
41
+ lossless?: boolean | "auto";
42
+ }
43
+ export declare function encodeWebP(image: ImageDataLike, opts?: EncodeOptions): Uint8Array;
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ var g2=Object.defineProperty;var B2=(t,e,n)=>e in t?g2(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n;var O=(t,e,n)=>B2(t,typeof e!="symbol"?e+"":e,n);var $=null;async function x2(){return $!==null?$:typeof document>"u"?($=!1,$):($=await new Promise(t=>{try{let e=document.createElement("canvas");e.width=1,e.height=1,e.toBlob(n=>t(n?.type==="image/webp"),"image/webp")}catch{t(!1)}}),$)}var s5=[[[[128,128,128,128,128,128,128,128,128,128,128],[128,128,128,128,128,128,128,128,128,128,128],[128,128,128,128,128,128,128,128,128,128,128]],[[253,136,254,255,228,219,128,128,128,128,128],[189,129,242,255,227,213,255,219,128,128,128],[106,126,227,252,214,209,255,255,128,128,128]],[[1,98,248,255,236,226,255,255,128,128,128],[181,133,238,254,221,234,255,154,128,128,128],[78,134,202,247,198,180,255,219,128,128,128]],[[1,185,249,255,243,255,128,128,128,128,128],[184,150,247,255,236,224,128,128,128,128,128],[77,110,216,255,236,230,128,128,128,128,128]],[[1,101,251,255,241,255,128,128,128,128,128],[170,139,241,252,236,209,255,255,128,128,128],[37,116,196,243,228,255,255,255,128,128,128]],[[1,204,254,255,245,255,128,128,128,128,128],[207,160,250,255,238,128,128,128,128,128,128],[102,103,231,255,211,171,128,128,128,128,128]],[[1,152,252,255,240,255,128,128,128,128,128],[177,135,243,255,234,225,128,128,128,128,128],[80,129,211,255,194,224,128,128,128,128,128]],[[1,1,255,128,128,128,128,128,128,128,128],[246,1,255,128,128,128,128,128,128,128,128],[255,128,128,128,128,128,128,128,128,128,128]]],[[[198,35,237,223,193,187,162,160,145,155,62],[131,45,198,221,172,176,220,157,252,221,1],[68,47,146,208,149,167,221,162,255,223,128]],[[1,149,241,255,221,224,255,255,128,128,128],[184,141,234,253,222,220,255,199,128,128,128],[81,99,181,242,176,190,249,202,255,255,128]],[[1,129,232,253,214,197,242,196,255,255,128],[99,121,210,250,201,198,255,202,128,128,128],[23,91,163,242,170,187,247,210,255,255,128]],[[1,200,246,255,234,255,128,128,128,128,128],[109,178,241,255,231,245,255,255,128,128,128],[44,130,201,253,205,192,255,255,128,128,128]],[[1,132,239,251,219,209,255,165,128,128,128],[94,136,225,251,218,190,255,255,128,128,128],[22,100,174,245,186,161,255,199,128,128,128]],[[1,182,249,255,232,235,128,128,128,128,128],[124,143,241,255,227,234,128,128,128,128,128],[35,77,181,251,193,211,255,205,128,128,128]],[[1,157,247,255,236,231,255,255,128,128,128],[121,141,235,255,225,227,255,255,128,128,128],[45,99,188,251,195,217,255,224,128,128,128]],[[1,1,251,255,213,255,128,128,128,128,128],[203,1,248,255,255,128,128,128,128,128,128],[137,1,177,255,224,255,128,128,128,128,128]]],[[[253,9,248,251,207,208,255,192,128,128,128],[175,13,224,243,193,185,249,198,255,255,128],[73,17,171,221,161,179,236,167,255,234,128]],[[1,95,247,253,212,183,255,255,128,128,128],[239,90,244,250,211,209,255,255,128,128,128],[155,77,195,248,188,195,255,255,128,128,128]],[[1,24,239,251,218,219,255,205,128,128,128],[201,51,219,255,196,186,128,128,128,128,128],[69,46,190,239,201,218,255,228,128,128,128]],[[1,191,251,255,255,128,128,128,128,128,128],[223,165,249,255,213,255,128,128,128,128,128],[141,124,248,255,255,128,128,128,128,128,128]],[[1,16,248,255,255,128,128,128,128,128,128],[190,36,230,255,236,255,128,128,128,128,128],[149,1,255,128,128,128,128,128,128,128,128]],[[1,226,255,128,128,128,128,128,128,128,128],[247,192,255,128,128,128,128,128,128,128,128],[240,128,255,128,128,128,128,128,128,128,128]],[[1,134,252,255,255,128,128,128,128,128,128],[213,62,250,255,255,128,128,128,128,128,128],[55,93,255,128,128,128,128,128,128,128,128]],[[128,128,128,128,128,128,128,128,128,128,128],[128,128,128,128,128,128,128,128,128,128,128],[128,128,128,128,128,128,128,128,128,128,128]]],[[[202,24,213,235,186,191,220,160,240,175,255],[126,38,182,232,169,184,228,174,255,187,128],[61,46,138,219,151,178,240,170,255,216,128]],[[1,112,230,250,199,191,247,159,255,255,128],[166,109,228,252,211,215,255,174,128,128,128],[39,77,162,232,172,180,245,178,255,255,128]],[[1,52,220,246,198,199,249,220,255,255,128],[124,74,191,243,183,193,250,221,255,255,128],[24,71,130,219,154,170,243,182,255,255,128]],[[1,182,225,249,219,240,255,224,128,128,128],[149,150,226,252,216,205,255,171,128,128,128],[28,108,170,242,183,194,254,223,255,255,128]],[[1,81,230,252,204,203,255,192,128,128,128],[123,102,209,247,188,196,255,233,128,128,128],[20,95,153,243,164,173,255,203,128,128,128]],[[1,222,248,255,216,213,128,128,128,128,128],[168,175,246,252,235,205,255,255,128,128,128],[47,116,215,255,211,212,255,255,128,128,128]],[[1,121,236,253,212,214,255,255,128,128,128],[141,84,213,252,201,202,255,219,128,128,128],[42,80,160,240,162,185,255,205,128,128,128]],[[1,1,255,128,128,128,128,128,128,128,128],[244,1,255,128,128,128,128,128,128,128,128],[238,1,255,128,128,128,128,128,128,128,128]]]],C5=[[[[255,255,255,255,255,255,255,255,255,255,255],[255,255,255,255,255,255,255,255,255,255,255],[255,255,255,255,255,255,255,255,255,255,255]],[[176,246,255,255,255,255,255,255,255,255,255],[223,241,252,255,255,255,255,255,255,255,255],[249,253,253,255,255,255,255,255,255,255,255]],[[255,244,252,255,255,255,255,255,255,255,255],[234,254,254,255,255,255,255,255,255,255,255],[253,255,255,255,255,255,255,255,255,255,255]],[[255,246,254,255,255,255,255,255,255,255,255],[239,253,254,255,255,255,255,255,255,255,255],[254,255,254,255,255,255,255,255,255,255,255]],[[255,248,254,255,255,255,255,255,255,255,255],[251,255,254,255,255,255,255,255,255,255,255],[255,255,255,255,255,255,255,255,255,255,255]],[[255,253,254,255,255,255,255,255,255,255,255],[251,254,254,255,255,255,255,255,255,255,255],[254,255,254,255,255,255,255,255,255,255,255]],[[255,254,253,255,254,255,255,255,255,255,255],[250,255,254,255,254,255,255,255,255,255,255],[254,255,255,255,255,255,255,255,255,255,255]],[[255,255,255,255,255,255,255,255,255,255,255],[255,255,255,255,255,255,255,255,255,255,255],[255,255,255,255,255,255,255,255,255,255,255]]],[[[217,255,255,255,255,255,255,255,255,255,255],[225,252,241,253,255,255,254,255,255,255,255],[234,250,241,250,253,255,253,254,255,255,255]],[[255,254,255,255,255,255,255,255,255,255,255],[223,254,254,255,255,255,255,255,255,255,255],[238,253,254,254,255,255,255,255,255,255,255]],[[255,248,254,255,255,255,255,255,255,255,255],[249,254,255,255,255,255,255,255,255,255,255],[255,255,255,255,255,255,255,255,255,255,255]],[[255,253,255,255,255,255,255,255,255,255,255],[247,254,255,255,255,255,255,255,255,255,255],[255,255,255,255,255,255,255,255,255,255,255]],[[255,253,254,255,255,255,255,255,255,255,255],[252,255,255,255,255,255,255,255,255,255,255],[255,255,255,255,255,255,255,255,255,255,255]],[[255,254,254,255,255,255,255,255,255,255,255],[253,255,255,255,255,255,255,255,255,255,255],[255,255,255,255,255,255,255,255,255,255,255]],[[255,254,253,255,255,255,255,255,255,255,255],[250,255,255,255,255,255,255,255,255,255,255],[254,255,255,255,255,255,255,255,255,255,255]],[[255,255,255,255,255,255,255,255,255,255,255],[255,255,255,255,255,255,255,255,255,255,255],[255,255,255,255,255,255,255,255,255,255,255]]],[[[186,251,250,255,255,255,255,255,255,255,255],[234,251,244,254,255,255,255,255,255,255,255],[251,251,243,253,254,255,254,255,255,255,255]],[[255,253,254,255,255,255,255,255,255,255,255],[236,253,254,255,255,255,255,255,255,255,255],[251,253,253,254,254,255,255,255,255,255,255]],[[255,254,254,255,255,255,255,255,255,255,255],[254,254,254,255,255,255,255,255,255,255,255],[255,255,255,255,255,255,255,255,255,255,255]],[[255,254,255,255,255,255,255,255,255,255,255],[254,254,255,255,255,255,255,255,255,255,255],[254,255,255,255,255,255,255,255,255,255,255]],[[255,255,255,255,255,255,255,255,255,255,255],[254,255,255,255,255,255,255,255,255,255,255],[255,255,255,255,255,255,255,255,255,255,255]],[[255,255,255,255,255,255,255,255,255,255,255],[255,255,255,255,255,255,255,255,255,255,255],[255,255,255,255,255,255,255,255,255,255,255]],[[255,255,255,255,255,255,255,255,255,255,255],[255,255,255,255,255,255,255,255,255,255,255],[255,255,255,255,255,255,255,255,255,255,255]],[[255,255,255,255,255,255,255,255,255,255,255],[255,255,255,255,255,255,255,255,255,255,255],[255,255,255,255,255,255,255,255,255,255,255]]],[[[248,255,255,255,255,255,255,255,255,255,255],[250,254,252,254,255,255,255,255,255,255,255],[248,254,249,253,255,255,255,255,255,255,255]],[[255,253,253,255,255,255,255,255,255,255,255],[246,253,253,255,255,255,255,255,255,255,255],[252,254,251,254,254,255,255,255,255,255,255]],[[255,254,252,255,255,255,255,255,255,255,255],[248,254,253,255,255,255,255,255,255,255,255],[253,255,254,254,255,255,255,255,255,255,255]],[[255,251,254,255,255,255,255,255,255,255,255],[245,251,254,255,255,255,255,255,255,255,255],[253,253,254,255,255,255,255,255,255,255,255]],[[255,251,253,255,255,255,255,255,255,255,255],[252,253,254,255,255,255,255,255,255,255,255],[255,254,255,255,255,255,255,255,255,255,255]],[[255,252,255,255,255,255,255,255,255,255,255],[249,255,254,255,255,255,255,255,255,255,255],[255,255,254,255,255,255,255,255,255,255,255]],[[255,255,253,255,255,255,255,255,255,255,255],[250,255,255,255,255,255,255,255,255,255,255],[255,255,255,255,255,255,255,255,255,255,255]],[[255,255,255,255,255,255,255,255,255,255,255],[254,255,255,255,255,255,255,255,255,255,255],[255,255,255,255,255,255,255,255,255,255,255]]]],u5=[4,5,6,7,8,9,10,10,11,12,13,14,15,16,17,17,18,19,20,20,21,21,22,22,23,23,24,25,25,26,27,28,29,30,31,32,33,34,35,36,37,37,38,39,40,41,42,43,44,45,46,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,76,77,78,79,80,81,82,83,84,85,86,87,88,89,91,93,95,96,98,100,101,102,104,106,108,110,112,114,116,118,122,124,126,128,130,132,134,136,138,140,143,145,148,151,154,157],K=[4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,60,62,64,66,68,70,72,74,76,78,80,82,84,86,88,90,92,94,96,98,100,102,104,106,108,110,112,114,116,119,122,125,128,131,134,137,140,143,146,149,152,155,158,161,164,167,170,173,177,181,185,189,193,197,201,205,209,213,217,221,225,229,234,239,245,249,254,259,264,269,274,279,284],$5=[0,1,4,8,5,2,3,6,9,12,13,10,7,11,14,15],D=[0,1,2,3,6,4,5,6,6,6,6,6,6,6,6,7,0],G5=[173,148,140],Q5=[176,155,140,135],X5=[180,157,141,134,130],Z5=[254,254,243,230,196,177,153,140,133,130,129],P5=[96,73,55,39,23,13,5,1,255,255,255,255,255,255,255,255,101,78,58,42,26,16,8,2,0,3,9,17,27,43,59,79,102,86,62,46,32,20,10,6,4,7,11,21,33,47,63,87,105,90,70,52,37,28,18,14,12,15,19,29,38,53,71,91,110,99,82,66,48,35,30,24,22,25,31,36,49,67,83,100,115,108,94,76,64,50,44,40,34,41,45,51,65,77,95,109,118,113,103,92,80,68,60,56,54,57,61,69,81,93,104,114,119,116,111,106,97,88,84,74,72,75,85,89,98,107,112,117];var c5=class{constructor(){O(this,"buf",[]);O(this,"acc",0);O(this,"used",0)}putBits(e,n){for(this.acc|=e<<this.used,this.used+=n;this.used>=8;)this.buf.push(this.acc&255),this.acc>>>=8,this.used-=8}finish(){return this.used>0&&(this.buf.push(this.acc&255),this.acc=0,this.used=0),new Uint8Array(this.buf)}};function l5(t){if(t<=4)return{code:t-1,extraBits:0,extraValue:0};let e=t-1,n=31-Math.clz32(e),o=e>>n-1&1,s=n-1;return{code:2*n+o,extraBits:s,extraValue:e&(1<<s)-1}}function U2(t,e){let n=e/t|0,o=e-n*t;return o<=8&&n<8?P5[n*16+8-o]+1:o>t-8&&n<7?P5[(n+1)*16+8+(t-o)]+1:e+120}function G(t,e){let n=t.length,o=new Uint8Array(n),s=[];for(let r=0;r<n;r++)t[r]>0&&s.push(r);if(s.length===0)return o;if(s.length===1)return o[s[0]]=1,o;let i=Array.from(t);for(;;){let r=s.map(l=>({count:i[l],symbol:l,left:null,right:null})).sort((l,u)=>l.count-u.count);for(;r.length>1;){let l=r.shift(),u=r.shift(),m={count:l.count+u.count,symbol:-1,left:l,right:u},f=0,b=r.length;for(;f<b;){let x=f+b>>1;r[x].count<=m.count?f=x+1:b=x}r.splice(f,0,m)}let c=!1,a=(l,u)=>{if(l.symbol>=0){u>e&&(c=!0),o[l.symbol]=u;return}a(l.left,u+1),a(l.right,u+1)};if(a(r[0],0),!c)return o;i=i.map(l=>l>0?l+1>>1:0)}}function C2(t,e){let n=0;for(let o=0;o<e;o++)n=n<<1|t>>o&1;return n}function Q(t){let e=0;for(let n of t.lengths)n>0&&e++;return e!==1?t:{codes:t.codes,lengths:new Uint8Array(t.lengths.length)}}function X(t){let e=Math.max(0,...t),n=new Array(e+1).fill(0);for(let r of t)r>0&&n[r]++;let o=new Array(e+1).fill(0),s=0;for(let r=1;r<=e;r++)s=s+n[r-1]<<1,o[r]=s;let i=new Uint16Array(t.length);for(let r=0;r<t.length;r++)t[r]>0&&(i[r]=C2(o[t[r]]++,t[r]));return{codes:i,lengths:t}}var E5=[17,18,0,1,2,3,4,5,16,6,7,8,9,10,11,12,13,14,15];function j(t,e){let n=[];for(let l=0;l<e.length;l++)e[l]>0&&n.push(l);if(n.length===0){t.putBits(1,1),t.putBits(0,1),t.putBits(0,1),t.putBits(0,1);return}if(n.length<=2&&n[n.length-1]<256){t.putBits(1,1),t.putBits(n.length-1,1),n[0]<=1?(t.putBits(0,1),t.putBits(n[0],1)):(t.putBits(1,1),t.putBits(n[0],8)),n.length===2&&t.putBits(n[1],8);return}t.putBits(0,1);let o=[],s=8;for(let l=0;l<e.length;){let u=e[l],m=1;for(;l+m<e.length&&e[l+m]===u;)m++;if(u===0){let f=m;for(;f>=11;){let b=Math.min(f,138);o.push({symbol:18,extra:b-11,extraBits:7}),f-=b}for(f>=3&&(o.push({symbol:17,extra:f-3,extraBits:3}),f=0);f-- >0;)o.push({symbol:0,extra:0,extraBits:0})}else{let f=m;for(u!==s&&(o.push({symbol:u,extra:0,extraBits:0}),s=u,f--);f>=3;){let b=Math.min(f,6);o.push({symbol:16,extra:b-3,extraBits:2}),f-=b}for(;f-- >0;)o.push({symbol:u,extra:0,extraBits:0})}l+=m}let i=new Uint32Array(19);for(let l of o)i[l.symbol]++;let r=G(i,7),c=Q(X(r)),a=E5.length;for(;a>4&&r[E5[a-1]]===0;)a--;t.putBits(a-4,4);for(let l=0;l<a;l++)t.putBits(r[E5[l]],3);t.putBits(0,1);for(let l of o)t.putBits(c.codes[l.symbol],c.lengths[l.symbol]),l.extraBits>0&&t.putBits(l.extra,l.extraBits)}var P2=4,E2=4096;function L2(t,e){let n=[],o=t.length,s=0;for(;s<o;){let i=0,r=0;for(let c of s>=e?[1,e]:[1]){if(s<c)continue;let a=0,l=Math.min(E2,o-s);for(;a<l&&t[s+a]===t[s+a-c];)a++;a>i&&(i=a,r=c)}i>=P2?(n.push({length:i,distCode:U2(e,r)}),s+=i):(n.push({literal:t[s]}),s++)}return n}var L5=256,v2=24,I2=L5+v2;function v5(t,e,n,o){let s=L2(e,n),i=new Uint32Array(I2),r=new Uint32Array(256),c=new Uint32Array(256),a=new Uint32Array(256),l=new Uint32Array(40);for(let A of s)"literal"in A?(i[A.literal>>>8&255]++,r[A.literal>>>16&255]++,c[A.literal&255]++,a[A.literal>>>24]++):(i[L5+l5(A.length).code]++,l[l5(A.distCode).code]++);let u=G(i,15),m=G(r,15),f=G(c,15),b=G(a,15),x=G(l,15),g=Q(X(u)),p=Q(X(m)),h=Q(X(f)),C=Q(X(b)),v=Q(X(x));t.putBits(0,1),o&&t.putBits(0,1),j(t,u),j(t,m),j(t,f),j(t,b),j(t,x);let T=(A,_)=>{A.lengths[_]>0&&t.putBits(A.codes[_],A.lengths[_])};for(let A of s)if("literal"in A)T(g,A.literal>>>8&255),T(p,A.literal>>>16&255),T(h,A.literal&255),T(C,A.literal>>>24);else{let _=l5(A.length);T(g,L5+_.code),_.extraBits>0&&t.putBits(_.extraValue,_.extraBits);let H=l5(A.distCode);T(v,H.code),H.extraBits>0&&t.putBits(H.extraValue,H.extraBits)}}function K5(t,e,n){let o=new Uint32Array(t.length);for(let i=0;i<t.length;i++)o[i]=(4278190080|t[i]<<8)>>>0;let s=new c5;return s.putBits(0,1),v5(s,o,e,!0),s.finish()}function M2(t){return t<=2?3:t<=4?2:t<=16?1:0}function j5(t,e,n){let o=new Set,s=e*n,i=new Uint32Array(s);for(let p=0;p<s;p++){let h=(t[p*4+3]<<24|t[p*4]<<16|t[p*4+1]<<8|t[p*4+2])>>>0;if(i[p]=h,o.add(h),o.size>256)return null}let r=[...o].sort((p,h)=>p-h),c=new Map;r.forEach((p,h)=>{c.set(p,h)});let a=M2(r.length),l=8>>a,u=e+(1<<a)-1>>a,m=new Uint32Array(u*n);m.fill(4278190080);for(let p=0;p<n;p++)for(let h=0;h<e;h++){let C=c.get(i[p*e+h]),v=p*u+(h>>a);m[v]=(m[v]|C<<l*(h&(1<<a)-1)+8)>>>0}let f=!1;for(let p of r)if(p>>>24!==255){f=!0;break}let b=new c5;b.putBits(47,8),b.putBits(e-1,14),b.putBits(n-1,14),b.putBits(f?1:0,1),b.putBits(0,3),b.putBits(1,1),b.putBits(3,2),b.putBits(r.length-1,8);let x=new Uint32Array(r.length),g=0;for(let p=0;p<r.length;p++){let h=r[p];x[p]=((h>>>24)-(g>>>24)&255)*16777216+(((h>>>16)-(g>>>16)&255)<<16)+(((h>>>8)-(g>>>8)&255)<<8)+(h-g&255)>>>0,g=h}return v5(b,x,r.length,!1),b.putBits(0,1),v5(b,m,u,!0),b.finish()}var z5=[0,8,2,10,12,4,14,6,3,11,1,9,15,7,13,5];function w2(t,e,n=16,o=1){let s=255/(n-1),i=new Uint8Array(t.length);if(o<=0){let c=new Uint8Array(256);for(let a=0;a<256;a++)c[a]=Math.round(Math.round(a/s)*s);for(let a=0;a<t.length;a++)i[a]=c[t[a]];return i}let r=o>1?1:o;for(let c=0;c<t.length;c++){let a=c%e,l=c/e|0,u=((z5[(l&3)*4+(a&3)]+.5)/16-.5)*r,m=Math.round(t[c]/s+u),f=Math.round(m*s);i[c]=f<0?0:f>255?255:f}return i}function F2(t,e,n=16,o=1){let s=new Uint32Array(256),i=255,r=0,c=0;for(let p=0;p<t.length;p++){let h=t[p];s[h]===0&&c++,s[h]++,h<i&&(i=h),h>r&&(r=h)}if(c<=n)return t.slice();let a=new Float64Array(n);for(let p=0;p<n;p++)a[p]=i+(r-i)*p/(n-1);let l=1/0,u=new Uint8Array(256);for(let p=0;p<6;p++){let h=new Float64Array(n),C=new Float64Array(n),v=0;for(let A=i;A<=r;A++){for(;v<n-1&&2*A>a[v]+a[v+1];)v++;u[A]=v,h[v]+=A*s[A],C[v]+=s[A]}for(let A=1;A<n-1;A++)C[A]>0&&(a[A]=h[A]/C[A]);let T=0;for(let A=i;A<=r;A++){let _=A-a[u[A]];T+=s[A]*_*_}if(l-T<1e-4*t.length)break;l=T}let m=new Uint8Array(n);for(let p=0;p<n;p++)m[p]=Math.round(a[p]);m[0]=i,m[n-1]=r;let f=new Uint8Array(256),b=new Float64Array(256);{let p=0;for(let h=i;h<=r;h++){for(;p<n-2&&h>=m[p+1];)p++;f[h]=p;let C=m[p+1]-m[p];b[h]=C>0?(h-m[p])/C:0}}let x=o<=0?0:o>1?1:o,g=new Uint8Array(t.length);for(let p=0;p<t.length;p++){let h=t[p],C;if(x>0){let v=p%e,T=p/e|0,A=((z5[(T&3)*4+(v&3)]+.5)/16-.5)*x;C=f[h]+Math.round(b[h]+A)}else C=f[h]+Math.round(b[h]);g[p]=m[C<0?0:C>=n?n-1:C]}return g}var a5=0,J5=1,t2=2,R2=3;function T2(t){return t<0?0:t>255?255:t}function _2(t,e,n,o){if(o===a5)return t;let s=new Uint8Array(t.length);for(let i=0;i<n;i++)for(let r=0;r<e;r++){let c=i*e+r,a;r===0&&i===0?a=0:o===J5?a=r>0?t[c-1]:t[c-e]:o===t2?a=i>0?t[c-e]:t[c-1]:i===0?a=t[c-1]:r===0?a=t[c-e]:a=T2(t[c-1]+t[c-e]-t[c-e-1]),s[c]=t[c]-a&255}return s}function S2(t){let e=new Uint32Array(256),n=0;for(let s=0;s<t.length;s++)s>0&&t[s]===t[s-1]||(e[t[s]]++,n++);if(n===0)return 0;let o=0;for(let s=0;s<256;s++){if(e[s]===0)continue;let i=e[s]/n;o-=i*Math.log2(i)}return n*(o+2)}function n2(t,e,n,o=16,s=1,i=!0){let r=i?F2(t,e,o,s):w2(t,e,o,s),c=!0;for(let f=0;f<t.length;f++)if(r[f]!==t[f]){c=!1;break}let a=c?[{plane:t,preprocessing:0}]:[{plane:t,preprocessing:0},{plane:r,preprocessing:1}],l=null,u=a5,m=t;for(let{plane:f,preprocessing:b}of a){let x=[a5,J5,t2,R2].map(g=>({f:g,filtered:_2(f,e,n,g)})).map(g=>({...g,h:S2(g.filtered)})).sort((g,p)=>g.h-p.h).slice(0,2);for(let{f:g,filtered:p}of x){let h=K5(p,e,n);if(l===null||h.length+1<l.length){let C=new Uint8Array(1+h.length);C[0]=1|g<<2|b<<4,C.set(h,1),l=C,u=g,m=f}}}if(1+t.length<l.length){let f=new Uint8Array(1+t.length);return f[0]=0,f.set(t,1),{payload:f,filter:a5,quantized:t}}return{payload:l,filter:u,quantized:m}}function e2(t){let e=t.length/4,n=new Uint8Array(e);for(let o=0;o<e;o++)n[o]=t[o*4+3];return n}function z(t){return[t.charCodeAt(0),t.charCodeAt(1),t.charCodeAt(2),t.charCodeAt(3)]}function I5(t){return[t&255,t>>>8&255,t>>>16&255,t>>>24&255]}function r2(t){return[t&255,t>>>8&255,t>>>16&255]}function f5(t,e){let n=e.length+(e.length&1),o=new Uint8Array(8+n);return o.set(z(t),0),o.set(I5(e.length),4),o.set(e,8),o}function M5(t){let e=[];if(t.alph){let i=new Uint8Array(10);i[0]=16,i.set(r2(t.width-1),4),i.set(r2(t.height-1),7),e.push(f5("VP8X",i)),e.push(f5("ALPH",t.alph))}e.push(f5("VP8 ",t.vp8));let n=e.reduce((i,r)=>i+r.length,0),o=new Uint8Array(12+n);o.set(z("RIFF"),0),o.set(I5(4+n),4),o.set(z("WEBP"),8);let s=12;for(let i of e)o.set(i,s),s+=i.length;return o}function o2(t){let e=f5("VP8L",t),n=new Uint8Array(12+e.length);return n.set(z("RIFF"),0),n.set(I5(4+e.length),4),n.set(z("WEBP"),8),n.set(e,12),n}function k2(t,e,n){return 16839*t+33059*e+6420*n+32768+(16<<16)>>16}function i2(t){return t=t+32768+8388608>>16,t<0?0:t>255?255:t}function N2(t,e,n){return i2(-9719*t-19081*e+28800*n)}function V2(t,e,n){return i2(28800*t-24116*e-4684*n)}function s2(t,e,n){let o=e+15>>4,s=n+15>>4,i=o*16,r=o*8,c=new Uint8Array(i*s*16),a=new Uint8Array(r*s*8),l=new Uint8Array(r*s*8);for(let u=0;u<s*16;u++){let m=u<n?u:n-1;for(let f=0;f<i;f++){let b=f<e?f:e-1,x=(m*e+b)*4;c[u*i+f]=k2(t[x],t[x+1],t[x+2])}}for(let u=0;u<s*8;u++)for(let m=0;m<r;m++){let f=0,b=0,x=0;for(let g=0;g<2;g++)for(let p=0;p<2;p++){let h=m*2+p,C=u*2+g;h>=e&&(h=e-1),C>=n&&(C=n-1);let v=(C*e+h)*4;f+=t[v],b+=t[v+1],x+=t[v+2]}f=f+2>>2,b=b+2>>2,x=x+2>>2,a[u*r+m]=N2(f,b,x),l[u*r+m]=V2(f,b,x)}return{width:e,height:n,mbW:o,mbH:s,yStride:i,uvStride:r,y:c,u:a,v:l}}var O2=[7,6,6,5,5,5,5,4,4,4,4,4,4,4,4,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0],u2=[127,127,191,127,159,191,223,127,143,159,175,191,207,223,239,127,135,143,151,159,167,175,183,191,199,207,215,223,231,239,247,127,131,135,139,143,147,151,155,159,163,167,171,175,179,183,187,191,195,199,203,207,211,215,219,223,227,231,235,239,243,247,251,127,129,131,133,135,137,139,141,143,145,147,149,151,153,155,157,159,161,163,165,167,169,171,173,175,177,179,181,183,185,187,189,191,193,195,197,199,201,203,205,207,209,211,213,215,217,219,221,223,225,227,229,231,233,235,237,239,241,243,245,247,249,251,253,127],J=class{constructor(){O(this,"range",254);O(this,"value",0);O(this,"run",0);O(this,"nbBits",-8);O(this,"buf",[])}flush(){let e=8+this.nbBits,n=this.value>>e;if(this.value-=n<<e,this.nbBits-=8,(n&255)!==255){if(n&256){let s=this.buf.length-1;s>=0&&this.buf[s]++}let o=n&256?0:255;for(;this.run>0;this.run--)this.buf.push(o);this.buf.push(n&255)}else this.run++}putBit(e,n){let o=e?1:0,s=this.range*n>>8;if(o?(this.value+=s+1,this.range-=s+1):this.range=s,this.range<127){let i=O2[this.range];this.range=u2[this.range],this.value<<=i,this.nbBits+=i,this.nbBits>0&&this.flush()}return!!o}putBitUniform(e){let n=e?1:0,o=this.range>>1;return n?(this.value+=o+1,this.range-=o+1):this.range=o,this.range<127&&(this.range=u2[this.range],this.value<<=1,this.nbBits+=1,this.nbBits>0&&this.flush()),!!n}putBits(e,n){for(let o=1<<n-1;o;o>>>=1)this.putBitUniform(e&o)}putSignedBits(e,n){this.putBitUniform(e!==0)&&(e<0?this.putBits(-e<<1|1,n+1):this.putBits(e<<1,n+1))}finish(){return this.putBits(0,9-this.nbBits),this.nbBits=0,this.flush(),new Uint8Array(this.buf)}};function m5(t){return(t*20091>>16)+t|0}function b5(t){return t*35468>>16|0}function p5(t){return t<0?0:t>255?255:t}var y=new Int32Array(16);function w5(t,e,n,o,s,i){for(let r=0;r<4;r++){let c=e+r*s,a=o+r*s,l=t[c]-n[a],u=t[c+1]-n[a+1],m=t[c+2]-n[a+2],f=t[c+3]-n[a+3],b=l+f,x=u+m,g=u-m,p=l-f;y[0+r*4]=(b+x)*8,y[1+r*4]=g*2217+p*5352+1812>>9,y[2+r*4]=(b-x)*8,y[3+r*4]=p*2217-g*5352+937>>9}for(let r=0;r<4;r++){let c=y[0+r]+y[12+r],a=y[4+r]+y[8+r],l=y[4+r]-y[8+r],u=y[0+r]-y[12+r];i[0+r]=c+a+7>>4,i[4+r]=(l*2217+u*5352+12e3>>16)+(u!==0?1:0),i[8+r]=c-a+7>>4,i[12+r]=u*2217-l*5352+51e3>>16}}function F5(t,e,n,o,s,i){for(let r=0;r<4;r++){let c=t[r]+t[8+r],a=t[r]-t[8+r],l=b5(t[4+r])-m5(t[12+r]),u=m5(t[4+r])+b5(t[12+r]);y[r*4+0]=c+u,y[r*4+1]=a+l,y[r*4+2]=a-l,y[r*4+3]=c-u}for(let r=0;r<4;r++){let c=y[0+r]+4,a=c+y[8+r],l=c-y[8+r],u=b5(y[4+r])-m5(y[12+r]),m=m5(y[4+r])+b5(y[12+r]),f=i+r*o,b=n+r*o;s[f]=p5(e[b]+(a+m>>3)),s[f+1]=p5(e[b+1]+(l+u>>3)),s[f+2]=p5(e[b+2]+(l-u>>3)),s[f+3]=p5(e[b+3]+(a-m>>3))}}function l2(t,e){for(let n=0;n<4;n++){let o=n*4,s=t[o]+t[o+2],i=t[o+1]+t[o+3],r=t[o+1]-t[o+3],c=t[o]-t[o+2];y[0+n*4]=s+i,y[1+n*4]=c+r,y[2+n*4]=c-r,y[3+n*4]=s-i}for(let n=0;n<4;n++){let o=y[0+n]+y[8+n],s=y[4+n]+y[12+n],i=y[4+n]-y[12+n],r=y[0+n]-y[8+n],c=o+s,a=r+i,l=r-i,u=o-s;e[0+n]=c>>1,e[4+n]=a>>1,e[8+n]=l>>1,e[12+n]=u>>1}}function c2(t,e){for(let n=0;n<4;n++){let o=t[0+n]+t[12+n],s=t[4+n]+t[8+n],i=t[4+n]-t[8+n],r=t[0+n]-t[12+n];y[0+n]=o+s,y[8+n]=o-s,y[4+n]=r+i,y[12+n]=r-i}for(let n=0;n<4;n++){let o=y[0+n*4]+3,s=o+y[3+n*4],i=y[1+n*4]+y[2+n*4],r=y[1+n*4]-y[2+n*4],c=o-y[3+n*4];e[n*4+0]=s+i>>3,e[n*4+1]=c+r>>3,e[n*4+2]=s-i>>3,e[n*4+3]=c-r>>3}}var a2=2047,y5=0,V5=1,O5=2,f2=3;function A5(t,e){let n=Math.round(t)|0;return n<0?0:n>e?e:n}function D2(t){let e=A5(t,127),n=K[e]*101581>>16;return{y1:{dc:u5[e],ac:K[e],dcBias:96,acBias:110},y2:{dc:u5[e]*2,ac:n<8?8:n,dcBias:96,acBias:108},uv:{dc:u5[A5(e,117)],ac:K[e],dcBias:110,acBias:115}}}function H2(t,e){let n=K[A5(t,127)]>>2,s=(n>63?63:n)*5*e/256|0;return s<1?0:s>63?63:s}function R5(t,e,n,o){let s=new Int16Array(16),i=-1;for(let r=n;r<16;r++){let c=$5[r],a=r===0?o.dc:o.ac,l=r===0?o.dcBias:o.acBias,u=t[c],f=((u<0?-u:u)*256+l*a)/(256*a)|0;f>a2&&(f=a2),s[r]=u<0?-f:f,e[c]=s[r]*a,f&&(i=r)}return{levels:s,last:i}}function m2(t,e,n,o){return(((t*8+e)*3+n)*11+o)*2}function h5(t,e){let n=t?255-e:e;return Math.round(-Math.log2((n<1?1:n)/256)*256)}function T5(t,e,n,o,s){let i=(a,l,u,m,f)=>{let b=m2(l,u,m,f);return t[b]+=a?1:0,t[b+1]++,!!a},r=o,c=D[r];if(!i(s.last>=0,n,c,e,0))return 0;for(;r<16;){let a=s.levels[r++],u=a<0?-a:a;if(!i(u!==0,n,c,e,1)){c=D[r],e=0;continue}if(i(u>1,n,c,e,2)?(i(u>4,n,c,e,3)?i(u>10,n,c,e,6)?(i(u>=35,n,c,e,8),u>=35?i(u>=67,n,c,e,10):i(u>=19,n,c,e,9)):i(u>6,n,c,e,7):i(u!==2,n,c,e,4)&&i(u===4,n,c,e,5),c=D[r],e=2):(c=D[r],e=1),r===16||!i(r<=s.last,n,c,e,0))return 1}return 1}function q2(t){let e=s5.map(n=>n.map(o=>o.map(s=>s.slice())));for(let n=0;n<4;n++)for(let o=0;o<8;o++)for(let s=0;s<3;s++)for(let i=0;i<11;i++){let r=m2(n,o,s,i),c=t[r],a=t[r+1];if(a===0)continue;let l=C5[n][o][s][i],u=s5[n][o][s][i],m=c?255-Math.floor(c*255/a):255,f=g=>c*h5(1,g)+(a-c)*h5(0,g),b=f(u)+h5(0,l),x=f(m)+h5(1,l)+8*256;b>x&&(e[n][o][s][i]=m)}return e}function _5(t,e,n,o,s){let i=o,r=n[i][e];if(!t.putBit(s.last>=0,r[0]))return 0;for(;i<16;){let c=s.levels[i++],a=c<0,l=a?-c:c;if(!t.putBit(l!==0,r[1])){r=n[D[i]][0];continue}if(!t.putBit(l>1,r[2]))r=n[D[i]][1];else{if(!t.putBit(l>4,r[3]))t.putBit(l!==2,r[4])&&t.putBit(l===4,r[5]);else if(!t.putBit(l>10,r[6]))t.putBit(l>6,r[7])?(t.putBit(l>=9,165),t.putBit(!(l&1),145)):t.putBit(l===6,159);else{let u,m;l<19?(t.putBit(0,r[8]),t.putBit(0,r[9]),l-=11,u=4,m=G5):l<35?(t.putBit(0,r[8]),t.putBit(1,r[9]),l-=19,u=8,m=Q5):l<67?(t.putBit(1,r[8]),t.putBit(0,r[10]),l-=35,u=16,m=X5):(t.putBit(1,r[8]),t.putBit(1,r[10]),l-=67,u=1024,m=Z5);let f=0;for(;u;)t.putBit(l&u,m[f++]),u>>=1}r=n[D[i]][2]}if(t.putBitUniform(a),i===16||!t.putBit(i<=s.last,r[0]))return 1}return 1}function W2(t){return t<0?0:t>255?255:t}function S5(t,e,n,o,s,i,r,c,a){if(t===y5){let u;if(r||c){let m=0;if(r)for(let b=0;b<i;b++)m+=e[(s-1)*n+o+b];if(c)for(let b=0;b<i;b++)m+=e[(s+b)*n+o-1];let f=(i===16?4:3)+(r&&c?1:0);u=m+(1<<f-1)>>f}else u=128;a.fill(u,0,i*i);return}if(t===V5){for(let u=0;u<i;u++){let m=r?e[(s-1)*n+o+u]:127;for(let f=0;f<i;f++)a[f*i+u]=m}return}if(t===O5){for(let u=0;u<i;u++){let m=c?e[(s+u)*n+o-1]:129;a.fill(m,u*i,u*i+i)}return}let l=r?c?e[(s-1)*n+o-1]:129:127;for(let u=0;u<i;u++){let m=c?e[(s+u)*n+o-1]:129;for(let f=0;f<i;f++){let b=r?e[(s-1)*n+o+f]:127;a[u*i+f]=W2(m+b-l)}}}function k5(t,e,n,o,s,i){let r=0;for(let c=0;c<s;c++){let a=(o+c)*e+n,l=c*s;for(let u=0;u<s;u++){let m=t[a+u]-i[l+u];r+=m<0?-m:m}}return r}function N5(t,e,n,o,s,i){for(let r=0;r<i;r++)e.set(t.subarray(r*i,r*i+i),(s+r)*n+o)}function b2(t,e){let{mbW:n,mbH:o,yStride:s,uvStride:i}=t,r=A5(e.qi,127),c=D2(r),a=H2(r,e.filterStrength??60),l=new Uint8Array(t.y.length),u=new Uint8Array(t.u.length),m=new Uint8Array(t.v.length),f=new Int16Array(16),b=new Int16Array(16),x=new Int16Array(16),g=new Int16Array(16),p=new Uint8Array(256),h=new Uint8Array(256),C=new Uint8Array(64),v=new Uint8Array(64),T=new Uint8Array(64),A=new Uint8Array(64),_=Array.from({length:16},()=>new Int16Array(16)),H=new Int16Array(16),d5=new Array(n*o),H5=0;for(let w=0;w<o;w++)for(let L=0;L<n;L++){let I=w>0,E=L>0,M=L*16,R=w*16,B=L*8,U=w*8,F=y5,V=1/0;for(let d=0;d<4;d++){S5(d,l,s,M,R,16,I,E,p);let k=k5(t.y,s,M,R,16,p);k<V&&(V=k,F=d,h.set(p))}N5(h,l,s,M,R,16);let q=new Array(16);for(let d=0;d<16;d++){let k=M+(d&3)*4,N=(R+(d>>2)*4)*s+k;w5(t.y,N,l,N,s,f),b[d]=f[0],q[d]=R5(f,_[d],1,c.y1)}l2(b,x);let o5=R5(x,g,0,c.y2);c2(g,b);for(let d=0;d<16;d++){let k=M+(d&3)*4,N=(R+(d>>2)*4)*s+k;_[d][0]=b[d],F5(_[d],l,N,s,l,N)}let W5=y5,Y5=1/0;for(let d=0;d<4;d++){S5(d,u,i,B,U,8,I,E,C),S5(d,m,i,B,U,8,I,E,v);let k=k5(t.u,i,B,U,8,C)+k5(t.v,i,B,U,8,v);k<Y5&&(Y5=k,W5=d,T.set(C),A.set(v))}N5(T,u,i,B,U,8),N5(A,m,i,B,U,8);let U5=new Array(8);for(let d=0;d<2;d++){let k=d===0?t.u:t.v,Z=d===0?u:m;for(let N=0;N<4;N++){let d2=B+(N&1)*4,i5=(U+(N>>1)*4)*i+d2;w5(k,i5,Z,i5,i,f),U5[d*4+N]=R5(f,H,0,c.uv),F5(H,Z,i5,i,Z,i5)}}let Y=o5.last<0;if(Y){for(let d of q)if(d.last>=0){Y=!1;break}}if(Y){for(let d of U5)if(d.last>=0){Y=!1;break}}Y&&H5++,d5[w*n+L]={yMode:F,uvMode:W5,skip:Y,y2:o5,luma:q,uv:U5}}let g5=n*o,B5=g5?(g5-H5)*255/g5|0:255,t5=B5<250,n5=new Uint32Array(1056*2);{let w=Array.from({length:n},()=>new Array(9).fill(0));for(let L=0;L<o;L++){let I=new Array(9).fill(0);for(let E=0;E<n;E++){let M=d5[L*n+E],R=w[E];if(t5&&M.skip){R.fill(0),I.fill(0);continue}R[8]=I[8]=T5(n5,R[8]+I[8],1,0,M.y2);for(let B=0;B<4;B++)for(let U=0;U<4;U++){let F=R[U]+I[B],V=T5(n5,F,0,1,M.luma[B*4+U]);R[U]=I[B]=V}for(let B=0;B<=2;B+=2)for(let U=0;U<2;U++)for(let F=0;F<2;F++){let V=R[4+B+F]+I[4+B+U],q=T5(n5,V,2,0,M.uv[(B>>1)*4+U*2+F]);R[4+B+F]=I[4+B+U]=q}}}}let e5=q2(n5),P=new J,r5=new J;P.putBitUniform(0),P.putBitUniform(0),P.putBitUniform(0),P.putBitUniform(0),P.putBits(a,6),P.putBits(0,3),P.putBitUniform(0),P.putBits(0,2),P.putBits(r,7),P.putSignedBits(0,4),P.putSignedBits(0,4),P.putSignedBits(0,4),P.putSignedBits(0,4),P.putSignedBits(0,4),P.putBitUniform(0);for(let w=0;w<4;w++)for(let L=0;L<8;L++)for(let I=0;I<3;I++)for(let E=0;E<11;E++){let M=e5[w][L][I][E],R=M!==s5[w][L][I][E];P.putBit(R,C5[w][L][I][E])&&P.putBits(M,8)}P.putBitUniform(t5)&&P.putBits(B5,8);let p2=e5[1],h2=e5[0],y2=e5[2],A2=Array.from({length:n},()=>new Array(9).fill(0));for(let w=0;w<o;w++){let L=new Array(9).fill(0);for(let I=0;I<n;I++){let E=d5[w*n+I];t5&&P.putBit(E.skip,B5),P.putBit(1,145),P.putBit(E.yMode===f2||E.yMode===O5,156)?P.putBit(E.yMode===f2,128):P.putBit(E.yMode===V5,163),P.putBit(E.uvMode!==y5,142)&&P.putBit(E.uvMode!==V5,114)&&P.putBit(E.uvMode!==O5,183);let M=A2[I];if(t5&&E.skip){M.fill(0),L.fill(0);continue}let R=_5(r5,M[8]+L[8],p2,0,E.y2);M[8]=L[8]=R;for(let B=0;B<4;B++)for(let U=0;U<4;U++){let F=M[U]+L[B],V=_5(r5,F,h2,1,E.luma[B*4+U]);M[U]=L[B]=V}for(let B=0;B<=2;B+=2)for(let U=0;U<2;U++)for(let F=0;F<2;F++){let V=M[4+B+F]+L[4+B+U],q=E.uv[(B>>1)*4+U*2+F],o5=_5(r5,V,y2,0,q);M[4+B+F]=L[4+B+U]=o5}}}let W=P.finish(),q5=r5.finish();if(W.length>=1<<19)throw new RangeError(`VP8: partition 0 is ${W.length} bytes, exceeding the bitstream's 2^19-1 limit \u2014 image too large/complex for a VP8 keyframe`);let x5=16|W.length<<5,S=new Uint8Array(10+W.length+q5.length);return S[0]=x5&255,S[1]=x5>>>8&255,S[2]=x5>>>16&255,S[3]=157,S[4]=1,S[5]=42,S[6]=t.width&255,S[7]=t.width>>8&63,S[8]=t.height&255,S[9]=t.height>>8&63,S.set(W,10),S.set(q5,10+W.length),S}var D5=16383;function Y2(t,e,n){if(!Number.isInteger(t)||!Number.isInteger(e))throw new RangeError(`encodeWebP: width and height must be integers (got ${t}\xD7${e})`);if(t<1||e<1)throw new RangeError(`encodeWebP: width and height must be \u2265 1 (got ${t}\xD7${e})`);if(t>D5||e>D5)throw new RangeError(`encodeWebP: width and height must be \u2264 ${D5} (got ${t}\xD7${e})`);let o=t*e*4;if(n<o)throw new RangeError(`encodeWebP: data too short \u2014 need ${o} bytes for a ${t}\xD7${e} RGBA image, got ${n}`)}function $2(t){if(t.quality!==void 0&&!Number.isFinite(t.quality))throw new RangeError(`encodeWebP: quality must be a finite number (got ${t.quality})`);if(t.alphaDither!==void 0&&!Number.isFinite(t.alphaDither))throw new RangeError(`encodeWebP: alphaDither must be a finite number (got ${t.alphaDither})`)}function G2(t){let e=(t<0?0:t>100?100:t)/100,n=e<.75?e*(2/3):2*e-1,o=Math.cbrt(n);return Math.round(127*(1-o))}function Q2(t){let e=0,n=0,o=0,s=0,i=0;for(let u=0;u<t.length;u+=4)t[u+3]===0?i++:(e+=t[u],n+=t[u+1],o+=t[u+2],s++);if(i===0)return t;let r=s?Math.round(e/s):255,c=s?Math.round(n/s):255,a=s?Math.round(o/s):255,l=t.slice();for(let u=0;u<l.length;u+=4)l[u+3]===0&&(l[u]=r,l[u+1]=c,l[u+2]=a);return l}function At(t,e={}){let{width:n,height:o}=t;Y2(n,o,t.data.length),$2(e);let s=(t.data instanceof Uint8Array?t.data:new Uint8Array(t.data.buffer,t.data.byteOffset,t.data.byteLength)).subarray(0,n*o*4),i=e2(s),r=!1;for(let b=0;b<i.length;b++)if(i[b]!==255){r=!0;break}let c=r?Q2(s):s,a=e.lossless??"auto",l=null;if(a!==!1){let b=j5(s,n,o);if(b&&(l=o2(b)),l&&a===!0)return l}let u=s2(c,n,o),m=b2(u,{qi:G2(e.quality??80)}),f;if(!r)f=M5({width:n,height:o,vp8:m});else{let b=n2(i,n,o,e.alphaLevels??16,e.alphaDither??1,e.alphaAdaptive??!0);f=M5({width:n,height:o,vp8:m,alph:b.payload})}return l&&l.length<=f.length?l:f}export{At as encodeWebP,x2 as hasNativeWebPEncoder};
@@ -0,0 +1,19 @@
1
+ /** RFC 6386 §13.5 default coefficient probabilities [type][band][ctx][proba]. */
2
+ export declare const COEFFS_PROBA0: number[][][][];
3
+ /** RFC 6386 §13.4 coefficient probability update probabilities. */
4
+ export declare const COEFFS_UPDATE_PROBA: number[][][][];
5
+ /** RFC 6386 §14.1 DC dequantization lookup, indexed by QP 0..127. */
6
+ export declare const DC_TABLE: number[];
7
+ /** RFC 6386 §14.1 AC dequantization lookup, indexed by QP 0..127. */
8
+ export declare const AC_TABLE: number[];
9
+ /** Zigzag scan order: coefficient n is stored at block position ZIGZAG[n]. */
10
+ export declare const ZIGZAG: number[];
11
+ /** Coefficient position -> probability band (VP8EncBands, incl. sentinel). */
12
+ export declare const BANDS: number[];
13
+ /** Extra-bit probabilities for large-level categories (RFC 6386 §13.2). */
14
+ export declare const CAT3: number[];
15
+ export declare const CAT4: number[];
16
+ export declare const CAT5: number[];
17
+ export declare const CAT6: number[];
18
+ /** VP8L distance → 2D plane-code LUT (backward_references_enc.c). */
19
+ export declare const PLANE_TO_CODE: number[];
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Forward DCT of (src - ref) for one 4x4 block.
3
+ * src/ref are sampled at (x + y*stride); out receives 16 coefficients.
4
+ */
5
+ export declare function fdct4x4(src: Uint8Array, srcOff: number, ref: Uint8Array, refOff: number, stride: number, out: Int16Array): void;
6
+ /**
7
+ * Inverse DCT: dst = clip(ref + idct(coeffs)) for one 4x4 block.
8
+ * dst may alias ref (in-place reconstruction over the prediction).
9
+ */
10
+ export declare function idct4x4(coeffs: Int16Array, ref: Uint8Array, refOff: number, stride: number, dst: Uint8Array, dstOff: number): void;
11
+ /**
12
+ * Forward Walsh-Hadamard transform over the 16 luma-block DC values.
13
+ * `dcs` holds the DC of luma block k at index k (raster order within the MB).
14
+ */
15
+ export declare function fwht4x4(dcs: Int16Array, out: Int16Array): void;
16
+ /**
17
+ * Inverse WHT (RFC 6386 §14.3): dequantized Y2 block (block order) → the 16
18
+ * luma-block DC values, raster order.
19
+ */
20
+ export declare function iwht4x4(coeffs: Int16Array, dcs: Int16Array): void;
package/dist/vp8.d.ts ADDED
@@ -0,0 +1,9 @@
1
+ import type { YuvImage } from "./yuv.ts";
2
+ export interface Vp8Options {
3
+ /** Quantizer index 0..127 (lower = better quality). */
4
+ qi: number;
5
+ /** Loop-filter strength 0..100 (cwebp -f). Default 60. */
6
+ filterStrength?: number;
7
+ }
8
+ /** Encode a padded YUV420 image as a VP8 keyframe ("VP8 " chunk payload). */
9
+ export declare function encodeVP8Frame(yuv: YuvImage, opts: Vp8Options): Uint8Array;
package/dist/vp8l.d.ts ADDED
@@ -0,0 +1,44 @@
1
+ export declare class LsbBitWriter {
2
+ private buf;
3
+ private acc;
4
+ private used;
5
+ putBits(value: number, nBits: number): void;
6
+ finish(): Uint8Array;
7
+ }
8
+ interface PrefixCode {
9
+ code: number;
10
+ extraBits: number;
11
+ extraValue: number;
12
+ }
13
+ export declare function prefixEncode(value: number): PrefixCode;
14
+ /** Map a linear distance to the VP8L 2D "plane code". */
15
+ export declare function distanceToPlaneCode(xsize: number, dist: number): number;
16
+ interface HuffmanCode {
17
+ /** code bits, already reversed for the LSB-first stream */
18
+ codes: Uint16Array;
19
+ lengths: Uint8Array;
20
+ }
21
+ /**
22
+ * Build depth-limited canonical Huffman code lengths from symbol counts.
23
+ * Standard two-queue Huffman; on depth overflow, halve counts and retry.
24
+ */
25
+ export declare function buildCodeLengths(counts: Uint32Array, maxDepth: number): Uint8Array;
26
+ /** Canonical code assignment (VP8LConvertBitDepthsToSymbols), pre-reversed. */
27
+ export declare function lengthsToCodes(lengths: Uint8Array): HuffmanCode;
28
+ /** Write one Huffman code to the stream. `lengths` covers the full alphabet. */
29
+ export declare function writeHuffmanCode(bw: LsbBitWriter, lengths: Uint8Array): void;
30
+ /**
31
+ * Encode a (filtered) alpha plane as a headerless VP8L stream — the payload
32
+ * that follows the ALPH header byte for compression method 1. Alpha values
33
+ * ride in the green channel; the other channels are constant.
34
+ */
35
+ export declare function encodeAlphaVP8L(data: Uint8Array, width: number, height: number): Uint8Array;
36
+ /** Spec-mandated pixel bundling: indices packed per coded pixel. */
37
+ export declare function paletteWidthBits(paletteSize: number): number;
38
+ /**
39
+ * Encode interleaved RGBA as a complete "VP8L" chunk payload (lossless),
40
+ * using the color-indexing (palette) transform. Returns null when the image
41
+ * has more than 256 distinct colors — the caller should stick with lossy.
42
+ */
43
+ export declare function encodeVP8L(rgba: Uint8Array | Uint8ClampedArray, width: number, height: number): Uint8Array | null;
44
+ export {};
package/dist/yuv.d.ts ADDED
@@ -0,0 +1,16 @@
1
+ export interface YuvImage {
2
+ width: number;
3
+ height: number;
4
+ mbW: number;
5
+ mbH: number;
6
+ yStride: number;
7
+ uvStride: number;
8
+ y: Uint8Array;
9
+ u: Uint8Array;
10
+ v: Uint8Array;
11
+ }
12
+ /**
13
+ * Convert interleaved RGBA to padded YUV420. Alpha is ignored (the alpha
14
+ * plane travels separately in the ALPH chunk).
15
+ */
16
+ export declare function rgbaToYuv420(rgba: Uint8Array | Uint8ClampedArray, width: number, height: number): YuvImage;
package/package.json ADDED
@@ -0,0 +1,70 @@
1
+ {
2
+ "name": "@graysonlang/slim-webp-enc",
3
+ "version": "1.0.0",
4
+ "description": "Pure-TypeScript lossy WebP thumbnail encoder with alpha support",
5
+ "keywords": [
6
+ "webp",
7
+ "webp-encoder",
8
+ "encoder",
9
+ "image",
10
+ "compression",
11
+ "thumbnail",
12
+ "alpha",
13
+ "transparency",
14
+ "canvas",
15
+ "safari",
16
+ "webkit",
17
+ "vp8",
18
+ "browser",
19
+ "typescript",
20
+ "zero-dependencies"
21
+ ],
22
+ "homepage": "https://github.com/graysonlang/slim-webp-enc#readme",
23
+ "bugs": {
24
+ "url": "https://github.com/graysonlang/slim-webp-enc/issues"
25
+ },
26
+ "repository": {
27
+ "type": "git",
28
+ "url": "git+https://github.com/graysonlang/slim-webp-enc.git"
29
+ },
30
+ "license": "MIT",
31
+ "author": "Grayson Lang",
32
+ "type": "module",
33
+ "exports": {
34
+ ".": {
35
+ "types": "./dist/index.d.ts",
36
+ "default": "./dist/index.js"
37
+ }
38
+ },
39
+ "main": "./dist/index.js",
40
+ "types": "./dist/index.d.ts",
41
+ "files": [
42
+ "dist"
43
+ ],
44
+ "scripts": {
45
+ "build": "node ./scripts/build.mjs --minify",
46
+ "serve": "node ./scripts/build.mjs --sourcemap --watch --serve --debug-port=9222",
47
+ "dev": "npm run serve -- --proxy --launch",
48
+ "vscode:build": "npm run build -- --vscode",
49
+ "vscode:debug": "npm run serve -- --vscode",
50
+ "dist": "node ./scripts/dist.mjs",
51
+ "prepare": "npm run dist",
52
+ "corpus": "node harness/corpus.ts",
53
+ "harness": "node harness/run.ts",
54
+ "compare": "node harness/compare.ts",
55
+ "typecheck": "tsc --noEmit",
56
+ "size": "node harness/size-gate.ts"
57
+ },
58
+ "devDependencies": {
59
+ "@graysonlang/esp": "^1.6.2",
60
+ "@jsquash/webp": "^1.5.0",
61
+ "@types/node": "^24.0.0",
62
+ "esbuild": "^0.28.1",
63
+ "sharp": "^0.34.0",
64
+ "typescript": "^5.8.0"
65
+ },
66
+ "publishConfig": {
67
+ "access": "public"
68
+ },
69
+ "sideEffects": false
70
+ }