@squoosh-kit/resize 0.0.3 → 0.0.5
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 +338 -45
- package/dist/bridge.browser.mjs +4 -0
- package/dist/bridge.browser.mjs.map +13 -0
- package/dist/bridge.bun.js +5 -0
- package/dist/bridge.bun.js.map +13 -0
- package/dist/bridge.d.ts +3 -1
- package/dist/bridge.d.ts.map +1 -0
- package/dist/bridge.node.cjs +3 -0
- package/dist/bridge.node.cjs.map +13 -0
- package/dist/bridge.node.mjs +4 -0
- package/dist/bridge.node.mjs.map +13 -0
- package/dist/chunk-djaabg7r.js +3 -0
- package/dist/chunk-djaabg7r.js.map +9 -0
- package/dist/index.browser.mjs +3 -0
- package/dist/index.browser.mjs.map +10 -0
- package/dist/index.bun.js +4 -0
- package/dist/index.bun.js.map +10 -0
- package/dist/index.d.ts +39 -7
- package/dist/index.d.ts.map +1 -0
- package/dist/index.node.cjs +3 -0
- package/dist/index.node.cjs.map +10 -0
- package/dist/index.node.mjs +3 -0
- package/dist/index.node.mjs.map +10 -0
- package/dist/resize.worker.browser.mjs +4 -0
- package/dist/resize.worker.browser.mjs.map +13 -0
- package/dist/resize.worker.bun.js +5 -0
- package/dist/resize.worker.bun.js.map +13 -0
- package/dist/resize.worker.d.ts +3 -2
- package/dist/resize.worker.d.ts.map +1 -0
- package/dist/resize.worker.node.cjs +3 -0
- package/dist/resize.worker.node.cjs.map +13 -0
- package/dist/resize.worker.node.mjs +4 -0
- package/dist/resize.worker.node.mjs.map +13 -0
- package/dist/types.browser.mjs +2 -0
- package/dist/types.browser.mjs.map +9 -0
- package/dist/types.bun.js +3 -0
- package/dist/types.bun.js.map +9 -0
- package/dist/types.d.ts +28 -4
- package/dist/types.d.ts.map +1 -0
- package/dist/types.node.cjs +3 -0
- package/dist/types.node.cjs.map +9 -0
- package/dist/types.node.mjs +2 -0
- package/dist/types.node.mjs.map +9 -0
- package/package.json +13 -5
- package/dist/index.js +0 -5
- package/dist/index.js.map +0 -12
- package/dist/resize.worker.js +0 -6
- package/dist/resize.worker.js.map +0 -10
- package/dist/wasm/squoosh_resize.d.ts +0 -34
- package/dist/wasm/squoosh_resize.js +0 -120
- package/dist/wasm/squoosh_resize_bg.wasm +0 -0
- package/dist/wasm/squoosh_resize_bg.wasm.d.ts +0 -7
package/README.md
CHANGED
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
**Professional image resizing with uncompromising quality**
|
|
6
6
|
|
|
7
|
-
Transform your images with
|
|
7
|
+
Transform your images with flexible resizing algorithms that balance quality and performance. Using the proven Squoosh WASM codecs with support for Triangular, Catrom, Mitchell, and Lanczos3 methods, this package delivers crisp results at any size.
|
|
8
8
|
|
|
9
|
-
Whether you need thumbnails for a gallery, responsive images for the web, or
|
|
9
|
+
Whether you need fast thumbnails for a gallery, responsive images for the web, or high-quality output for production, this package handles resizing with the algorithm your users deserve, all while keeping your application smooth and responsive.
|
|
10
10
|
|
|
11
11
|
## Installation
|
|
12
12
|
|
|
@@ -28,96 +28,161 @@ import type { ImageInput } from '@squoosh-kit/resize';
|
|
|
28
28
|
const imageData: ImageInput = {
|
|
29
29
|
data: imageBuffer,
|
|
30
30
|
width: 2048,
|
|
31
|
-
height: 1536
|
|
31
|
+
height: 1536,
|
|
32
32
|
};
|
|
33
33
|
|
|
34
|
-
//
|
|
34
|
+
// With cancellation support
|
|
35
|
+
const controller = new AbortController();
|
|
35
36
|
const thumbnail = await resize(
|
|
36
|
-
new AbortController().signal,
|
|
37
37
|
imageData,
|
|
38
|
-
{ width: 400 } // height calculated automatically
|
|
38
|
+
{ width: 400 }, // height calculated automatically
|
|
39
|
+
controller.signal
|
|
39
40
|
);
|
|
40
41
|
|
|
41
|
-
//
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
);
|
|
42
|
+
// Cancel after 5 seconds if still running
|
|
43
|
+
setTimeout(() => controller.abort(), 5000);
|
|
44
|
+
|
|
45
|
+
// Without cancellation (operation cannot be stopped once started)
|
|
46
|
+
const resizedImage = await resize(imageData, { width: 1200, height: 800 });
|
|
47
47
|
|
|
48
48
|
// Create a resizer for batch operations
|
|
49
49
|
const resizer = createResizer('worker');
|
|
50
50
|
const results = await Promise.all([
|
|
51
|
-
resizer(
|
|
52
|
-
resizer(
|
|
53
|
-
resizer(
|
|
51
|
+
resizer(imageData, { width: 800 }, new AbortController().signal),
|
|
52
|
+
resizer(imageData, { width: 1200 }, new AbortController().signal),
|
|
53
|
+
resizer(imageData, { width: 1600 }, new AbortController().signal),
|
|
54
54
|
]);
|
|
55
55
|
```
|
|
56
56
|
|
|
57
|
-
##
|
|
57
|
+
## Public API
|
|
58
|
+
|
|
59
|
+
Only the following exports are part of the public API and guaranteed to be stable across versions:
|
|
60
|
+
|
|
61
|
+
- `resize(imageData, options, signal?)` - Resize an image
|
|
62
|
+
- `createResizer(mode?)` - Create a reusable resizer function
|
|
63
|
+
- `ImageInput` type - Input image data structure
|
|
64
|
+
- `ResizeOptions` type - Resize configuration options
|
|
65
|
+
- `ResizerFactory` type - Type for reusable resizer functions
|
|
66
|
+
|
|
67
|
+
Internal implementation details (such as `resizeClient`) are not part of the public API and may change without notice.
|
|
68
|
+
|
|
69
|
+
## Resize Methods
|
|
70
|
+
|
|
71
|
+
Control the quality/speed trade-off with the `method` option:
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
// Balanced quality and speed (default)
|
|
75
|
+
const balanced = await resize(imageData, { width: 800, method: 'mitchell' });
|
|
76
|
+
|
|
77
|
+
// Fast for real-time preview
|
|
78
|
+
const fast = await resize(imageData, { width: 800, method: 'triangular' });
|
|
79
|
+
|
|
80
|
+
// Highest quality for production
|
|
81
|
+
const highQuality = await resize(imageData, { width: 800, method: 'lanczos3' });
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Available Methods
|
|
85
|
+
|
|
86
|
+
All methods are provided by the Squoosh WASM codec:
|
|
58
87
|
|
|
59
|
-
|
|
88
|
+
- **triangular** (typ_idx=0): Fastest, lowest quality. Good for real-time previews and large-scale batch processing.
|
|
89
|
+
- **catrom** (typ_idx=1): Medium quality and speed. Good general-purpose option.
|
|
90
|
+
- **mitchell** (typ_idx=2, default): Balanced quality and performance. Recommended for most use cases.
|
|
91
|
+
- **lanczos3** (typ_idx=3): Highest quality, slowest. Use for production output where quality is paramount.
|
|
60
92
|
|
|
61
|
-
|
|
93
|
+
### Advanced Options
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
// Color space control - use linear RGB for more accurate math
|
|
97
|
+
const linearResize = await resize(imageData, {
|
|
98
|
+
width: 800,
|
|
99
|
+
method: 'lanczos3',
|
|
100
|
+
linearRGB: true, // Proper color space conversion
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
// Alpha channel handling - premultiply for better transparency
|
|
104
|
+
const transparencyResize = await resize(imageData, {
|
|
105
|
+
width: 800,
|
|
106
|
+
premultiply: true, // Improves quality with transparent images
|
|
107
|
+
});
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## The Quality Difference
|
|
111
|
+
|
|
112
|
+
This isn't your average image resizer. Choose your trade-off between speed and quality with four proven algorithms from Google Squoosh. All processing happens in WebAssembly for incredible speed, with Web Workers ensuring your main thread stays free for user interactions.
|
|
62
113
|
|
|
63
114
|
## Real-World Examples
|
|
64
115
|
|
|
65
116
|
**Responsive Image Generation**
|
|
117
|
+
|
|
66
118
|
```typescript
|
|
67
119
|
// Generate multiple sizes for responsive design
|
|
68
120
|
const sizes = [320, 640, 1024, 1600];
|
|
69
121
|
|
|
70
122
|
const responsiveImages = await Promise.all(
|
|
71
|
-
sizes.map(width =>
|
|
123
|
+
sizes.map((width) =>
|
|
72
124
|
resize(
|
|
73
|
-
new AbortController().signal,
|
|
74
125
|
originalImage,
|
|
75
|
-
{ width, height: Math.round(width * 0.75) }
|
|
126
|
+
{ width, height: Math.round(width * 0.75) },
|
|
127
|
+
new AbortController().signal
|
|
76
128
|
)
|
|
77
129
|
)
|
|
78
130
|
);
|
|
79
131
|
```
|
|
80
132
|
|
|
81
|
-
**Photo Gallery Thumbnails**
|
|
133
|
+
**Photo Gallery Thumbnails with Timeout**
|
|
134
|
+
|
|
82
135
|
```typescript
|
|
83
136
|
const resizer = createResizer('client'); // Direct for server use
|
|
84
137
|
|
|
85
138
|
for (const photo of photoFiles) {
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
139
|
+
const controller = new AbortController();
|
|
140
|
+
|
|
141
|
+
// Set a 30-second timeout
|
|
142
|
+
const timeout = setTimeout(() => controller.abort(), 30000);
|
|
143
|
+
|
|
144
|
+
try {
|
|
145
|
+
const fullImage = await loadImage(photo);
|
|
146
|
+
const thumbnail = await resizer(
|
|
147
|
+
fullImage,
|
|
148
|
+
{ width: 300, height: 200 },
|
|
149
|
+
controller.signal
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
await saveThumbnail(photo.name, thumbnail);
|
|
153
|
+
} catch (error) {
|
|
154
|
+
if (error.name === 'AbortError') {
|
|
155
|
+
console.log(`Resize timed out for ${photo.name}`);
|
|
156
|
+
} else {
|
|
157
|
+
throw error;
|
|
158
|
+
}
|
|
159
|
+
} finally {
|
|
160
|
+
clearTimeout(timeout);
|
|
161
|
+
}
|
|
94
162
|
}
|
|
95
163
|
```
|
|
96
164
|
|
|
97
165
|
**Dynamic Image Processing**
|
|
166
|
+
|
|
98
167
|
```typescript
|
|
99
168
|
// Resize based on user preferences
|
|
100
169
|
const userWidth = getUserPreferredWidth();
|
|
101
|
-
const processedImage = await resize(
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
linearRGB: true, // Better color accuracy
|
|
107
|
-
premultiply: false // Maintain transparency
|
|
108
|
-
}
|
|
109
|
-
);
|
|
170
|
+
const processedImage = await resize(imageData, {
|
|
171
|
+
width: userWidth,
|
|
172
|
+
linearRGB: true, // Better color accuracy
|
|
173
|
+
premultiply: false, // Maintain transparency
|
|
174
|
+
});
|
|
110
175
|
```
|
|
111
176
|
|
|
112
177
|
## API Reference
|
|
113
178
|
|
|
114
|
-
### `resize(
|
|
179
|
+
### `resize(imageData, options, signal?)`
|
|
115
180
|
|
|
116
181
|
The main resizing function. Smart defaults make it easy to use.
|
|
117
182
|
|
|
118
|
-
- `signal` - `AbortSignal` to cancel long operations
|
|
119
183
|
- `imageData` - `ImageInput` object with your pixel data
|
|
120
|
-
- `options` -
|
|
184
|
+
- `options` - `ResizeOptions` for dimensions and quality
|
|
185
|
+
- `signal` - (optional) `AbortSignal` to cancel long operations. If provided, you can cancel by calling `controller.abort()` on the associated `AbortController`. If not provided, the operation cannot be cancelled.
|
|
121
186
|
- **Returns** - `Promise<ImageInput>` with resized image data
|
|
122
187
|
|
|
123
188
|
### `createResizer(mode?)`
|
|
@@ -127,19 +192,247 @@ Creates a reusable resizing function for efficient batch processing.
|
|
|
127
192
|
- `mode` - (optional) `'worker'` or `'client'`, defaults to `'worker'`
|
|
128
193
|
- **Returns** - A function with the same signature as `resize()`
|
|
129
194
|
|
|
195
|
+
## Cancellation Support
|
|
196
|
+
|
|
197
|
+
To cancel a resize operation in progress, pass an `AbortSignal`:
|
|
198
|
+
|
|
199
|
+
```typescript
|
|
200
|
+
const controller = new AbortController();
|
|
201
|
+
|
|
202
|
+
// Start resize
|
|
203
|
+
const resizePromise = resize(imageData, { width: 800 }, controller.signal);
|
|
204
|
+
|
|
205
|
+
// Cancel after 5 seconds if still running
|
|
206
|
+
setTimeout(() => controller.abort(), 5000);
|
|
207
|
+
|
|
208
|
+
try {
|
|
209
|
+
const result = await resizePromise;
|
|
210
|
+
} catch (error) {
|
|
211
|
+
if (error.name === 'AbortError') {
|
|
212
|
+
console.log('Resize was cancelled');
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
**Important**: If no signal is provided, the resize operation cannot be cancelled. It will run to completion.
|
|
218
|
+
|
|
219
|
+
## Input Validation
|
|
220
|
+
|
|
221
|
+
All inputs are automatically validated before processing to provide clear error messages:
|
|
222
|
+
|
|
223
|
+
### Image Validation
|
|
224
|
+
|
|
225
|
+
The `ImageInput` must contain valid image data:
|
|
226
|
+
|
|
227
|
+
```typescript
|
|
228
|
+
// Valid image data
|
|
229
|
+
const validImage: ImageInput = {
|
|
230
|
+
data: new Uint8Array(4096), // or Uint8ClampedArray
|
|
231
|
+
width: 32,
|
|
232
|
+
height: 32,
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
// Will throw TypeError: image must be an object
|
|
236
|
+
await resize(null, { width: 800 });
|
|
237
|
+
|
|
238
|
+
// Will throw TypeError: image.data is required
|
|
239
|
+
await resize({ width: 32, height: 32 }, { width: 800 });
|
|
240
|
+
|
|
241
|
+
// Will throw TypeError: image.data must be Uint8Array or Uint8ClampedArray
|
|
242
|
+
await resize({ data: [0, 0, 0, 255], width: 32, height: 32 }, { width: 800 });
|
|
243
|
+
|
|
244
|
+
// Will throw RangeError: image.width must be a positive integer
|
|
245
|
+
await resize(
|
|
246
|
+
{ data: new Uint8Array(100), width: 0, height: 32 },
|
|
247
|
+
{ width: 800 }
|
|
248
|
+
);
|
|
249
|
+
|
|
250
|
+
// Will throw RangeError: image.data too small
|
|
251
|
+
// (needs 32 * 32 * 4 = 4096 bytes, but only 100 provided)
|
|
252
|
+
await resize(
|
|
253
|
+
{ data: new Uint8Array(100), width: 32, height: 32 },
|
|
254
|
+
{ width: 800 }
|
|
255
|
+
);
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
### Options Validation
|
|
259
|
+
|
|
260
|
+
All resize options are validated for correctness:
|
|
261
|
+
|
|
262
|
+
```typescript
|
|
263
|
+
// Will throw RangeError: options.width must be a positive integer
|
|
264
|
+
await resize(validImage, { width: -800 });
|
|
265
|
+
|
|
266
|
+
// Will throw RangeError: options.height must be a positive integer
|
|
267
|
+
await resize(validImage, { height: 0 });
|
|
268
|
+
|
|
269
|
+
// Will throw TypeError: options.method must be one of: triangular, catrom, mitchell, lanczos3
|
|
270
|
+
await resize(validImage, { width: 800, method: 'invalid' });
|
|
271
|
+
|
|
272
|
+
// Will throw TypeError: options.premultiply must be boolean
|
|
273
|
+
await resize(validImage, { width: 800, premultiply: 1 });
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
### Why Validation Matters
|
|
277
|
+
|
|
278
|
+
Input validation prevents:
|
|
279
|
+
|
|
280
|
+
- **Cryptic WASM errors** - Clear messages instead of "undefined behavior"
|
|
281
|
+
- **Out-of-bounds buffer access** - Catches undersized buffers early
|
|
282
|
+
- **NaN propagation** - Rejects invalid numeric dimensions
|
|
283
|
+
- **Type confusion** - Ensures data is in the correct format
|
|
284
|
+
|
|
285
|
+
All validation happens synchronously before WASM processing, so you get errors immediately without starting an async operation.
|
|
286
|
+
|
|
287
|
+
### Edge Case Handling
|
|
288
|
+
|
|
289
|
+
The library safely handles edge cases that could cause errors or unexpected behavior:
|
|
290
|
+
|
|
291
|
+
#### Aspect Ratio Preservation with Small Dimensions
|
|
292
|
+
|
|
293
|
+
When resizing with only width or height specified, the other dimension is calculated while maintaining aspect ratio. Extreme aspect ratios are handled safely:
|
|
294
|
+
|
|
295
|
+
```typescript
|
|
296
|
+
// Width 1, height calculates automatically - minimum 1 pixel enforced
|
|
297
|
+
const tinyWidth = await resize(
|
|
298
|
+
{ data, width: 1921, height: 1080 },
|
|
299
|
+
{ width: 1 }
|
|
300
|
+
);
|
|
301
|
+
// Result: width=1, height≥1 (never 0)
|
|
302
|
+
|
|
303
|
+
// Very wide image, height to 1
|
|
304
|
+
const tinyHeight = await resize(
|
|
305
|
+
{ data, width: 1920, height: 1 },
|
|
306
|
+
{ height: 1 }
|
|
307
|
+
);
|
|
308
|
+
// Result: width≥1 (never 0), height=1
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
#### Rounding Precision
|
|
312
|
+
|
|
313
|
+
Decimal aspect ratios are rounded carefully to avoid precision loss:
|
|
314
|
+
|
|
315
|
+
```typescript
|
|
316
|
+
// Calculation: (1080 * 960) / 1920 = 540 (exact)
|
|
317
|
+
const result1 = await resize(
|
|
318
|
+
{ data, width: 1920, height: 1080 },
|
|
319
|
+
{ width: 960 }
|
|
320
|
+
);
|
|
321
|
+
// Result: width=960, height=540
|
|
322
|
+
|
|
323
|
+
// Calculation: (1081 * 960) / 1920 = 540.5 → rounds to 541
|
|
324
|
+
const result2 = await resize(
|
|
325
|
+
{ data, width: 1920, height: 1081 },
|
|
326
|
+
{ width: 960 }
|
|
327
|
+
);
|
|
328
|
+
// Result: width=960, height=541 (properly rounded)
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
#### Minimum Dimension Enforcement
|
|
332
|
+
|
|
333
|
+
Output dimensions must be at least 1x1 pixel (WASM requirement):
|
|
334
|
+
|
|
335
|
+
```typescript
|
|
336
|
+
// Both dimensions will be at least 1
|
|
337
|
+
const minimal = await resize(
|
|
338
|
+
{ data, width: 100, height: 100 },
|
|
339
|
+
{ width: 0.1 } // Would round to 0, enforced to 1
|
|
340
|
+
);
|
|
341
|
+
// This throws validation error (width must be ≥1)
|
|
342
|
+
|
|
343
|
+
// But if validation passes, minimum 1x1 is guaranteed
|
|
344
|
+
const valid = await resize({ data, width: 1000, height: 1000 }, { width: 1 });
|
|
345
|
+
// Result: width=1, height≥1
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
#### Why This Matters
|
|
349
|
+
|
|
350
|
+
- **No NaN values** - Rounding prevents `Infinity` from division by zero
|
|
351
|
+
- **No 0-pixel images** - Minimum 1x1 ensures valid output
|
|
352
|
+
- **Consistent behavior** - Aspect ratios always preserve proportion
|
|
353
|
+
- **Safe calculations** - `Math.max(1, ...)` protects against negative results
|
|
354
|
+
|
|
355
|
+
### Package Size
|
|
356
|
+
|
|
357
|
+
This package includes WebAssembly binaries (~30-50KB gzipped) for the resize codec. These enable fast processing through Web Workers and are essential for optimal performance.
|
|
358
|
+
|
|
359
|
+
**Size breakdown:**
|
|
360
|
+
|
|
361
|
+
- JavaScript code: ~5-10KB gzipped
|
|
362
|
+
- TypeScript definitions: ~3KB
|
|
363
|
+
- WASM binaries: ~30-50KB gzipped (required for resizing)
|
|
364
|
+
|
|
365
|
+
If you're using client mode only and want to reduce package size, you can safely remove the WASM files:
|
|
366
|
+
|
|
367
|
+
```bash
|
|
368
|
+
rm -rf node_modules/@squoosh-kit/resize/dist/wasm/
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
**Note**: This will cause worker mode to fail. Only remove if using client mode exclusively.
|
|
372
|
+
|
|
373
|
+
### Worker Cleanup
|
|
374
|
+
|
|
375
|
+
When using worker mode (`createResizer('worker')`), always clean up the worker when you're done to prevent memory leaks:
|
|
376
|
+
|
|
377
|
+
```typescript
|
|
378
|
+
const resizer = createResizer('worker');
|
|
379
|
+
|
|
380
|
+
try {
|
|
381
|
+
const result = await resizer(imageData, { width: 800 });
|
|
382
|
+
// Use the result...
|
|
383
|
+
} finally {
|
|
384
|
+
// Clean up the worker to free resources
|
|
385
|
+
await resizer.terminate();
|
|
386
|
+
}
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
For batch operations, keep the resizer alive throughout processing:
|
|
390
|
+
|
|
391
|
+
```typescript
|
|
392
|
+
const resizer = createResizer('worker');
|
|
393
|
+
|
|
394
|
+
try {
|
|
395
|
+
const results = await Promise.all([
|
|
396
|
+
resizer(image1, { width: 800 }),
|
|
397
|
+
resizer(image2, { width: 800 }),
|
|
398
|
+
resizer(image3, { width: 800 }),
|
|
399
|
+
]);
|
|
400
|
+
|
|
401
|
+
// Process results...
|
|
402
|
+
} finally {
|
|
403
|
+
// Clean up when all operations are complete
|
|
404
|
+
await resizer.terminate();
|
|
405
|
+
}
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
**Note**: In client mode (`createResizer('client')`), calling `terminate()` is a no-op since there are no worker resources to clean up. It's always safe to call for consistency.
|
|
409
|
+
|
|
130
410
|
### `ResizeOptions`
|
|
131
411
|
|
|
132
412
|
Control the quality and behavior of resizing:
|
|
133
413
|
|
|
134
414
|
```typescript
|
|
135
415
|
type ResizeOptions = {
|
|
136
|
-
width?: number;
|
|
137
|
-
height?: number;
|
|
416
|
+
width?: number; // Target width (aspect ratio maintained if only width/height set)
|
|
417
|
+
height?: number; // Target height (aspect ratio maintained if only width/height set)
|
|
418
|
+
method?: 'triangular' | 'catrom' | 'mitchell' | 'lanczos3'; // Resize algorithm (default: 'mitchell')
|
|
138
419
|
premultiply?: boolean; // Premultiply alpha channel (default: false)
|
|
139
|
-
linearRGB?: boolean;
|
|
420
|
+
linearRGB?: boolean; // Use linear RGB color space (default: false)
|
|
140
421
|
};
|
|
141
422
|
```
|
|
142
423
|
|
|
424
|
+
### Parameter Reference
|
|
425
|
+
|
|
426
|
+
All options map directly to the Squoosh WASM resize function:
|
|
427
|
+
|
|
428
|
+
| Option | WASM Parameter | Type | Default | Description |
|
|
429
|
+
| ------------- | ---------------------- | ---------------------------------------------------- | --------------- | -------------------------------------------------------- |
|
|
430
|
+
| `width` | output_width | number? | original width | Target width (aspect ratio maintained if height omitted) |
|
|
431
|
+
| `height` | output_height | number? | original height | Target height (aspect ratio maintained if width omitted) |
|
|
432
|
+
| `method` | typ_idx | 'triangular' \| 'catrom' \| 'mitchell' \| 'lanczos3' | 'mitchell' | Resize algorithm selection |
|
|
433
|
+
| `premultiply` | premultiply | boolean? | false | Pre-multiply alpha channel before resizing |
|
|
434
|
+
| `linearRGB` | color_space_conversion | boolean? | false | Use linear RGB color space instead of sRGB |
|
|
435
|
+
|
|
143
436
|
## Pro Tips
|
|
144
437
|
|
|
145
438
|
- **Maintain aspect ratio** - Set only width or height, and the other dimension calculates automatically
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import{b as A,c as E,d as B}from"./resize.worker.browser.mjs";function N(){return typeof Bun<"u"}var T=0;async function S(G,J,K,Y,H){return new Promise((X,Q)=>{let Z=++T;if(Y?.aborted){Q(new DOMException("Aborted","AbortError"));return}let V=(D)=>{let _=D.data;if(_.id!==Z)return;if($(),_.ok&&_.data!==void 0)X(_.data);else Q(Error(_.error||"Unknown worker error"))},O=(D)=>{$(),Q(Error(`Worker error: ${D.message}`))},x=()=>{$(),Q(new DOMException("Aborted","AbortError"))},$=()=>{G.removeEventListener("message",V),G.removeEventListener("error",O),Y?.removeEventListener("abort",x)};G.addEventListener("message",V),G.addEventListener("error",O),Y?.addEventListener("abort",x);let L={type:J,id:Z,payload:K};if(H&&H.length>0)G.postMessage(L,H);else G.postMessage(L)})}function W(G){let J=G.endsWith(".js")?G:`${G}.js`;if(typeof window<"u"){let Q={"webp.worker.js":"/dist/features/webp/webp.worker.browser.mjs","resize.worker.js":"/dist/features/resize/resize.worker.browser.mjs"}[J];if(Q)return new URL(Q,window.location.href)}let K=N()?".bun.js":".node.mjs",H={"webp.worker.js":`../../webp/dist/webp.worker${K}`,"resize.worker.js":`../../resize/dist/resize.worker${K}`}[J];if(H)return new URL(H,import.meta.url);return new URL(J,import.meta.url)}function q(G){let J=W(G);try{return new Worker(J.href,{type:"module"})}catch(K){let Y=K instanceof Error?K.message:String(K);throw Error(`Failed to create worker from ${J}: ${Y}. Ensure the worker file exists at the expected location. Expected worker file: ${G}${G.endsWith(".js")?"":".js"}`)}}function U(G,J=1e4){return new Promise((K,Y)=>{let H=setTimeout(()=>{Y(Error(`Worker initialization timeout after ${J}ms. Worker file: ${G}`))},J),X;try{X=q(G)}catch(Z){clearTimeout(H),Y(Z);return}let Q=(Z)=>{if(Z.data?.type==="worker:ready")clearTimeout(H),X.removeEventListener("message",Q),K(X)};X.addEventListener("message",Q),X.postMessage({type:"worker:ping"})})}class P{async resize(G,J,K){return B(G,J,K)}async terminate(){}}class I{worker=null;workerReady=null;async getWorker(){if(!this.worker){if(!this.workerReady)this.workerReady=this.createWorker();this.worker=await this.workerReady}return this.worker}async createWorker(){return U("resize.worker")}async resize(G,J,K){let Y=await this.getWorker();if(!G||typeof G!=="object")throw TypeError("image must be an object");let H=G;if(!H.data)throw TypeError("image.data is required");if(H.width===void 0||H.height===void 0)throw TypeError("image.width and image.height are required");let X={data:H.data,width:H.width,height:H.height};E(X);let Q=X.data.buffer;A(Q);try{return await S(Y,"resize:run",{image:X,options:J},K,[Q])}catch(Z){throw console.error("Resize error:",Z),Z}}async terminate(){if(this.worker)this.worker.terminate(),this.worker=null,this.workerReady=null}}function v(G){return G==="client"?new P:new I}export{v as createBridge};
|
|
2
|
+
export{v as a};
|
|
3
|
+
|
|
4
|
+
//# debugId=1358BB738EBDD58364756E2164756E21
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../runtime/src/env.ts", "../../runtime/src/worker-call.ts", "../../runtime/src/worker-helper.ts", "../src/bridge.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"/**\n * Runtime environment detection utilities\n */\n\n/**\n * Detect if running in a Web Worker context\n */\nexport function isWorker(): boolean {\n return (\n typeof self !== 'undefined' &&\n typeof (globalThis as unknown as { DedicatedWorkerGlobalScope?: unknown })\n .DedicatedWorkerGlobalScope !== 'undefined'\n );\n}\n\n/**\n * Detect if running in a browser context\n */\nexport function isBrowser(): boolean {\n return typeof window !== 'undefined' && typeof document !== 'undefined';\n}\n\n/**\n * Detect if running in Bun\n */\nexport function isBun(): boolean {\n return typeof Bun !== 'undefined';\n}\n\n/**\n * Detect if running in Node.js\n */\nexport function isNode(): boolean {\n return (\n typeof process !== 'undefined' &&\n process.versions != null &&\n process.versions.node != null\n );\n}\n\n/**\n * Check if ImageData is available in the current environment\n */\nexport function hasImageData(): boolean {\n return typeof ImageData !== 'undefined';\n}\n",
|
|
6
|
+
"/**\n * Generic worker communication helper with support for transferables and AbortSignal\n */\n\nexport interface WorkerRequest<T = unknown> {\n type: string;\n id: number;\n payload: T;\n}\n\nexport interface WorkerResponse<T = unknown> {\n id: number;\n ok: boolean;\n data?: T;\n error?: string;\n}\n\nlet requestId = 0;\n\n/**\n * Call a worker with a typed request and wait for response\n *\n * @param worker - The worker instance to call\n * @param type - The message type\n * @param payload - The payload to send\n * @param signal - Optional AbortSignal to cancel the operation\n * @param transfer - Optional list of Transferable objects to transfer\n * @returns Promise that resolves with the worker's response data\n */\nexport async function callWorker<TPayload, TResponse>(\n worker: Worker,\n type: string,\n payload: TPayload,\n signal?: AbortSignal,\n transfer?: Transferable[]\n): Promise<TResponse> {\n return new Promise<TResponse>((resolve, reject) => {\n const id = ++requestId;\n\n // Check if already aborted\n if (signal?.aborted) {\n reject(new DOMException('Aborted', 'AbortError'));\n return;\n }\n\n const handleMessage = (event: MessageEvent) => {\n const response = event.data as WorkerResponse<TResponse>;\n if (response.id !== id) return;\n\n cleanup();\n\n if (response.ok && response.data !== undefined) {\n resolve(response.data);\n } else {\n reject(new Error(response.error || 'Unknown worker error'));\n }\n };\n\n const handleError = (error: ErrorEvent) => {\n cleanup();\n reject(new Error(`Worker error: ${error.message}`));\n };\n\n const handleAbort = () => {\n cleanup();\n reject(new DOMException('Aborted', 'AbortError'));\n };\n\n const cleanup = () => {\n worker.removeEventListener('message', handleMessage);\n worker.removeEventListener('error', handleError);\n signal?.removeEventListener('abort', handleAbort);\n };\n\n // Set up listeners\n worker.addEventListener('message', handleMessage);\n worker.addEventListener('error', handleError);\n signal?.addEventListener('abort', handleAbort);\n\n // Send the request\n const request: WorkerRequest<TPayload> = { type, id, payload };\n\n if (transfer && transfer.length > 0) {\n worker.postMessage(request, transfer);\n } else {\n worker.postMessage(request);\n }\n });\n}\n",
|
|
7
|
+
"/**\n * Worker helper utilities for creating and managing Web Workers\n *\n * This module provides centralized logic for locating and creating worker files\n * in different environments (development, npm package, bundled, etc.)\n */\n\nimport { isBun } from './env';\n\n/**\n * Get the URL for a worker file\n *\n * This helper abstracts away the complexity of locating worker files\n * in different environments (development, npm package, bundled, etc.)\n *\n * @param workerFilename - The name of the worker file (with or without .js extension)\n * @returns URL object pointing to the worker file\n */\nexport function getWorkerURL(workerFilename: string): URL {\n // Ensure filename has correct format\n const normalizedName = workerFilename.endsWith('.js')\n ? workerFilename\n : `${workerFilename}.js`;\n\n // In browser contexts, use absolute paths from the server root\n // The server will route these to the correct locations\n if (typeof window !== 'undefined') {\n // Browser environment - use absolute paths with platform-specific extension\n const workerPathMap: Record<string, string> = {\n 'webp.worker.js': '/dist/features/webp/webp.worker.browser.mjs',\n 'resize.worker.js': '/dist/features/resize/resize.worker.browser.mjs',\n };\n\n const browserPath = workerPathMap[normalizedName];\n if (browserPath) {\n return new URL(browserPath, window.location.href);\n }\n }\n\n // Node.js/Bun: use relative path from runtime package location\n // Determine which platform variant to use\n const platformExt = isBun() ? '.bun.js' : '.node.mjs';\n\n const nodePathMap: Record<string, string> = {\n 'webp.worker.js': `../../webp/dist/webp.worker${platformExt}`,\n 'resize.worker.js': `../../resize/dist/resize.worker${platformExt}`,\n };\n\n const nodePath = nodePathMap[normalizedName];\n if (nodePath) {\n return new URL(nodePath, import.meta.url);\n }\n\n // Fallback: assume worker is in same directory as this module\n return new URL(normalizedName, import.meta.url);\n}\n\n/**\n * Create a Web Worker for a specific codec\n *\n * Handles environment-specific worker creation logic and provides\n * clear error messages when worker creation fails.\n *\n * @param workerFilename - The name of the worker file (e.g., 'resize.worker' or 'webp.worker')\n * @returns Worker instance\n * @throws Error if worker creation fails with detailed error message\n */\nexport function createCodecWorker(workerFilename: string): Worker {\n const workerURL = getWorkerURL(workerFilename);\n\n try {\n return new Worker(workerURL.href, { type: 'module' });\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n throw new Error(\n `Failed to create worker from ${workerURL}: ${errorMessage}. ` +\n `Ensure the worker file exists at the expected location. ` +\n `Expected worker file: ${workerFilename}${workerFilename.endsWith('.js') ? '' : '.js'}`\n );\n }\n}\n\n/**\n * Create a worker with initialization timeout and ready signal handling\n *\n * This is a higher-level function that creates a worker and waits for it\n * to signal that it's ready to receive messages.\n *\n * @param workerFilename - The name of the worker file\n * @param timeoutMs - Timeout in milliseconds (default: 10000)\n * @returns Promise that resolves to a ready Worker instance\n * @throws Error if worker creation fails or times out\n */\nexport function createReadyWorker(\n workerFilename: string,\n timeoutMs: number = 10000\n): Promise<Worker> {\n return new Promise((resolve, reject) => {\n const timeout = setTimeout(() => {\n reject(\n new Error(\n `Worker initialization timeout after ${timeoutMs}ms. Worker file: ${workerFilename}`\n )\n );\n }, timeoutMs);\n\n let worker: Worker;\n try {\n worker = createCodecWorker(workerFilename);\n } catch (error) {\n clearTimeout(timeout);\n reject(error);\n return;\n }\n\n const handleMessage = (event: MessageEvent) => {\n if (event.data?.type === 'worker:ready') {\n clearTimeout(timeout);\n worker.removeEventListener('message', handleMessage);\n resolve(worker);\n }\n };\n\n worker.addEventListener('message', handleMessage);\n worker.postMessage({ type: 'worker:ping' });\n });\n}\n",
|
|
8
|
+
"/**\n * Bridge implementation for the Resize package, handling worker and client modes.\n */\n\nimport {\n callWorker,\n createReadyWorker,\n type ImageInput,\n} from '@squoosh-kit/runtime';\nimport { validateArrayBuffer, validateImageInput } from '@squoosh-kit/runtime';\nimport { resizeClient } from './resize.worker.ts';\nimport type { ResizeOptions } from './types.ts';\n\ninterface ResizeBridge {\n resize(\n image: ImageInput,\n options: ResizeOptions,\n signal?: AbortSignal\n ): Promise<ImageInput>;\n terminate(): Promise<void>;\n}\n\nclass ResizeClientBridge implements ResizeBridge {\n async resize(\n image: ImageInput,\n options: ResizeOptions,\n signal?: AbortSignal\n ): Promise<ImageInput> {\n return resizeClient(image, options, signal);\n }\n\n async terminate(): Promise<void> {\n // Client mode has nothing to terminate\n }\n}\n\nclass ResizeWorkerBridge implements ResizeBridge {\n private worker: Worker | null = null;\n private workerReady: Promise<Worker> | null = null;\n\n private async getWorker(): Promise<Worker> {\n if (!this.worker) {\n if (!this.workerReady) {\n this.workerReady = this.createWorker();\n }\n this.worker = await this.workerReady;\n }\n return this.worker;\n }\n\n private async createWorker(): Promise<Worker> {\n // Use the centralized worker helper for robust path resolution\n return createReadyWorker('resize.worker');\n }\n\n async resize(\n image: ImageInput,\n options: ResizeOptions,\n signal?: AbortSignal\n ): Promise<ImageInput> {\n const worker = await this.getWorker();\n\n // Validate and normalize image - ensure all required properties exist\n if (!image || typeof image !== 'object') {\n throw new TypeError('image must be an object');\n }\n\n const imageRecord = image as Record<string, unknown>;\n if (!imageRecord.data) {\n throw new TypeError('image.data is required');\n }\n if (imageRecord.width === undefined || imageRecord.height === undefined) {\n throw new TypeError('image.width and image.height are required');\n }\n\n const normalizedImage: ImageInput = {\n data: imageRecord.data as Uint8Array | Uint8ClampedArray,\n width: imageRecord.width as number,\n height: imageRecord.height as number,\n };\n\n validateImageInput(normalizedImage);\n const buffer = normalizedImage.data.buffer;\n validateArrayBuffer(buffer);\n\n try {\n const result = await callWorker<\n { image: ImageInput; options: ResizeOptions },\n ImageInput\n >(worker, 'resize:run', { image: normalizedImage, options }, signal, [\n buffer,\n ]);\n\n return result;\n } catch (error) {\n console.error('Resize error:', error);\n throw error;\n }\n }\n\n async terminate(): Promise<void> {\n if (this.worker) {\n this.worker.terminate();\n this.worker = null;\n this.workerReady = null;\n }\n }\n}\n\nexport function createBridge(mode: 'worker' | 'client'): ResizeBridge {\n return mode === 'client'\n ? new ResizeClientBridge()\n : new ResizeWorkerBridge();\n}\n"
|
|
9
|
+
],
|
|
10
|
+
"mappings": "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",
|
|
11
|
+
"debugId": "1358BB738EBDD58364756E2164756E21",
|
|
12
|
+
"names": []
|
|
13
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import{b as A,c as E,d as B}from"./resize.worker.bun.js";function N(){return typeof Bun<"u"}var T=0;async function S(G,J,K,Y,H){return new Promise((X,Q)=>{let Z=++T;if(Y?.aborted){Q(new DOMException("Aborted","AbortError"));return}let V=(D)=>{let _=D.data;if(_.id!==Z)return;if($(),_.ok&&_.data!==void 0)X(_.data);else Q(Error(_.error||"Unknown worker error"))},O=(D)=>{$(),Q(Error(`Worker error: ${D.message}`))},x=()=>{$(),Q(new DOMException("Aborted","AbortError"))},$=()=>{G.removeEventListener("message",V),G.removeEventListener("error",O),Y?.removeEventListener("abort",x)};G.addEventListener("message",V),G.addEventListener("error",O),Y?.addEventListener("abort",x);let L={type:J,id:Z,payload:K};if(H&&H.length>0)G.postMessage(L,H);else G.postMessage(L)})}function W(G){let J=G.endsWith(".js")?G:`${G}.js`;if(typeof window<"u"){let Q={"webp.worker.js":"/dist/features/webp/webp.worker.browser.mjs","resize.worker.js":"/dist/features/resize/resize.worker.browser.mjs"}[J];if(Q)return new URL(Q,window.location.href)}let K=N()?".bun.js":".node.mjs",H={"webp.worker.js":`../../webp/dist/webp.worker${K}`,"resize.worker.js":`../../resize/dist/resize.worker${K}`}[J];if(H)return new URL(H,import.meta.url);return new URL(J,import.meta.url)}function q(G){let J=W(G);try{return new Worker(J.href,{type:"module"})}catch(K){let Y=K instanceof Error?K.message:String(K);throw Error(`Failed to create worker from ${J}: ${Y}. Ensure the worker file exists at the expected location. Expected worker file: ${G}${G.endsWith(".js")?"":".js"}`)}}function U(G,J=1e4){return new Promise((K,Y)=>{let H=setTimeout(()=>{Y(Error(`Worker initialization timeout after ${J}ms. Worker file: ${G}`))},J),X;try{X=q(G)}catch(Z){clearTimeout(H),Y(Z);return}let Q=(Z)=>{if(Z.data?.type==="worker:ready")clearTimeout(H),X.removeEventListener("message",Q),K(X)};X.addEventListener("message",Q),X.postMessage({type:"worker:ping"})})}class P{async resize(G,J,K){return B(G,J,K)}async terminate(){}}class I{worker=null;workerReady=null;async getWorker(){if(!this.worker){if(!this.workerReady)this.workerReady=this.createWorker();this.worker=await this.workerReady}return this.worker}async createWorker(){return U("resize.worker")}async resize(G,J,K){let Y=await this.getWorker();if(!G||typeof G!=="object")throw TypeError("image must be an object");let H=G;if(!H.data)throw TypeError("image.data is required");if(H.width===void 0||H.height===void 0)throw TypeError("image.width and image.height are required");let X={data:H.data,width:H.width,height:H.height};E(X);let Q=X.data.buffer;A(Q);try{return await S(Y,"resize:run",{image:X,options:J},K,[Q])}catch(Z){throw console.error("Resize error:",Z),Z}}async terminate(){if(this.worker)this.worker.terminate(),this.worker=null,this.workerReady=null}}function v(G){return G==="client"?new P:new I}export{v as createBridge};
|
|
3
|
+
export{v as a};
|
|
4
|
+
|
|
5
|
+
//# debugId=26D9507FE5210F9564756E2164756E21
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../runtime/src/env.ts", "../../runtime/src/worker-call.ts", "../../runtime/src/worker-helper.ts", "../src/bridge.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"/**\n * Runtime environment detection utilities\n */\n\n/**\n * Detect if running in a Web Worker context\n */\nexport function isWorker(): boolean {\n return (\n typeof self !== 'undefined' &&\n typeof (globalThis as unknown as { DedicatedWorkerGlobalScope?: unknown })\n .DedicatedWorkerGlobalScope !== 'undefined'\n );\n}\n\n/**\n * Detect if running in a browser context\n */\nexport function isBrowser(): boolean {\n return typeof window !== 'undefined' && typeof document !== 'undefined';\n}\n\n/**\n * Detect if running in Bun\n */\nexport function isBun(): boolean {\n return typeof Bun !== 'undefined';\n}\n\n/**\n * Detect if running in Node.js\n */\nexport function isNode(): boolean {\n return (\n typeof process !== 'undefined' &&\n process.versions != null &&\n process.versions.node != null\n );\n}\n\n/**\n * Check if ImageData is available in the current environment\n */\nexport function hasImageData(): boolean {\n return typeof ImageData !== 'undefined';\n}\n",
|
|
6
|
+
"/**\n * Generic worker communication helper with support for transferables and AbortSignal\n */\n\nexport interface WorkerRequest<T = unknown> {\n type: string;\n id: number;\n payload: T;\n}\n\nexport interface WorkerResponse<T = unknown> {\n id: number;\n ok: boolean;\n data?: T;\n error?: string;\n}\n\nlet requestId = 0;\n\n/**\n * Call a worker with a typed request and wait for response\n *\n * @param worker - The worker instance to call\n * @param type - The message type\n * @param payload - The payload to send\n * @param signal - Optional AbortSignal to cancel the operation\n * @param transfer - Optional list of Transferable objects to transfer\n * @returns Promise that resolves with the worker's response data\n */\nexport async function callWorker<TPayload, TResponse>(\n worker: Worker,\n type: string,\n payload: TPayload,\n signal?: AbortSignal,\n transfer?: Transferable[]\n): Promise<TResponse> {\n return new Promise<TResponse>((resolve, reject) => {\n const id = ++requestId;\n\n // Check if already aborted\n if (signal?.aborted) {\n reject(new DOMException('Aborted', 'AbortError'));\n return;\n }\n\n const handleMessage = (event: MessageEvent) => {\n const response = event.data as WorkerResponse<TResponse>;\n if (response.id !== id) return;\n\n cleanup();\n\n if (response.ok && response.data !== undefined) {\n resolve(response.data);\n } else {\n reject(new Error(response.error || 'Unknown worker error'));\n }\n };\n\n const handleError = (error: ErrorEvent) => {\n cleanup();\n reject(new Error(`Worker error: ${error.message}`));\n };\n\n const handleAbort = () => {\n cleanup();\n reject(new DOMException('Aborted', 'AbortError'));\n };\n\n const cleanup = () => {\n worker.removeEventListener('message', handleMessage);\n worker.removeEventListener('error', handleError);\n signal?.removeEventListener('abort', handleAbort);\n };\n\n // Set up listeners\n worker.addEventListener('message', handleMessage);\n worker.addEventListener('error', handleError);\n signal?.addEventListener('abort', handleAbort);\n\n // Send the request\n const request: WorkerRequest<TPayload> = { type, id, payload };\n\n if (transfer && transfer.length > 0) {\n worker.postMessage(request, transfer);\n } else {\n worker.postMessage(request);\n }\n });\n}\n",
|
|
7
|
+
"/**\n * Worker helper utilities for creating and managing Web Workers\n *\n * This module provides centralized logic for locating and creating worker files\n * in different environments (development, npm package, bundled, etc.)\n */\n\nimport { isBun } from './env';\n\n/**\n * Get the URL for a worker file\n *\n * This helper abstracts away the complexity of locating worker files\n * in different environments (development, npm package, bundled, etc.)\n *\n * @param workerFilename - The name of the worker file (with or without .js extension)\n * @returns URL object pointing to the worker file\n */\nexport function getWorkerURL(workerFilename: string): URL {\n // Ensure filename has correct format\n const normalizedName = workerFilename.endsWith('.js')\n ? workerFilename\n : `${workerFilename}.js`;\n\n // In browser contexts, use absolute paths from the server root\n // The server will route these to the correct locations\n if (typeof window !== 'undefined') {\n // Browser environment - use absolute paths with platform-specific extension\n const workerPathMap: Record<string, string> = {\n 'webp.worker.js': '/dist/features/webp/webp.worker.browser.mjs',\n 'resize.worker.js': '/dist/features/resize/resize.worker.browser.mjs',\n };\n\n const browserPath = workerPathMap[normalizedName];\n if (browserPath) {\n return new URL(browserPath, window.location.href);\n }\n }\n\n // Node.js/Bun: use relative path from runtime package location\n // Determine which platform variant to use\n const platformExt = isBun() ? '.bun.js' : '.node.mjs';\n\n const nodePathMap: Record<string, string> = {\n 'webp.worker.js': `../../webp/dist/webp.worker${platformExt}`,\n 'resize.worker.js': `../../resize/dist/resize.worker${platformExt}`,\n };\n\n const nodePath = nodePathMap[normalizedName];\n if (nodePath) {\n return new URL(nodePath, import.meta.url);\n }\n\n // Fallback: assume worker is in same directory as this module\n return new URL(normalizedName, import.meta.url);\n}\n\n/**\n * Create a Web Worker for a specific codec\n *\n * Handles environment-specific worker creation logic and provides\n * clear error messages when worker creation fails.\n *\n * @param workerFilename - The name of the worker file (e.g., 'resize.worker' or 'webp.worker')\n * @returns Worker instance\n * @throws Error if worker creation fails with detailed error message\n */\nexport function createCodecWorker(workerFilename: string): Worker {\n const workerURL = getWorkerURL(workerFilename);\n\n try {\n return new Worker(workerURL.href, { type: 'module' });\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n throw new Error(\n `Failed to create worker from ${workerURL}: ${errorMessage}. ` +\n `Ensure the worker file exists at the expected location. ` +\n `Expected worker file: ${workerFilename}${workerFilename.endsWith('.js') ? '' : '.js'}`\n );\n }\n}\n\n/**\n * Create a worker with initialization timeout and ready signal handling\n *\n * This is a higher-level function that creates a worker and waits for it\n * to signal that it's ready to receive messages.\n *\n * @param workerFilename - The name of the worker file\n * @param timeoutMs - Timeout in milliseconds (default: 10000)\n * @returns Promise that resolves to a ready Worker instance\n * @throws Error if worker creation fails or times out\n */\nexport function createReadyWorker(\n workerFilename: string,\n timeoutMs: number = 10000\n): Promise<Worker> {\n return new Promise((resolve, reject) => {\n const timeout = setTimeout(() => {\n reject(\n new Error(\n `Worker initialization timeout after ${timeoutMs}ms. Worker file: ${workerFilename}`\n )\n );\n }, timeoutMs);\n\n let worker: Worker;\n try {\n worker = createCodecWorker(workerFilename);\n } catch (error) {\n clearTimeout(timeout);\n reject(error);\n return;\n }\n\n const handleMessage = (event: MessageEvent) => {\n if (event.data?.type === 'worker:ready') {\n clearTimeout(timeout);\n worker.removeEventListener('message', handleMessage);\n resolve(worker);\n }\n };\n\n worker.addEventListener('message', handleMessage);\n worker.postMessage({ type: 'worker:ping' });\n });\n}\n",
|
|
8
|
+
"/**\n * Bridge implementation for the Resize package, handling worker and client modes.\n */\n\nimport {\n callWorker,\n createReadyWorker,\n type ImageInput,\n} from '@squoosh-kit/runtime';\nimport { validateArrayBuffer, validateImageInput } from '@squoosh-kit/runtime';\nimport { resizeClient } from './resize.worker.ts';\nimport type { ResizeOptions } from './types.ts';\n\ninterface ResizeBridge {\n resize(\n image: ImageInput,\n options: ResizeOptions,\n signal?: AbortSignal\n ): Promise<ImageInput>;\n terminate(): Promise<void>;\n}\n\nclass ResizeClientBridge implements ResizeBridge {\n async resize(\n image: ImageInput,\n options: ResizeOptions,\n signal?: AbortSignal\n ): Promise<ImageInput> {\n return resizeClient(image, options, signal);\n }\n\n async terminate(): Promise<void> {\n // Client mode has nothing to terminate\n }\n}\n\nclass ResizeWorkerBridge implements ResizeBridge {\n private worker: Worker | null = null;\n private workerReady: Promise<Worker> | null = null;\n\n private async getWorker(): Promise<Worker> {\n if (!this.worker) {\n if (!this.workerReady) {\n this.workerReady = this.createWorker();\n }\n this.worker = await this.workerReady;\n }\n return this.worker;\n }\n\n private async createWorker(): Promise<Worker> {\n // Use the centralized worker helper for robust path resolution\n return createReadyWorker('resize.worker');\n }\n\n async resize(\n image: ImageInput,\n options: ResizeOptions,\n signal?: AbortSignal\n ): Promise<ImageInput> {\n const worker = await this.getWorker();\n\n // Validate and normalize image - ensure all required properties exist\n if (!image || typeof image !== 'object') {\n throw new TypeError('image must be an object');\n }\n\n const imageRecord = image as Record<string, unknown>;\n if (!imageRecord.data) {\n throw new TypeError('image.data is required');\n }\n if (imageRecord.width === undefined || imageRecord.height === undefined) {\n throw new TypeError('image.width and image.height are required');\n }\n\n const normalizedImage: ImageInput = {\n data: imageRecord.data as Uint8Array | Uint8ClampedArray,\n width: imageRecord.width as number,\n height: imageRecord.height as number,\n };\n\n validateImageInput(normalizedImage);\n const buffer = normalizedImage.data.buffer;\n validateArrayBuffer(buffer);\n\n try {\n const result = await callWorker<\n { image: ImageInput; options: ResizeOptions },\n ImageInput\n >(worker, 'resize:run', { image: normalizedImage, options }, signal, [\n buffer,\n ]);\n\n return result;\n } catch (error) {\n console.error('Resize error:', error);\n throw error;\n }\n }\n\n async terminate(): Promise<void> {\n if (this.worker) {\n this.worker.terminate();\n this.worker = null;\n this.workerReady = null;\n }\n }\n}\n\nexport function createBridge(mode: 'worker' | 'client'): ResizeBridge {\n return mode === 'client'\n ? new ResizeClientBridge()\n : new ResizeWorkerBridge();\n}\n"
|
|
9
|
+
],
|
|
10
|
+
"mappings": "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",
|
|
11
|
+
"debugId": "26D9507FE5210F9564756E2164756E21",
|
|
12
|
+
"names": []
|
|
13
|
+
}
|
package/dist/bridge.d.ts
CHANGED
|
@@ -4,7 +4,9 @@
|
|
|
4
4
|
import { type ImageInput } from '@squoosh-kit/runtime';
|
|
5
5
|
import type { ResizeOptions } from './types.ts';
|
|
6
6
|
interface ResizeBridge {
|
|
7
|
-
resize(
|
|
7
|
+
resize(image: ImageInput, options: ResizeOptions, signal?: AbortSignal): Promise<ImageInput>;
|
|
8
|
+
terminate(): Promise<void>;
|
|
8
9
|
}
|
|
9
10
|
export declare function createBridge(mode: 'worker' | 'client'): ResizeBridge;
|
|
10
11
|
export {};
|
|
12
|
+
//# sourceMappingURL=bridge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAGL,KAAK,UAAU,EAChB,MAAM,sBAAsB,CAAC;AAG9B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,UAAU,YAAY;IACpB,MAAM,CACJ,KAAK,EAAE,UAAU,EACjB,OAAO,EAAE,aAAa,EACtB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,UAAU,CAAC,CAAC;IACvB,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5B;AAyFD,wBAAgB,YAAY,CAAC,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,YAAY,CAIpE"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
var j={};M(j,{createBridge:()=>b});module.exports=C(j);function N(){return typeof Bun<"u"}var T=0;async function S(G,J,K,Y,H){return new Promise((X,Q)=>{let Z=++T;if(Y?.aborted){Q(new DOMException("Aborted","AbortError"));return}let V=(D)=>{let _=D.data;if(_.id!==Z)return;if($(),_.ok&&_.data!==void 0)X(_.data);else Q(Error(_.error||"Unknown worker error"))},O=(D)=>{$(),Q(Error(`Worker error: ${D.message}`))},x=()=>{$(),Q(new DOMException("Aborted","AbortError"))},$=()=>{G.removeEventListener("message",V),G.removeEventListener("error",O),Y?.removeEventListener("abort",x)};G.addEventListener("message",V),G.addEventListener("error",O),Y?.addEventListener("abort",x);let L={type:J,id:Z,payload:K};if(H&&H.length>0)G.postMessage(L,H);else G.postMessage(L)})}function W(G){let J=G.endsWith(".js")?G:`${G}.js`;if(typeof window<"u"){let Q={"webp.worker.js":"/dist/features/webp/webp.worker.browser.mjs","resize.worker.js":"/dist/features/resize/resize.worker.browser.mjs"}[J];if(Q)return new URL(Q,window.location.href)}let K=N()?".bun.js":".node.mjs",H={"webp.worker.js":`../../webp/dist/webp.worker${K}`,"resize.worker.js":`../../resize/dist/resize.worker${K}`}[J];if(H)return new URL(H,"file:///home/bnowak/repos/squoosh-lite/packages/runtime/src/worker-helper.ts");return new URL(J,"file:///home/bnowak/repos/squoosh-lite/packages/runtime/src/worker-helper.ts")}function q(G){let J=W(G);try{return new Worker(J.href,{type:"module"})}catch(K){let Y=K instanceof Error?K.message:String(K);throw Error(`Failed to create worker from ${J}: ${Y}. Ensure the worker file exists at the expected location. Expected worker file: ${G}${G.endsWith(".js")?"":".js"}`)}}function U(G,J=1e4){return new Promise((K,Y)=>{let H=setTimeout(()=>{Y(Error(`Worker initialization timeout after ${J}ms. Worker file: ${G}`))},J),X;try{X=q(G)}catch(Z){clearTimeout(H),Y(Z);return}let Q=(Z)=>{if(Z.data?.type==="worker:ready")clearTimeout(H),X.removeEventListener("message",Q),K(X)};X.addEventListener("message",Q),X.postMessage({type:"worker:ping"})})}class P{async resize(G,J,K){return B(G,J,K)}async terminate(){}}class I{worker=null;workerReady=null;async getWorker(){if(!this.worker){if(!this.workerReady)this.workerReady=this.createWorker();this.worker=await this.workerReady}return this.worker}async createWorker(){return U("resize.worker")}async resize(G,J,K){let Y=await this.getWorker();if(!G||typeof G!=="object")throw TypeError("image must be an object");let H=G;if(!H.data)throw TypeError("image.data is required");if(H.width===void 0||H.height===void 0)throw TypeError("image.width and image.height are required");let X={data:H.data,width:H.width,height:H.height};E(X);let Q=X.data.buffer;A(Q);try{return await S(Y,"resize:run",{image:X,options:J},K,[Q])}catch(Z){throw console.error("Resize error:",Z),Z}}async terminate(){if(this.worker)this.worker.terminate(),this.worker=null,this.workerReady=null}}function b(G){return G==="client"?new P:new I}
|
|
2
|
+
|
|
3
|
+
//# debugId=814DE931A95A6D5D64756E2164756E21
|