@squoosh-kit/avif 0.2.1 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +274 -0
  2. package/package.json +2 -1
package/README.md ADDED
@@ -0,0 +1,274 @@
1
+ # @squoosh-kit/avif
2
+
3
+ [![npm version](https://badge.fury.io/js/%40squoosh-kit%2Favif.svg)](https://badge.fury.io/js/%40squoosh-kit%2Favif)
4
+ [![Bun](https://img.shields.io/badge/Bun-000000?logo=bun&logoColor=white)](https://bun.sh/)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![License: Apache 2.0](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://www.apache.org/licenses/LICENSE-2.0)
6
+ [![TypeScript](https://img.shields.io/badge/TypeScript-007ACC?logo=typescript&logoColor=white)](https://www.typescriptlang.org/)
7
+
8
+ ![Squoosh-Kit](https://github.com/bnowak008/squoosh-kit/blob/main/squoosh-kit-banner.webp)
9
+
10
+ ## Squoosh-Kit
11
+
12
+ Squoosh-Kit is built on a simple idea: provide a lightweight and modular bridge to the powerful, production-tested codecs from Google's Squoosh project. This package (`@squoosh-kit/avif`) is one of those modules.
13
+
14
+ **Directly from the Source**
15
+ We don't modify the core AVIF codec. The WebAssembly (`.wasm`) binary is taken directly from the official Squoosh repository builds. This means you get the exact same performance, quality, and reliability you'd expect from Squoosh.
16
+
17
+ **A Thin, Modern Wrapper**
18
+ Our goal is to provide a minimal, modern JavaScript wrapper around the codec. We handle the tricky parts—like loading WASM, managing web workers, and providing a clean, type-safe API—so you can focus on your application. The library is designed to be a thin bridge, not a heavy framework.
19
+
20
+ **Modular by Design**
21
+ We believe you should only install what you need. As a standalone package, `@squoosh-kit/avif` allows you to add AVIF encoding and decoding to your project without pulling in other unrelated image processing tools.
22
+
23
+ ## Installation
24
+
25
+ ```bash
26
+ bun add @squoosh-kit/avif
27
+ # or
28
+ npm install @squoosh-kit/avif
29
+ ```
30
+
31
+ ## Quick Start
32
+
33
+ ```typescript
34
+ import { encode, decode, createAvifEncoder, AVIFTune } from '@squoosh-kit/avif';
35
+ import type { ImageInput, AvifEncodeOptions } from '@squoosh-kit/avif';
36
+
37
+ const imageData: ImageInput = {
38
+ data: imageBuffer,
39
+ width: 1920,
40
+ height: 1080,
41
+ };
42
+
43
+ // Quick encode with default settings
44
+ const avifBuffer = await encode(imageData, { quality: 60 });
45
+
46
+ // With cancellation support
47
+ const controller = new AbortController();
48
+ const avif = await encode(
49
+ imageData,
50
+ { quality: 60, speed: 6 },
51
+ controller.signal
52
+ );
53
+
54
+ // Decode AVIF back to raw pixel data
55
+ const rawImage = await decode(avifBuffer);
56
+
57
+ // For multiple images, create a persistent encoder
58
+ const encoder = createAvifEncoder('worker');
59
+ const result = await encoder(imageData, { quality: 70, tune: AVIFTune.ssim });
60
+ await encoder.terminate();
61
+ ```
62
+
63
+ ## Public API
64
+
65
+ Only the following exports are part of the public API and guaranteed to be stable across versions:
66
+
67
+ - `encode(imageData, options?, signal?)` - Encode an image to AVIF format
68
+ - `decode(data, signal?)` - Decode an AVIF file to raw pixel data
69
+ - `createAvifEncoder(mode?)` - Create a reusable encoder function
70
+ - `createAvifDecoder(mode?)` - Create a reusable decoder function
71
+ - `AVIFTune` - Tuning mode enum (`auto`, `psnr`, `ssim`)
72
+ - `ImageInput` type - Input image data structure
73
+ - `AvifEncodeOptions` type - AVIF encoding configuration
74
+ - `AvifEncoderFactory` type - Type for reusable encoder functions
75
+ - `AvifDecoderFactory` type - Type for reusable decoder functions
76
+
77
+ ## Real-World Examples
78
+
79
+ **Serve optimized images to modern browsers**
80
+
81
+ ```typescript
82
+ const controller = new AbortController();
83
+ const timeout = setTimeout(() => controller.abort(), 30000);
84
+
85
+ try {
86
+ const avif = await encode(
87
+ uploadedImage,
88
+ {
89
+ quality: 60, // Good quality for most photos
90
+ speed: 6, // Faster encoding; lower = smaller files but slower
91
+ },
92
+ controller.signal
93
+ );
94
+
95
+ await saveToStorage('image.avif', avif);
96
+ } catch (error) {
97
+ if (error.name === 'AbortError') {
98
+ console.log('Encoding timed out');
99
+ }
100
+ } finally {
101
+ clearTimeout(timeout);
102
+ }
103
+ ```
104
+
105
+ **Batch conversion with quality tuning**
106
+
107
+ ```typescript
108
+ const encoder = createAvifEncoder('client'); // Direct encoding on the server
109
+
110
+ for (const imagePath of imageFiles) {
111
+ const imageData = await loadImage(imagePath);
112
+ const avifData = await encoder(imageData, {
113
+ quality: 65,
114
+ qualityAlpha: 80,
115
+ speed: 8,
116
+ });
117
+ await writeFile(`${imagePath}.avif`, avifData);
118
+ }
119
+
120
+ await encoder.terminate();
121
+ ```
122
+
123
+ ## API Reference
124
+
125
+ ### `encode(imageData, options?, signal?)`
126
+
127
+ Encodes raw RGBA pixel data to AVIF format.
128
+
129
+ **Note**: `encode()` uses a global singleton worker. For long-running applications where worker cleanup is important, use `createAvifEncoder()` instead.
130
+
131
+ - `imageData` - `ImageInput` object with your pixel data
132
+ - `options` - (optional) `AvifEncodeOptions` for quality and compression settings
133
+ - `signal` - (optional) `AbortSignal` to cancel the operation
134
+ - **Returns** - `Promise<Uint8Array>` with the encoded AVIF data
135
+
136
+ ### `decode(data, signal?)`
137
+
138
+ Decodes an AVIF file back to raw RGBA pixel data.
139
+
140
+ - `data` - `BufferSource` containing the AVIF file bytes
141
+ - `signal` - (optional) `AbortSignal` to cancel the operation
142
+ - **Returns** - `Promise<ImageData>` with decoded pixel data, width, and height
143
+
144
+ ### `createAvifEncoder(mode?)`
145
+
146
+ Creates a reusable encoder. More efficient for processing multiple images.
147
+
148
+ - `mode` - (optional) `'worker'` or `'client'`, defaults to `'worker'`
149
+ - **Returns** - A function with the same signature as `encode()`
150
+
151
+ ### `createAvifDecoder(mode?)`
152
+
153
+ Creates a reusable decoder.
154
+
155
+ - `mode` - (optional) `'worker'` or `'client'`, defaults to `'worker'`
156
+ - **Returns** - A function with the same signature as `decode()`
157
+
158
+ ## Cancellation Support
159
+
160
+ To cancel an encoding operation in progress, pass an `AbortSignal`:
161
+
162
+ ```typescript
163
+ const controller = new AbortController();
164
+
165
+ const encodePromise = encode(imageData, { quality: 60 }, controller.signal);
166
+ setTimeout(() => controller.abort(), 5000);
167
+
168
+ try {
169
+ const result = await encodePromise;
170
+ } catch (error) {
171
+ if (error.name === 'AbortError') {
172
+ console.log('Encoding was cancelled');
173
+ }
174
+ }
175
+ ```
176
+
177
+ **Important**: If no signal is provided, the encoding operation cannot be cancelled.
178
+
179
+ ## Input Validation
180
+
181
+ All inputs are automatically validated before processing:
182
+
183
+ ```typescript
184
+ // Will throw TypeError: image must be an object
185
+ await encode(null, { quality: 60 });
186
+
187
+ // Will throw TypeError: image.data must be Uint8Array or Uint8ClampedArray
188
+ await encode({ data: [0, 0, 0, 255], width: 32, height: 32 }, { quality: 60 });
189
+
190
+ // Will throw RangeError: image.data too small
191
+ await encode(
192
+ { data: new Uint8Array(100), width: 800, height: 600 },
193
+ { quality: 60 }
194
+ );
195
+ ```
196
+
197
+ ### Package Size
198
+
199
+ This package includes WebAssembly binaries for the AVIF codec (~60-80KB gzipped). AVIF encoding is computationally expensive; the WASM binary includes the full libaom encoder.
200
+
201
+ **Size breakdown:**
202
+
203
+ - JavaScript code: ~5-8KB gzipped
204
+ - TypeScript definitions: ~3KB
205
+ - WASM binaries: ~60-80KB gzipped (multi-threaded variants included)
206
+
207
+ ### Worker Cleanup
208
+
209
+ When using worker mode, always clean up the worker when done to prevent memory leaks:
210
+
211
+ ```typescript
212
+ const encoder = createAvifEncoder('worker');
213
+
214
+ try {
215
+ const avifData = await encoder(imageData, { quality: 60 });
216
+ } finally {
217
+ await encoder.terminate();
218
+ }
219
+ ```
220
+
221
+ **Note**: In client mode, `terminate()` is a no-op. It's always safe to call for consistency.
222
+
223
+ ### `AvifEncodeOptions`
224
+
225
+ ```typescript
226
+ type AvifEncodeOptions = {
227
+ quality?: number; // 0–100, visual quality (default: 60)
228
+ qualityAlpha?: number; // 0–100, alpha channel quality (default: 60)
229
+ denoiseLevel?: number; // 0–50, pre-encode denoising (default: 0)
230
+ tileRowsLog2?: number; // 0–6, tile rows as power of 2 (default: 0)
231
+ tileColsLog2?: number; // 0–6, tile columns as power of 2 (default: 0)
232
+ speed?: number; // 0–10, encoding speed (default: 6, lower = better compression)
233
+ subsample?: number; // Chroma subsampling (default: 1)
234
+ chromaDeltaQ?: boolean; // Use chroma delta quantization (default: false)
235
+ sharpness?: number; // 0–7, sharpness filter (default: 0)
236
+ enableSharpYUV?: boolean; // Use sharp YUV conversion (default: false)
237
+ tune?: AVIFTune; // Tuning mode: auto, psnr, or ssim (default: auto)
238
+ };
239
+ ```
240
+
241
+ **Key options:**
242
+
243
+ - `quality` — Primary quality control. `60` is a good starting point for photos. Lower values produce smaller, lower-quality files.
244
+ - `speed` — Encoding effort. `0` = maximum compression (very slow); `10` = fastest (larger files). `6` is a practical default.
245
+ - `tune` — Metric to optimize for: `AVIFTune.auto` (default), `AVIFTune.psnr` (signal fidelity), or `AVIFTune.ssim` (structural similarity).
246
+
247
+ ## Performance Tips
248
+
249
+ - **AVIF is slow to encode** — Use workers or client mode with server-side encoding; expect several seconds for large images at low speed settings
250
+ - **Speed 6–8 for real-time** — Speeds below 4 are typically too slow for interactive use
251
+ - **AVIF produces excellent quality** — At equivalent visual quality, AVIF files are typically 30-50% smaller than WebP
252
+ - **Batch with persistent encoders** — Amortizes WASM initialization cost across multiple encodes
253
+
254
+ ## Encoding Quality & File Size
255
+
256
+ AVIF uses AV1 video compression applied to still images:
257
+
258
+ - **Quality 80–100** — Near-lossless, very large files
259
+ - **Quality 60–80** — High quality, significantly smaller than PNG/JPEG
260
+ - **Quality 40–60** — Good quality for photos, very compact
261
+ - **Quality 0–40** — Visible artifacts; useful only for very small thumbnails
262
+
263
+ At quality 60 with default settings, AVIF files are typically **50–70% smaller** than equivalent-quality JPEG.
264
+
265
+ ## Works With
266
+
267
+ - **Bun** - First-class support, fastest performance
268
+ - **Node.js** - Works great in server environments
269
+ - **Browsers** - Full Web Worker support for responsive UIs
270
+ - **TypeScript** - Complete type definitions included
271
+
272
+ ## License
273
+
274
+ MIT - use it freely in your projects
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@squoosh-kit/avif",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "type": "module",
5
5
  "description": "AVIF codec for squoosh-kit.",
6
6
  "author": "Bartosz Nowak <bnowak008@gmail.com>",
@@ -10,6 +10,7 @@
10
10
  "url": "https://github.com/bnowak008/squoosh-kit.git",
11
11
  "directory": "packages/avif"
12
12
  },
13
+ "homepage": "http://squoosh-kit.dev",
13
14
  "publishConfig": {
14
15
  "access": "public",
15
16
  "registry": "https://registry.npmjs.org/"