@squoosh-kit/oxipng 0.2.1

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 (40) hide show
  1. package/dist/bridge.d.ts +15 -0
  2. package/dist/bridge.d.ts.map +1 -0
  3. package/dist/index.browser.mjs +520 -0
  4. package/dist/index.browser.mjs.map +18 -0
  5. package/dist/index.bun.js +521 -0
  6. package/dist/index.bun.js.map +18 -0
  7. package/dist/index.d.ts +47 -0
  8. package/dist/index.d.ts.map +1 -0
  9. package/dist/index.node.cjs +548 -0
  10. package/dist/index.node.cjs.map +18 -0
  11. package/dist/index.node.mjs +520 -0
  12. package/dist/index.node.mjs.map +18 -0
  13. package/dist/oxipng.worker.browser.mjs +452 -0
  14. package/dist/oxipng.worker.browser.mjs.map +16 -0
  15. package/dist/oxipng.worker.bun.js +453 -0
  16. package/dist/oxipng.worker.bun.js.map +16 -0
  17. package/dist/oxipng.worker.d.ts +7 -0
  18. package/dist/oxipng.worker.d.ts.map +1 -0
  19. package/dist/oxipng.worker.node.cjs +472 -0
  20. package/dist/oxipng.worker.node.cjs.map +16 -0
  21. package/dist/oxipng.worker.node.mjs +452 -0
  22. package/dist/oxipng.worker.node.mjs.map +16 -0
  23. package/dist/types.d.ts +5 -0
  24. package/dist/types.d.ts.map +1 -0
  25. package/dist/validators.d.ts +7 -0
  26. package/dist/validators.d.ts.map +1 -0
  27. package/dist/wasm/oxipng/README.md +5 -0
  28. package/dist/wasm/oxipng/package.json +17 -0
  29. package/dist/wasm/oxipng/squoosh_oxipng.d.ts +31 -0
  30. package/dist/wasm/oxipng/squoosh_oxipng.js +120 -0
  31. package/dist/wasm/oxipng/squoosh_oxipng_bg.wasm +0 -0
  32. package/dist/wasm/oxipng/squoosh_oxipng_bg.wasm.d.ts +7 -0
  33. package/dist/wasm/oxipng-parallel/README.md +5 -0
  34. package/dist/wasm/oxipng-parallel/package.json +17 -0
  35. package/dist/wasm/oxipng-parallel/snippets/wasm-bindgen-rayon-3d2df09ebec17a22/src/workerHelpers.js +98 -0
  36. package/dist/wasm/oxipng-parallel/squoosh_oxipng.d.ts +64 -0
  37. package/dist/wasm/oxipng-parallel/squoosh_oxipng.js +220 -0
  38. package/dist/wasm/oxipng-parallel/squoosh_oxipng_bg.wasm +0 -0
  39. package/dist/wasm/oxipng-parallel/squoosh_oxipng_bg.wasm.d.ts +14 -0
  40. package/package.json +52 -0
@@ -0,0 +1,47 @@
1
+ /**
2
+ * @squoosh-kit/oxipng public API
3
+ */
4
+ import type { ImageInput } from '@squoosh-kit/runtime';
5
+ import { type BridgeOptions } from './bridge';
6
+ import type { OxipngOptions } from './types';
7
+ export type { ImageInput, OxipngOptions };
8
+ /**
9
+ * A reusable OxiPNG optimizer function that can be terminated to clean up resources.
10
+ */
11
+ export type OxipngOptimizerFactory = ((imageData: ImageInput, options?: OxipngOptions, signal?: AbortSignal) => Promise<Uint8Array>) & {
12
+ /**
13
+ * Terminates the optimizer and cleans up resources.
14
+ * Important for worker mode to prevent memory leaks.
15
+ *
16
+ * @example
17
+ * const optimizer = createOxipngOptimizer('worker');
18
+ * try {
19
+ * const result = await optimizer(imageData, { level: 3 });
20
+ * } finally {
21
+ * await optimizer.terminate();
22
+ * }
23
+ */
24
+ terminate(): Promise<void>;
25
+ };
26
+ /**
27
+ * Optimizes a PNG image using OxiPNG. Uses worker mode for UI responsiveness.
28
+ *
29
+ * @param imageData - The raw RGBA image data to optimize.
30
+ * @param options - OxiPNG optimization options.
31
+ * @param signal - Optional AbortSignal to cancel the operation.
32
+ * @returns A Promise resolving to the optimized PNG data as a Uint8Array.
33
+ *
34
+ * @example
35
+ * const result = await optimize(imageData, { level: 3 });
36
+ */
37
+ export declare function optimize(imageData: ImageInput, options?: OxipngOptions, signal?: AbortSignal): Promise<Uint8Array>;
38
+ /**
39
+ * Creates a reusable OxiPNG optimizer for a specific execution mode.
40
+ * Useful for processing multiple images without creating new workers each time.
41
+ *
42
+ * @param mode - The execution mode, either 'worker' or 'client'.
43
+ * @param options - Optional bridge configuration options.
44
+ * @returns A function that optimizes a PNG image with optional AbortSignal.
45
+ */
46
+ export declare function createOxipngOptimizer(mode?: 'worker' | 'client', options?: BridgeOptions): OxipngOptimizerFactory;
47
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAgB,KAAK,aAAa,EAAE,MAAM,UAAU,CAAC;AAC5D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAE7C,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,CAAC;AAK1C;;GAEG;AACH,MAAM,MAAM,sBAAsB,GAAG,CAAC,CACpC,SAAS,EAAE,UAAU,EACrB,OAAO,CAAC,EAAE,aAAa,EACvB,MAAM,CAAC,EAAE,WAAW,KACjB,OAAO,CAAC,UAAU,CAAC,CAAC,GAAG;IAC1B;;;;;;;;;;;OAWG;IACH,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5B,CAAC;AAEF;;;;;;;;;;GAUG;AACH,wBAAsB,QAAQ,CAC5B,SAAS,EAAE,UAAU,EACrB,OAAO,CAAC,EAAE,aAAa,EACvB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,UAAU,CAAC,CAMrB;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,GAAE,QAAQ,GAAG,QAAmB,EACpC,OAAO,CAAC,EAAE,aAAa,GACtB,sBAAsB,CAiBxB"}
@@ -0,0 +1,548 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropNames = Object.getOwnPropertyNames;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ function __accessProp(key) {
6
+ return this[key];
7
+ }
8
+ var __toCommonJS = (from) => {
9
+ var entry = (__moduleCache ??= new WeakMap).get(from), desc;
10
+ if (entry)
11
+ return entry;
12
+ entry = __defProp({}, "__esModule", { value: true });
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (var key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(entry, key))
16
+ __defProp(entry, key, {
17
+ get: __accessProp.bind(from, key),
18
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
19
+ });
20
+ }
21
+ __moduleCache.set(from, entry);
22
+ return entry;
23
+ };
24
+ var __moduleCache;
25
+ var __returnValue = (v) => v;
26
+ function __exportSetter(name, newValue) {
27
+ this[name] = __returnValue.bind(null, newValue);
28
+ }
29
+ var __export = (target, all) => {
30
+ for (var name in all)
31
+ __defProp(target, name, {
32
+ get: all[name],
33
+ enumerable: true,
34
+ configurable: true,
35
+ set: __exportSetter.bind(all, name)
36
+ });
37
+ };
38
+ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
39
+
40
+ // ../runtime/src/env.ts
41
+ function isBun() {
42
+ return typeof Bun !== "undefined";
43
+ }
44
+
45
+ // ../runtime/src/worker-call.ts
46
+ async function callWorker(worker, type, payload, signal, transfer) {
47
+ return new Promise((resolve, reject) => {
48
+ const id = ++requestId;
49
+ if (signal?.aborted) {
50
+ reject(new DOMException("Aborted", "AbortError"));
51
+ return;
52
+ }
53
+ const handleMessage = (event) => {
54
+ const response = event.data;
55
+ if (response.id !== id)
56
+ return;
57
+ cleanup();
58
+ if (response.ok && response.data !== undefined) {
59
+ resolve(response.data);
60
+ } else {
61
+ reject(new Error(response.error || "Unknown worker error"));
62
+ }
63
+ };
64
+ const handleError = (error) => {
65
+ cleanup();
66
+ reject(new Error(`Worker error: ${error.message}`));
67
+ };
68
+ const handleAbort = () => {
69
+ cleanup();
70
+ reject(new DOMException("Aborted", "AbortError"));
71
+ };
72
+ const cleanup = () => {
73
+ worker.removeEventListener("message", handleMessage);
74
+ worker.removeEventListener("error", handleError);
75
+ signal?.removeEventListener("abort", handleAbort);
76
+ };
77
+ worker.addEventListener("message", handleMessage);
78
+ worker.addEventListener("error", handleError);
79
+ signal?.addEventListener("abort", handleAbort);
80
+ const request = { type, id, payload };
81
+ if (transfer && transfer.length > 0) {
82
+ worker.postMessage(request, transfer);
83
+ } else {
84
+ worker.postMessage(request);
85
+ }
86
+ });
87
+ }
88
+ var requestId = 0;
89
+
90
+ // ../runtime/src/worker-helper.ts
91
+ function createCodecWorker(workerFilename, options) {
92
+ const normalizedName = workerFilename.endsWith(".js") ? workerFilename : `${workerFilename}.js`;
93
+ const workerMap = {
94
+ "resize.worker.js": {
95
+ package: "@squoosh-kit/resize",
96
+ specifier: "resize.worker.js"
97
+ },
98
+ "webp.worker.js": {
99
+ package: "@squoosh-kit/webp",
100
+ specifier: "webp.worker.js"
101
+ },
102
+ "avif.worker.js": {
103
+ package: "@squoosh-kit/avif",
104
+ specifier: "avif.worker.js"
105
+ },
106
+ "mozjpeg.worker.js": {
107
+ package: "@squoosh-kit/mozjpeg",
108
+ specifier: "mozjpeg.worker.js"
109
+ },
110
+ "jxl.worker.js": {
111
+ package: "@squoosh-kit/jxl",
112
+ specifier: "jxl.worker.js"
113
+ },
114
+ "oxipng.worker.js": {
115
+ package: "@squoosh-kit/oxipng",
116
+ specifier: "oxipng.worker.js"
117
+ },
118
+ "png.worker.js": {
119
+ package: "@squoosh-kit/png",
120
+ specifier: "png.worker.js"
121
+ },
122
+ "imagequant.worker.js": {
123
+ package: "@squoosh-kit/imagequant",
124
+ specifier: "imagequant.worker.js"
125
+ },
126
+ "qoi.worker.js": {
127
+ package: "@squoosh-kit/qoi",
128
+ specifier: "qoi.worker.js"
129
+ },
130
+ "wp2.worker.js": {
131
+ package: "@squoosh-kit/wp2",
132
+ specifier: "wp2.worker.js"
133
+ },
134
+ "hqx.worker.js": {
135
+ package: "@squoosh-kit/hqx",
136
+ specifier: "hqx.worker.js"
137
+ },
138
+ "rotate.worker.js": {
139
+ package: "@squoosh-kit/rotate",
140
+ specifier: "rotate.worker.js"
141
+ },
142
+ "visdif.worker.js": {
143
+ package: "@squoosh-kit/visdif",
144
+ specifier: "visdif.worker.js"
145
+ }
146
+ };
147
+ const workerConfig = workerMap[normalizedName];
148
+ if (!workerConfig) {
149
+ throw new Error(`Unknown worker: ${normalizedName}. ` + `Supported workers: ${Object.keys(workerMap).join(", ")}`);
150
+ }
151
+ try {
152
+ if (typeof window !== "undefined") {
153
+ const packageName = workerConfig.package.split("/")[1];
154
+ const workerFile = normalizedName.replace(".js", ".browser.mjs");
155
+ console.log(`[worker-helper] In browser environment. Trying to create worker:`);
156
+ console.log(`[worker-helper] - Package Name: ${packageName}`);
157
+ console.log(`[worker-helper] - Worker File: ${workerFile}`);
158
+ if (options?.assetPath) {
159
+ let normalizedAssetPath = options.assetPath;
160
+ if (!normalizedAssetPath.startsWith("/")) {
161
+ normalizedAssetPath = "/" + normalizedAssetPath;
162
+ }
163
+ if (normalizedAssetPath.endsWith("/")) {
164
+ normalizedAssetPath = normalizedAssetPath.slice(0, -1);
165
+ }
166
+ const workerPath = `${normalizedAssetPath}/${packageName}/${workerFile}`;
167
+ const workerUrl = new URL(workerPath, window.location.origin).href;
168
+ console.log(`[worker-helper] Using provided assetPath. Full Worker URL: ${workerUrl}`);
169
+ try {
170
+ const worker = new Worker(workerUrl, { type: "module" });
171
+ console.log(`[worker-helper] Successfully created worker with assetPath: ${workerUrl}`);
172
+ return worker;
173
+ } catch (e) {
174
+ console.error(`[worker-helper] Failed to load worker from assetPath URL: ${workerUrl}`, e);
175
+ throw new Error(`Worker failed to load from ${workerUrl}: ${e instanceof Error ? e.message : String(e)}`, { cause: e });
176
+ }
177
+ }
178
+ const pathStrategies = [
179
+ `../../${packageName}/dist/${workerFile}`,
180
+ `../../../node_modules/@squoosh-kit/${packageName}/dist/${workerFile}`,
181
+ `../../../${packageName}/dist/${workerFile}`
182
+ ];
183
+ let lastError = null;
184
+ for (const relPath of pathStrategies) {
185
+ console.log("relPath:", relPath);
186
+ console.log("import.meta.url:", "file:///home/bnowak/repos/squoosh-kit/packages/runtime/src/worker-helper.ts");
187
+ try {
188
+ const workerUrl = new URL(relPath, "file:///home/bnowak/repos/squoosh-kit/packages/runtime/src/worker-helper.ts");
189
+ console.log(`[worker-helper] Trying path strategy. Full Worker URL: ${workerUrl.href}`);
190
+ const worker = new Worker(workerUrl, {
191
+ type: "module"
192
+ });
193
+ console.log(`[worker-helper] Successfully created worker with URL: ${workerUrl.href}`);
194
+ return worker;
195
+ } catch (error) {
196
+ console.warn(`[worker-helper] Path strategy failed for ${relPath}:`, error);
197
+ lastError = error instanceof Error ? error : new Error(String(error));
198
+ }
199
+ }
200
+ if (lastError) {
201
+ console.error("[worker-helper] All path strategies failed.", lastError);
202
+ throw lastError;
203
+ }
204
+ throw new Error(`Could not resolve worker ${normalizedName} using any available path strategy`);
205
+ }
206
+ const platformExt = isBun() ? ".bun.js" : ".node.mjs";
207
+ const baseName = normalizedName.replace(".js", "");
208
+ const pkgName = workerConfig.package.split("/")[1];
209
+ const srcRelPath = `../../${pkgName}/src/${baseName}.ts`;
210
+ console.log("srcRelPath:", srcRelPath);
211
+ console.log("import.meta.url:", "file:///home/bnowak/repos/squoosh-kit/packages/runtime/src/worker-helper.ts");
212
+ try {
213
+ return new Worker(new URL(srcRelPath, "file:///home/bnowak/repos/squoosh-kit/packages/runtime/src/worker-helper.ts"), {
214
+ type: "module"
215
+ });
216
+ } catch {
217
+ const distRelPath = `../../${pkgName}/dist/${baseName}.${platformExt.slice(1)}`;
218
+ console.log("distRelPath:", distRelPath);
219
+ console.log("import.meta.url:", "file:///home/bnowak/repos/squoosh-kit/packages/runtime/src/worker-helper.ts");
220
+ try {
221
+ return new Worker(new URL(distRelPath, "file:///home/bnowak/repos/squoosh-kit/packages/runtime/src/worker-helper.ts"), {
222
+ type: "module"
223
+ });
224
+ } catch {
225
+ if (typeof import.meta.resolve === "function") {
226
+ try {
227
+ const resolved = import.meta.resolve(`${workerConfig.package}/${workerConfig.specifier}`);
228
+ console.log("resolved:", resolved);
229
+ return new Worker(resolved, { type: "module" });
230
+ } catch {}
231
+ }
232
+ }
233
+ }
234
+ throw new Error(`Failed to create worker from ${normalizedName}. ` + `Tried TypeScript source, dist output, and import.meta.resolve. ` + `Ensure the @squoosh-kit/resize and @squoosh-kit/webp packages are installed.`);
235
+ } catch (error) {
236
+ const errorMessage = error instanceof Error ? error.message : String(error);
237
+ throw new Error(`Failed to create worker from ${normalizedName}: ${errorMessage}. ` + `Ensure the @squoosh-kit/resize and @squoosh-kit/webp packages are installed. ` + `If you're using Vite, ensure the worker files are not being optimized as dependencies.`, { cause: error });
238
+ }
239
+ }
240
+ function createReadyWorker(workerFilename, options, timeoutMs = 1e4) {
241
+ return new Promise((resolve, reject) => {
242
+ const timeout = setTimeout(() => {
243
+ reject(new Error(`Worker initialization timeout after ${timeoutMs}ms. Worker file: ${workerFilename}`));
244
+ }, timeoutMs);
245
+ let worker;
246
+ try {
247
+ worker = createCodecWorker(workerFilename, options);
248
+ } catch (error) {
249
+ clearTimeout(timeout);
250
+ reject(error);
251
+ return;
252
+ }
253
+ const handleMessage = (event) => {
254
+ if (event.data?.type === "worker:ready") {
255
+ clearTimeout(timeout);
256
+ worker.removeEventListener("message", handleMessage);
257
+ worker.removeEventListener("error", handleError);
258
+ worker.removeEventListener("messageerror", handleMessageError);
259
+ resolve(worker);
260
+ }
261
+ };
262
+ const handleError = (event) => {
263
+ clearTimeout(timeout);
264
+ worker.removeEventListener("message", handleMessage);
265
+ worker.removeEventListener("error", handleError);
266
+ worker.removeEventListener("messageerror", handleMessageError);
267
+ reject(new Error(`Worker failed to start: ${event?.message || "Unknown error"}. Worker file: ${workerFilename}`));
268
+ };
269
+ const handleMessageError = () => {
270
+ clearTimeout(timeout);
271
+ worker.removeEventListener("message", handleMessage);
272
+ worker.removeEventListener("error", handleError);
273
+ worker.removeEventListener("messageerror", handleMessageError);
274
+ reject(new Error(`Worker message error during initialization. Worker file: ${workerFilename}`));
275
+ };
276
+ worker.addEventListener("message", handleMessage);
277
+ worker.addEventListener("error", handleError);
278
+ worker.addEventListener("messageerror", handleMessageError);
279
+ worker.postMessage({ type: "worker:ping" });
280
+ });
281
+ }
282
+ var init_worker_helper = () => {};
283
+
284
+ // ../runtime/src/wasm-loader.ts
285
+ async function loadWasmBinary(relativePath, baseUrlOverride) {
286
+ const baseUrl = baseUrlOverride ? typeof baseUrlOverride === "string" ? new URL(".", baseUrlOverride) : new URL(".", baseUrlOverride.href) : new URL(".", "file:///home/bnowak/repos/squoosh-kit/packages/runtime/src/wasm-loader.ts");
287
+ const fullUrl = new URL(relativePath, baseUrl);
288
+ console.log(`[WasmLoader] Loading WASM from relative path: ${relativePath}`);
289
+ console.log(`[WasmLoader] Base URL (import.meta.url): ${baseUrl.href}`);
290
+ console.log(`[WasmLoader] Constructed full URL: ${fullUrl.href}`);
291
+ try {
292
+ const response = await fetch(fullUrl.href);
293
+ console.log(`[WasmLoader] Fetch response status for ${fullUrl.href}: ${response.status}`);
294
+ if (!response.ok) {
295
+ const responseText = await response.text();
296
+ console.error(`[WasmLoader] Fetch response text (first 500 chars):`, responseText.substring(0, 500));
297
+ throw new Error(`Failed to fetch WASM module at ${fullUrl.href}: ${response.status} ${response.statusText}`);
298
+ }
299
+ const contentType = response.headers.get("content-type");
300
+ console.log(`[WasmLoader] Response Content-Type: ${contentType}`);
301
+ if (!contentType || !contentType.includes("application/wasm")) {
302
+ console.warn(`[WasmLoader] Warning: WASM module at ${fullUrl.href} served with incorrect MIME type: "${contentType}". Should be "application/wasm".`);
303
+ }
304
+ return await response.arrayBuffer();
305
+ } catch (error) {
306
+ console.error(`[WasmLoader] CRITICAL: Fetching WASM binary from ${fullUrl.href} failed.`, error);
307
+ throw error;
308
+ }
309
+ }
310
+
311
+ // ../runtime/src/validators.ts
312
+ function validateImageInput(image) {
313
+ if (!image || typeof image !== "object") {
314
+ throw new TypeError("image must be an object");
315
+ }
316
+ const imageObj = image;
317
+ if (!("data" in imageObj)) {
318
+ throw new TypeError("image.data is required");
319
+ }
320
+ const { data } = imageObj;
321
+ if (!(data instanceof Uint8Array || data instanceof Uint8ClampedArray)) {
322
+ throw new TypeError("image.data must be Uint8Array or Uint8ClampedArray");
323
+ }
324
+ if (!("width" in imageObj) || !("height" in imageObj)) {
325
+ throw new TypeError("image.width and image.height are required");
326
+ }
327
+ const { width, height } = imageObj;
328
+ if (typeof width !== "number" || !Number.isInteger(width) || width <= 0) {
329
+ throw new RangeError(`image.width must be a positive integer, got ${width}`);
330
+ }
331
+ if (typeof height !== "number" || !Number.isInteger(height) || height <= 0) {
332
+ throw new RangeError(`image.height must be a positive integer, got ${height}`);
333
+ }
334
+ const expectedSize = width * height * 4;
335
+ if (data.length < expectedSize) {
336
+ throw new RangeError(`image.data too small: ${data.length} bytes, expected at least ${expectedSize} bytes for ${width}x${height} RGBA image`);
337
+ }
338
+ }
339
+ // ../runtime/src/simd-detector.ts
340
+ var init_simd_detector = () => {};
341
+
342
+ // ../runtime/src/index.ts
343
+ var init_src = __esm(() => {
344
+ init_worker_helper();
345
+ init_simd_detector();
346
+ });
347
+
348
+ // src/oxipng.worker.ts
349
+ var exports_oxipng_worker = {};
350
+ __export(exports_oxipng_worker, {
351
+ oxipngOptimizeClient: () => oxipngOptimizeClient
352
+ });
353
+ module.exports = __toCommonJS(exports_oxipng_worker);
354
+ async function initOxiPNG() {
355
+ if (optimiseFn) {
356
+ return;
357
+ }
358
+ if (initPromise) {
359
+ return initPromise;
360
+ }
361
+ initPromise = (async () => {
362
+ try {
363
+ const workerBaseUrl = new URL(".", "file:///home/bnowak/repos/squoosh-kit/packages/oxipng/src/oxipng.worker.ts");
364
+ const isSource = "file:///home/bnowak/repos/squoosh-kit/packages/oxipng/src/oxipng.worker.ts".includes("/src/");
365
+ const wasmPaths = isSource ? [
366
+ "../wasm/oxipng/squoosh_oxipng_bg.wasm",
367
+ "./wasm/oxipng/squoosh_oxipng_bg.wasm"
368
+ ] : [
369
+ "./wasm/oxipng/squoosh_oxipng_bg.wasm",
370
+ "../wasm/oxipng/squoosh_oxipng_bg.wasm"
371
+ ];
372
+ let wasmBuffer = null;
373
+ let lastError = null;
374
+ for (const path of wasmPaths) {
375
+ try {
376
+ wasmBuffer = await loadWasmBinary(path, workerBaseUrl);
377
+ break;
378
+ } catch (error) {
379
+ lastError = error instanceof Error ? error : new Error(String(error));
380
+ }
381
+ }
382
+ if (!wasmBuffer) {
383
+ throw lastError || new Error("Could not load OxiPNG WASM binary from any path");
384
+ }
385
+ const jsPaths = isSource ? [
386
+ "../wasm/oxipng/squoosh_oxipng.js",
387
+ "./wasm/oxipng/squoosh_oxipng.js"
388
+ ] : [
389
+ "./wasm/oxipng/squoosh_oxipng.js",
390
+ "../wasm/oxipng/squoosh_oxipng.js"
391
+ ];
392
+ let oxipngModule = null;
393
+ let jsLastError = null;
394
+ for (const jsPath of jsPaths) {
395
+ try {
396
+ oxipngModule = await import(jsPath);
397
+ break;
398
+ } catch (error) {
399
+ jsLastError = error instanceof Error ? error : new Error(String(error));
400
+ }
401
+ }
402
+ if (!oxipngModule) {
403
+ throw jsLastError || new Error("Could not load OxiPNG JS module from any path");
404
+ }
405
+ await oxipngModule.default(wasmBuffer);
406
+ optimiseFn = oxipngModule.optimise;
407
+ } catch (error) {
408
+ initPromise = null;
409
+ throw new Error(`Failed to initialize OxiPNG WASM module: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
410
+ }
411
+ })();
412
+ return initPromise;
413
+ }
414
+ async function oxipngOptimizeClient(image, options, signal) {
415
+ if (signal?.aborted) {
416
+ throw new DOMException("Aborted", "AbortError");
417
+ }
418
+ await initOxiPNG();
419
+ if (signal?.aborted) {
420
+ throw new DOMException("Aborted", "AbortError");
421
+ }
422
+ if (!optimiseFn) {
423
+ throw new Error("OxiPNG module not initialized");
424
+ }
425
+ const { data, width, height } = image;
426
+ const level = options?.level ?? 2;
427
+ const interlace = options?.interlace ?? false;
428
+ const clampedData = data instanceof Uint8ClampedArray ? data : new Uint8ClampedArray(data.buffer, data.byteOffset, data.length);
429
+ const result = optimiseFn(clampedData, width, height, level, interlace);
430
+ if (!result) {
431
+ throw new Error("OxiPNG optimization failed");
432
+ }
433
+ return result;
434
+ }
435
+ var optimiseFn = null, initPromise = null;
436
+ var init_oxipng_worker = __esm(() => {
437
+ init_src();
438
+ if (typeof self !== "undefined") {
439
+ self.onmessage = async (event) => {
440
+ const data = event.data;
441
+ if (data?.type === "worker:ping") {
442
+ await initOxiPNG();
443
+ self.postMessage({ type: "worker:ready" });
444
+ return;
445
+ }
446
+ const request = data;
447
+ const response = {
448
+ id: request.id,
449
+ ok: false
450
+ };
451
+ try {
452
+ if (request.type === "oxipng:optimize") {
453
+ const result = await oxipngOptimizeClient(request.payload.image, request.payload.options);
454
+ response.ok = true;
455
+ response.data = result;
456
+ self.postMessage(response, {
457
+ transfer: [result.buffer]
458
+ });
459
+ } else {
460
+ response.error = `Unknown message type: ${request.type}`;
461
+ self.postMessage(response);
462
+ }
463
+ } catch (error) {
464
+ response.error = error instanceof Error ? error.message : String(error);
465
+ self.postMessage(response);
466
+ }
467
+ };
468
+ }
469
+ });
470
+
471
+ // src/index.ts
472
+ var exports_src = {};
473
+ __export(exports_src, {
474
+ optimize: () => optimize,
475
+ createOxipngOptimizer: () => createOxipngOptimizer
476
+ });
477
+ module.exports = __toCommonJS(exports_src);
478
+
479
+ // src/bridge.ts
480
+ init_src();
481
+ init_src();
482
+
483
+ class OxipngClientBridge {
484
+ async optimize(image, options, signal) {
485
+ const module2 = await Promise.resolve().then(() => (init_oxipng_worker(), exports_oxipng_worker));
486
+ const oxipngOptimizeClient2 = module2.oxipngOptimizeClient;
487
+ return oxipngOptimizeClient2(image, options, signal);
488
+ }
489
+ async terminate() {}
490
+ }
491
+
492
+ class OxipngWorkerBridge {
493
+ worker = null;
494
+ workerReady = null;
495
+ options;
496
+ constructor(options) {
497
+ this.options = options;
498
+ }
499
+ async getWorker() {
500
+ if (!this.workerReady) {
501
+ this.workerReady = this.createWorker();
502
+ }
503
+ return this.workerReady;
504
+ }
505
+ async createWorker() {
506
+ this.worker = await createReadyWorker("oxipng.worker.js", this.options);
507
+ return this.worker;
508
+ }
509
+ async optimize(image, options, signal) {
510
+ const worker = await this.getWorker();
511
+ validateImageInput(image);
512
+ return callWorker(worker, "oxipng:optimize", { image, options }, signal);
513
+ }
514
+ async terminate() {
515
+ if (this.worker) {
516
+ this.worker.terminate();
517
+ this.worker = null;
518
+ this.workerReady = null;
519
+ }
520
+ }
521
+ }
522
+ function createBridge(mode, options) {
523
+ if (mode === "worker") {
524
+ return new OxipngWorkerBridge(options);
525
+ }
526
+ return new OxipngClientBridge;
527
+ }
528
+
529
+ // src/index.ts
530
+ var globalWorkerBridge = null;
531
+ async function optimize(imageData, options, signal) {
532
+ if (!globalWorkerBridge) {
533
+ globalWorkerBridge = createBridge("worker");
534
+ }
535
+ return globalWorkerBridge.optimize(imageData, options, signal);
536
+ }
537
+ function createOxipngOptimizer(mode = "worker", options) {
538
+ const bridge = createBridge(mode, options);
539
+ return Object.assign((imageData, optimizeOptions, signal) => {
540
+ return bridge.optimize(imageData, optimizeOptions, signal);
541
+ }, {
542
+ terminate: async () => {
543
+ await bridge.terminate();
544
+ }
545
+ });
546
+ }
547
+
548
+ //# debugId=D05EEE6F463D176964756E2164756E21