@standardagents/sip 0.10.0-dev

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/dist/index.js ADDED
@@ -0,0 +1,1272 @@
1
+ // src/probe.ts
2
+ var MAGIC = {
3
+ // JPEG: FFD8FF
4
+ JPEG: [255, 216, 255],
5
+ // PNG: 89504E47 0D0A1A0A
6
+ PNG: [137, 80, 78, 71, 13, 10, 26, 10],
7
+ // WebP: RIFF....WEBP
8
+ RIFF: [82, 73, 70, 70],
9
+ // "RIFF"
10
+ WEBP: [87, 69, 66, 80],
11
+ // "WEBP"
12
+ // AVIF: ....ftypavif or ....ftypavis
13
+ FTYP: [102, 116, 121, 112]
14
+ // "ftyp"
15
+ };
16
+ function detectFormat(data) {
17
+ if (data.length < 12) return "unknown";
18
+ if (data[0] === MAGIC.JPEG[0] && data[1] === MAGIC.JPEG[1] && data[2] === MAGIC.JPEG[2]) {
19
+ return "jpeg";
20
+ }
21
+ if (data[0] === MAGIC.PNG[0] && data[1] === MAGIC.PNG[1] && data[2] === MAGIC.PNG[2] && data[3] === MAGIC.PNG[3] && data[4] === MAGIC.PNG[4] && data[5] === MAGIC.PNG[5] && data[6] === MAGIC.PNG[6] && data[7] === MAGIC.PNG[7]) {
22
+ return "png";
23
+ }
24
+ if (data[0] === MAGIC.RIFF[0] && data[1] === MAGIC.RIFF[1] && data[2] === MAGIC.RIFF[2] && data[3] === MAGIC.RIFF[3] && data[8] === MAGIC.WEBP[0] && data[9] === MAGIC.WEBP[1] && data[10] === MAGIC.WEBP[2] && data[11] === MAGIC.WEBP[3]) {
25
+ return "webp";
26
+ }
27
+ if (data[4] === MAGIC.FTYP[0] && data[5] === MAGIC.FTYP[1] && data[6] === MAGIC.FTYP[2] && data[7] === MAGIC.FTYP[3]) {
28
+ const brand = String.fromCharCode(data[8], data[9], data[10], data[11]);
29
+ if (brand === "avif" || brand === "avis" || brand === "mif1" || brand === "msf1") {
30
+ return "avif";
31
+ }
32
+ }
33
+ return "unknown";
34
+ }
35
+ function probeJpeg(data) {
36
+ let offset = 2;
37
+ while (offset < data.length - 1) {
38
+ if (data[offset] !== 255) {
39
+ offset++;
40
+ continue;
41
+ }
42
+ while (offset < data.length && data[offset] === 255) {
43
+ offset++;
44
+ }
45
+ if (offset >= data.length) break;
46
+ const marker = data[offset++];
47
+ const isSOF = marker >= 192 && marker <= 195 || marker >= 197 && marker <= 199 || marker >= 201 && marker <= 203 || marker >= 205 && marker <= 207;
48
+ if (isSOF) {
49
+ if (offset + 7 > data.length) return null;
50
+ const height = data[offset + 3] << 8 | data[offset + 4];
51
+ const width = data[offset + 5] << 8 | data[offset + 6];
52
+ return { width, height };
53
+ }
54
+ if (marker === 216 || marker === 217 || marker >= 208 && marker <= 215) {
55
+ continue;
56
+ }
57
+ if (offset + 1 >= data.length) break;
58
+ const segmentLength = data[offset] << 8 | data[offset + 1];
59
+ offset += segmentLength;
60
+ }
61
+ return null;
62
+ }
63
+ function probePng(data) {
64
+ if (data.length < 24) return null;
65
+ const chunkType = String.fromCharCode(data[12], data[13], data[14], data[15]);
66
+ if (chunkType !== "IHDR") return null;
67
+ const width = data[16] << 24 | data[17] << 16 | data[18] << 8 | data[19];
68
+ const height = data[20] << 24 | data[21] << 16 | data[22] << 8 | data[23];
69
+ const colorType = data[25];
70
+ const hasAlpha = colorType === 4 || colorType === 6;
71
+ return { width, height, hasAlpha };
72
+ }
73
+ function probeWebp(data) {
74
+ if (data.length < 30) return null;
75
+ const chunkType = String.fromCharCode(data[12], data[13], data[14], data[15]);
76
+ if (chunkType === "VP8 ") {
77
+ if (data.length < 30) return null;
78
+ if (data[23] !== 157 || data[24] !== 1 || data[25] !== 42) return null;
79
+ const width = (data[26] | data[27] << 8) & 16383;
80
+ const height = (data[28] | data[29] << 8) & 16383;
81
+ return { width, height, hasAlpha: false };
82
+ }
83
+ if (chunkType === "VP8L") {
84
+ if (data[20] !== 47) return null;
85
+ const bits = data[21] | data[22] << 8 | data[23] << 16 | data[24] << 24;
86
+ const width = (bits & 16383) + 1;
87
+ const height = (bits >> 14 & 16383) + 1;
88
+ const hasAlpha = (bits >> 28 & 1) === 1;
89
+ return { width, height, hasAlpha };
90
+ }
91
+ if (chunkType === "VP8X") {
92
+ const flags = data[20];
93
+ const hasAlpha = (flags & 16) !== 0;
94
+ const width = (data[24] | data[25] << 8 | data[26] << 16) + 1;
95
+ const height = (data[27] | data[28] << 8 | data[29] << 16) + 1;
96
+ return { width, height, hasAlpha };
97
+ }
98
+ return null;
99
+ }
100
+ function probeAvif(data) {
101
+ let offset = 0;
102
+ while (offset + 8 <= data.length) {
103
+ const size = data[offset] << 24 | data[offset + 1] << 16 | data[offset + 2] << 8 | data[offset + 3];
104
+ const type = String.fromCharCode(
105
+ data[offset + 4],
106
+ data[offset + 5],
107
+ data[offset + 6],
108
+ data[offset + 7]
109
+ );
110
+ if (size === 0) break;
111
+ if (size < 8) break;
112
+ if (type === "ispe" && offset + 20 <= data.length) {
113
+ const width = data[offset + 12] << 24 | data[offset + 13] << 16 | data[offset + 14] << 8 | data[offset + 15];
114
+ const height = data[offset + 16] << 24 | data[offset + 17] << 16 | data[offset + 18] << 8 | data[offset + 19];
115
+ if (width > 0 && height > 0) {
116
+ return { width, height };
117
+ }
118
+ }
119
+ if (type === "meta" || type === "iprp" || type === "ipco") {
120
+ const headerSize = type === "meta" ? 12 : 8;
121
+ offset += headerSize;
122
+ continue;
123
+ }
124
+ offset += size;
125
+ }
126
+ return null;
127
+ }
128
+ function probe(input) {
129
+ const data = input instanceof ArrayBuffer ? new Uint8Array(input) : input;
130
+ const format = detectFormat(data);
131
+ let result = null;
132
+ switch (format) {
133
+ case "jpeg":
134
+ result = probeJpeg(data);
135
+ break;
136
+ case "png":
137
+ result = probePng(data);
138
+ break;
139
+ case "webp":
140
+ result = probeWebp(data);
141
+ break;
142
+ case "avif":
143
+ result = probeAvif(data);
144
+ break;
145
+ }
146
+ if (!result) {
147
+ return {
148
+ format: "unknown",
149
+ width: 0,
150
+ height: 0,
151
+ hasAlpha: false
152
+ };
153
+ }
154
+ return {
155
+ format,
156
+ width: result.width,
157
+ height: result.height,
158
+ hasAlpha: result.hasAlpha ?? false
159
+ };
160
+ }
161
+ function detectImageFormat(input) {
162
+ const data = input instanceof ArrayBuffer ? new Uint8Array(input) : input;
163
+ return detectFormat(data);
164
+ }
165
+
166
+ // src/decoders/simple.ts
167
+ function isNode() {
168
+ return typeof process !== "undefined" && process.versions != null && process.versions.node != null;
169
+ }
170
+ async function initCodecForNode(initFn, wasmPath) {
171
+ const { readFile } = await import('fs/promises');
172
+ const { createRequire } = await import('module');
173
+ const require2 = createRequire(import.meta.url);
174
+ const resolvedPath = require2.resolve(wasmPath);
175
+ const wasmBuffer = await readFile(resolvedPath);
176
+ const wasmModule2 = await WebAssembly.compile(wasmBuffer);
177
+ await initFn(wasmModule2);
178
+ }
179
+ var SimpleDecoder = class {
180
+ format;
181
+ supportsScanline = false;
182
+ supportsScaledDecode = false;
183
+ data;
184
+ width = 0;
185
+ height = 0;
186
+ hasAlpha = false;
187
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
188
+ decodeFn = null;
189
+ constructor(format, data) {
190
+ this.format = format;
191
+ this.data = data;
192
+ }
193
+ async init(data) {
194
+ this.data = data;
195
+ switch (this.format) {
196
+ case "avif": {
197
+ const { default: decode, init } = await import('@jsquash/avif/decode.js');
198
+ if (isNode()) {
199
+ await initCodecForNode(init, "@jsquash/avif/codec/dec/avif_dec.wasm");
200
+ }
201
+ this.decodeFn = decode;
202
+ this.hasAlpha = true;
203
+ break;
204
+ }
205
+ case "webp": {
206
+ const { default: decode, init } = await import('@jsquash/webp/decode.js');
207
+ if (isNode()) {
208
+ await initCodecForNode(init, "@jsquash/webp/codec/dec/webp_dec.wasm");
209
+ }
210
+ this.decodeFn = decode;
211
+ this.hasAlpha = true;
212
+ break;
213
+ }
214
+ case "jpeg":
215
+ case "png":
216
+ throw new Error(
217
+ `${this.format.toUpperCase()} requires native WASM decoder. Build the WASM module with \`pnpm build:wasm\` in packages/sip.`
218
+ );
219
+ default:
220
+ throw new Error(`Unsupported format for SimpleDecoder: ${this.format}`);
221
+ }
222
+ const imageData = await this.decodeFn(this.data);
223
+ if (!imageData) {
224
+ throw new Error(`Failed to decode ${this.format} image`);
225
+ }
226
+ this.width = imageData.width;
227
+ this.height = imageData.height;
228
+ return {
229
+ width: this.width,
230
+ height: this.height,
231
+ hasAlpha: this.hasAlpha
232
+ };
233
+ }
234
+ async decode(_scaleFactor) {
235
+ if (!this.decodeFn) {
236
+ throw new Error("Decoder not initialized. Call init() first.");
237
+ }
238
+ const imageData = await this.decodeFn(this.data);
239
+ this.width = imageData.width;
240
+ this.height = imageData.height;
241
+ const rgba = new Uint8Array(imageData.data.buffer);
242
+ const rgb = new Uint8Array(this.width * this.height * 3);
243
+ let srcIdx = 0;
244
+ let dstIdx = 0;
245
+ const pixelCount = this.width * this.height;
246
+ for (let i = 0; i < pixelCount; i++) {
247
+ rgb[dstIdx++] = rgba[srcIdx++];
248
+ rgb[dstIdx++] = rgba[srcIdx++];
249
+ rgb[dstIdx++] = rgba[srcIdx++];
250
+ srcIdx++;
251
+ }
252
+ return {
253
+ pixels: rgb,
254
+ width: this.width,
255
+ height: this.height
256
+ };
257
+ }
258
+ dispose() {
259
+ this.decodeFn = null;
260
+ }
261
+ };
262
+ async function createDecoder(format, data) {
263
+ const decoder = new SimpleDecoder(format, data);
264
+ await decoder.init(data);
265
+ return decoder;
266
+ }
267
+
268
+ // src/wasm/loader.ts
269
+ var wasmModule = null;
270
+ var wasmPromise = null;
271
+ var precompiledWasmModule = null;
272
+ function isWasmAvailable() {
273
+ return wasmModule !== null;
274
+ }
275
+ async function initWithWasmModule(compiledModule) {
276
+ console.log("[sip:initWithWasmModule] Called with module:", compiledModule ? "provided" : "none");
277
+ if (wasmModule) {
278
+ console.log("[sip:initWithWasmModule] Already initialized, skipping");
279
+ return;
280
+ }
281
+ if (compiledModule) {
282
+ precompiledWasmModule = compiledModule;
283
+ console.log("[sip:initWithWasmModule] Stored pre-compiled module");
284
+ }
285
+ console.log("[sip:initWithWasmModule] Calling loadWasm...");
286
+ await loadWasm();
287
+ console.log("[sip:initWithWasmModule] loadWasm completed, wasmModule:", wasmModule ? "loaded" : "null");
288
+ }
289
+ function getWasmModule() {
290
+ if (!wasmModule) {
291
+ throw new Error("WASM module not loaded. Call loadWasm() first.");
292
+ }
293
+ return wasmModule;
294
+ }
295
+ async function loadWasm() {
296
+ if (wasmModule) {
297
+ return wasmModule;
298
+ }
299
+ if (wasmPromise) {
300
+ return wasmPromise;
301
+ }
302
+ wasmPromise = doLoadWasm();
303
+ try {
304
+ wasmModule = await wasmPromise;
305
+ return wasmModule;
306
+ } catch (err) {
307
+ wasmPromise = null;
308
+ throw err;
309
+ }
310
+ }
311
+ async function doLoadWasm() {
312
+ console.log("[sip:doLoadWasm] Starting...");
313
+ if (typeof globalThis !== "undefined" && globalThis.__SIP_WASM_LOADER__) {
314
+ console.log("[sip:doLoadWasm] Using external loader");
315
+ const loader = globalThis.__SIP_WASM_LOADER__;
316
+ return await loader();
317
+ }
318
+ try {
319
+ console.log("[sip:doLoadWasm] Importing sip.js...");
320
+ const createSipModule = (await import('./sip.js')).default;
321
+ console.log("[sip:doLoadWasm] sip.js imported, createSipModule:", typeof createSipModule);
322
+ if (precompiledWasmModule) {
323
+ console.log("[sip:doLoadWasm] Using pre-compiled module with instantiateWasm callback");
324
+ const module2 = await new Promise((resolve, reject) => {
325
+ let resolvedModule = null;
326
+ createSipModule({
327
+ instantiateWasm: (imports, receiveInstance) => {
328
+ console.log("[sip:instantiateWasm] Called, instantiating with pre-compiled module");
329
+ WebAssembly.instantiate(precompiledWasmModule, imports).then((instance) => {
330
+ console.log("[sip:instantiateWasm] Instance created successfully");
331
+ receiveInstance(instance);
332
+ }).catch((err) => {
333
+ console.error("[sip:instantiateWasm] Failed:", err);
334
+ reject(err);
335
+ });
336
+ return {};
337
+ },
338
+ onRuntimeInitialized: () => {
339
+ console.log("[sip:onRuntimeInitialized] Runtime ready, HEAPU8:", resolvedModule?.HEAPU8 ? "exists" : "undefined");
340
+ if (resolvedModule && resolvedModule.HEAPU8) {
341
+ resolve(resolvedModule);
342
+ }
343
+ }
344
+ }).then((mod) => {
345
+ console.log("[sip:doLoadWasm] Module promise resolved, HEAPU8:", mod?.HEAPU8 ? "exists" : "undefined");
346
+ resolvedModule = mod;
347
+ if (mod.HEAPU8) {
348
+ resolve(mod);
349
+ }
350
+ }).catch(reject);
351
+ });
352
+ return module2;
353
+ }
354
+ console.log("[sip:doLoadWasm] Using standard loading");
355
+ const module = await createSipModule();
356
+ console.log("[sip:doLoadWasm] Standard load complete, module.HEAPU8:", module?.HEAPU8 ? "exists" : "undefined");
357
+ return module;
358
+ } catch (err) {
359
+ console.error("[sip:doLoadWasm] Failed:", err);
360
+ throw new Error(
361
+ "SIP WASM module not available. To use streaming processing, build the WASM module with `pnpm build:wasm` in packages/sip. Error: " + (err instanceof Error ? err.message : String(err))
362
+ );
363
+ }
364
+ }
365
+ function copyToWasm(module, data) {
366
+ const ptr = module._malloc(data.length);
367
+ if (!ptr) {
368
+ throw new Error("Failed to allocate WASM memory");
369
+ }
370
+ module.HEAPU8.set(data, ptr);
371
+ return ptr;
372
+ }
373
+ function copyFromWasm(module, ptr, size) {
374
+ return new Uint8Array(module.HEAPU8.buffer, ptr, size).slice();
375
+ }
376
+
377
+ // src/wasm/decoder.ts
378
+ var WasmJpegDecoder = class {
379
+ module;
380
+ decoder = 0;
381
+ dataPtr = 0;
382
+ width = 0;
383
+ height = 0;
384
+ outputWidth = 0;
385
+ outputHeight = 0;
386
+ scaleDenom = 1;
387
+ rowBufferPtr = 0;
388
+ started = false;
389
+ finished = false;
390
+ constructor() {
391
+ this.module = getWasmModule();
392
+ }
393
+ /**
394
+ * Initialize decoder with JPEG data
395
+ */
396
+ init(data) {
397
+ const bytes = data instanceof ArrayBuffer ? new Uint8Array(data) : data;
398
+ this.decoder = this.module._sip_decoder_create();
399
+ if (!this.decoder) {
400
+ throw new Error("Failed to create JPEG decoder");
401
+ }
402
+ this.dataPtr = copyToWasm(this.module, bytes);
403
+ if (this.module._sip_decoder_set_source(this.decoder, this.dataPtr, bytes.length) !== 0) {
404
+ this.dispose();
405
+ throw new Error("Failed to set decoder source");
406
+ }
407
+ if (this.module._sip_decoder_read_header(this.decoder) !== 0) {
408
+ this.dispose();
409
+ throw new Error("Failed to read JPEG header");
410
+ }
411
+ this.width = this.module._sip_decoder_get_width(this.decoder);
412
+ this.height = this.module._sip_decoder_get_height(this.decoder);
413
+ this.outputWidth = this.width;
414
+ this.outputHeight = this.height;
415
+ return { width: this.width, height: this.height };
416
+ }
417
+ /**
418
+ * Get original image dimensions
419
+ */
420
+ getDimensions() {
421
+ return { width: this.width, height: this.height };
422
+ }
423
+ /**
424
+ * Set DCT scale factor for decoding
425
+ *
426
+ * Must be called after init() and before start()
427
+ *
428
+ * @param scaleDenom - Scale denominator: 1, 2, 4, or 8
429
+ * 1 = full size (default)
430
+ * 2 = 1/2 size
431
+ * 4 = 1/4 size
432
+ * 8 = 1/8 size
433
+ */
434
+ setScale(scaleDenom) {
435
+ if (!this.decoder) {
436
+ throw new Error("Decoder not initialized");
437
+ }
438
+ if (this.started) {
439
+ throw new Error("Cannot change scale after decoding started");
440
+ }
441
+ if (this.module._sip_decoder_set_scale(this.decoder, scaleDenom) !== 0) {
442
+ throw new Error(`Invalid scale denominator: ${scaleDenom}`);
443
+ }
444
+ this.scaleDenom = scaleDenom;
445
+ this.outputWidth = this.module._sip_decoder_get_output_width(this.decoder);
446
+ this.outputHeight = this.module._sip_decoder_get_output_height(this.decoder);
447
+ return { width: this.outputWidth, height: this.outputHeight };
448
+ }
449
+ /**
450
+ * Get output dimensions (after any scaling)
451
+ */
452
+ getOutputDimensions() {
453
+ return { width: this.outputWidth, height: this.outputHeight };
454
+ }
455
+ /**
456
+ * Start decoding
457
+ */
458
+ start() {
459
+ if (!this.decoder) {
460
+ throw new Error("Decoder not initialized");
461
+ }
462
+ if (this.started) {
463
+ throw new Error("Decoding already started");
464
+ }
465
+ if (this.module._sip_decoder_start(this.decoder) !== 0) {
466
+ throw new Error("Failed to start decompression");
467
+ }
468
+ this.rowBufferPtr = this.module._sip_decoder_get_row_buffer(this.decoder);
469
+ if (!this.rowBufferPtr) {
470
+ throw new Error("Failed to get row buffer");
471
+ }
472
+ this.started = true;
473
+ }
474
+ /**
475
+ * Read next scanline
476
+ *
477
+ * @returns Scanline object or null if no more scanlines
478
+ */
479
+ readScanline() {
480
+ if (!this.started || this.finished) {
481
+ return null;
482
+ }
483
+ const result = this.module._sip_decoder_read_scanline(this.decoder);
484
+ if (result === 0) {
485
+ this.finished = true;
486
+ return null;
487
+ }
488
+ if (result < 0) {
489
+ throw new Error("Failed to read scanline");
490
+ }
491
+ const y = this.module._sip_decoder_get_scanline(this.decoder) - 1;
492
+ const rowSize = this.outputWidth * 3;
493
+ const data = new Uint8Array(
494
+ this.module.HEAPU8.buffer,
495
+ this.rowBufferPtr,
496
+ rowSize
497
+ ).slice();
498
+ return {
499
+ data,
500
+ width: this.outputWidth,
501
+ y
502
+ };
503
+ }
504
+ /**
505
+ * Read all remaining scanlines
506
+ *
507
+ * @yields Scanline objects
508
+ */
509
+ *readAllScanlines() {
510
+ let scanline;
511
+ while ((scanline = this.readScanline()) !== null) {
512
+ yield scanline;
513
+ }
514
+ }
515
+ /**
516
+ * Decode entire image to RGB buffer
517
+ *
518
+ * @returns Full RGB pixel buffer
519
+ */
520
+ decodeAll() {
521
+ if (!this.started) {
522
+ this.start();
523
+ }
524
+ const pixels = new Uint8Array(this.outputWidth * this.outputHeight * 3);
525
+ const rowSize = this.outputWidth * 3;
526
+ for (const scanline of this.readAllScanlines()) {
527
+ pixels.set(scanline.data, scanline.y * rowSize);
528
+ }
529
+ return {
530
+ pixels,
531
+ width: this.outputWidth,
532
+ height: this.outputHeight
533
+ };
534
+ }
535
+ /**
536
+ * Clean up resources
537
+ */
538
+ dispose() {
539
+ if (this.decoder) {
540
+ this.module._sip_decoder_destroy(this.decoder);
541
+ this.decoder = 0;
542
+ }
543
+ if (this.dataPtr) {
544
+ this.module._free(this.dataPtr);
545
+ this.dataPtr = 0;
546
+ }
547
+ this.started = false;
548
+ this.finished = false;
549
+ this.rowBufferPtr = 0;
550
+ }
551
+ };
552
+ function calculateOptimalScale(srcWidth, srcHeight, targetWidth, targetHeight) {
553
+ const scales = [8, 4, 2, 1];
554
+ for (const scale of scales) {
555
+ const scaledWidth = Math.ceil(srcWidth / scale);
556
+ const scaledHeight = Math.ceil(srcHeight / scale);
557
+ if (scaledWidth >= targetWidth && scaledHeight >= targetHeight) {
558
+ return scale;
559
+ }
560
+ }
561
+ return 1;
562
+ }
563
+
564
+ // src/wasm/encoder.ts
565
+ var WasmJpegEncoder = class {
566
+ module;
567
+ encoder = 0;
568
+ width = 0;
569
+ height = 0;
570
+ quality = 85;
571
+ rowBufferPtr = 0;
572
+ started = false;
573
+ finished = false;
574
+ currentLine = 0;
575
+ constructor() {
576
+ this.module = getWasmModule();
577
+ }
578
+ /**
579
+ * Initialize encoder with output dimensions and quality
580
+ *
581
+ * @param width - Output image width
582
+ * @param height - Output image height
583
+ * @param quality - JPEG quality (1-100, default 85)
584
+ */
585
+ init(width, height, quality = 85) {
586
+ this.width = width;
587
+ this.height = height;
588
+ this.quality = Math.max(1, Math.min(100, quality));
589
+ this.encoder = this.module._sip_encoder_create();
590
+ if (!this.encoder) {
591
+ throw new Error("Failed to create JPEG encoder");
592
+ }
593
+ if (this.module._sip_encoder_init(this.encoder, width, height, this.quality) !== 0) {
594
+ this.dispose();
595
+ throw new Error("Failed to initialize encoder");
596
+ }
597
+ }
598
+ /**
599
+ * Start encoding
600
+ */
601
+ start() {
602
+ if (!this.encoder) {
603
+ throw new Error("Encoder not initialized");
604
+ }
605
+ if (this.started) {
606
+ throw new Error("Encoding already started");
607
+ }
608
+ if (this.module._sip_encoder_start(this.encoder) !== 0) {
609
+ throw new Error("Failed to start compression");
610
+ }
611
+ this.rowBufferPtr = this.module._sip_encoder_get_row_buffer(this.encoder);
612
+ if (!this.rowBufferPtr) {
613
+ throw new Error("Failed to get row buffer");
614
+ }
615
+ this.started = true;
616
+ this.currentLine = 0;
617
+ }
618
+ /**
619
+ * Write a scanline to the encoder
620
+ *
621
+ * @param scanline - Scanline with RGB data
622
+ */
623
+ writeScanline(scanline) {
624
+ this.writeScanlineData(scanline.data);
625
+ }
626
+ /**
627
+ * Write raw RGB data as a scanline
628
+ *
629
+ * @param data - RGB data (width * 3 bytes)
630
+ */
631
+ writeScanlineData(data) {
632
+ if (!this.started || this.finished) {
633
+ throw new Error("Encoder not ready for writing");
634
+ }
635
+ if (this.currentLine >= this.height) {
636
+ throw new Error("All scanlines already written");
637
+ }
638
+ const expectedSize = this.width * 3;
639
+ if (data.length !== expectedSize) {
640
+ throw new Error(`Invalid scanline size: expected ${expectedSize}, got ${data.length}`);
641
+ }
642
+ this.module.HEAPU8.set(data, this.rowBufferPtr);
643
+ if (this.module._sip_encoder_write_scanline(this.encoder) !== 1) {
644
+ throw new Error("Failed to write scanline");
645
+ }
646
+ this.currentLine++;
647
+ }
648
+ /**
649
+ * Get current scanline number
650
+ */
651
+ getCurrentLine() {
652
+ return this.currentLine;
653
+ }
654
+ /**
655
+ * Finish encoding and get output
656
+ *
657
+ * @returns JPEG data as ArrayBuffer
658
+ */
659
+ finish() {
660
+ if (!this.started) {
661
+ throw new Error("Encoding not started");
662
+ }
663
+ if (this.currentLine !== this.height) {
664
+ throw new Error(`Incomplete image: wrote ${this.currentLine}/${this.height} scanlines`);
665
+ }
666
+ if (this.module._sip_encoder_finish(this.encoder) !== 0) {
667
+ throw new Error("Failed to finish encoding");
668
+ }
669
+ this.finished = true;
670
+ const outputPtr = this.module._sip_encoder_get_output(this.encoder);
671
+ const outputSize = this.module._sip_encoder_get_output_size(this.encoder);
672
+ if (!outputPtr || !outputSize) {
673
+ throw new Error("No output data");
674
+ }
675
+ const output = copyFromWasm(this.module, outputPtr, outputSize);
676
+ return output.buffer;
677
+ }
678
+ /**
679
+ * Encode a full RGB buffer to JPEG
680
+ *
681
+ * @param pixels - RGB pixel data (width * height * 3 bytes)
682
+ * @returns JPEG data as ArrayBuffer
683
+ */
684
+ encodeAll(pixels) {
685
+ if (pixels.length !== this.width * this.height * 3) {
686
+ throw new Error(`Invalid pixel data size: expected ${this.width * this.height * 3}, got ${pixels.length}`);
687
+ }
688
+ this.start();
689
+ const rowSize = this.width * 3;
690
+ for (let y = 0; y < this.height; y++) {
691
+ const rowData = pixels.subarray(y * rowSize, (y + 1) * rowSize);
692
+ this.writeScanlineData(rowData);
693
+ }
694
+ return this.finish();
695
+ }
696
+ /**
697
+ * Clean up resources
698
+ */
699
+ dispose() {
700
+ if (this.encoder) {
701
+ this.module._sip_encoder_destroy(this.encoder);
702
+ this.encoder = 0;
703
+ }
704
+ this.started = false;
705
+ this.finished = false;
706
+ this.rowBufferPtr = 0;
707
+ this.currentLine = 0;
708
+ }
709
+ };
710
+
711
+ // src/wasm/png-decoder.ts
712
+ var WasmPngDecoder = class {
713
+ module;
714
+ decoder = 0;
715
+ dataPtr = 0;
716
+ width = 0;
717
+ height = 0;
718
+ hasAlpha = false;
719
+ rowBufferPtr = 0;
720
+ started = false;
721
+ finished = false;
722
+ currentRow = 0;
723
+ constructor() {
724
+ this.module = getWasmModule();
725
+ }
726
+ /**
727
+ * Initialize decoder with PNG data
728
+ */
729
+ init(data) {
730
+ const bytes = data instanceof ArrayBuffer ? new Uint8Array(data) : data;
731
+ this.decoder = this.module._sip_png_decoder_create();
732
+ if (!this.decoder) {
733
+ throw new Error("Failed to create PNG decoder");
734
+ }
735
+ this.dataPtr = copyToWasm(this.module, bytes);
736
+ if (this.module._sip_png_decoder_set_source(this.decoder, this.dataPtr, bytes.length) !== 0) {
737
+ this.dispose();
738
+ throw new Error("Failed to set PNG decoder source");
739
+ }
740
+ if (this.module._sip_png_decoder_read_header(this.decoder) !== 0) {
741
+ this.dispose();
742
+ throw new Error("Failed to read PNG header");
743
+ }
744
+ this.width = this.module._sip_png_decoder_get_width(this.decoder);
745
+ this.height = this.module._sip_png_decoder_get_height(this.decoder);
746
+ this.hasAlpha = this.module._sip_png_decoder_has_alpha(this.decoder) !== 0;
747
+ return { width: this.width, height: this.height, hasAlpha: this.hasAlpha };
748
+ }
749
+ /**
750
+ * Get image dimensions
751
+ */
752
+ getDimensions() {
753
+ return { width: this.width, height: this.height };
754
+ }
755
+ /**
756
+ * Check if image has alpha channel
757
+ */
758
+ getHasAlpha() {
759
+ return this.hasAlpha;
760
+ }
761
+ /**
762
+ * Start decoding
763
+ */
764
+ start() {
765
+ if (!this.decoder) {
766
+ throw new Error("Decoder not initialized");
767
+ }
768
+ if (this.started) {
769
+ throw new Error("Decoding already started");
770
+ }
771
+ if (this.module._sip_png_decoder_start(this.decoder) !== 0) {
772
+ throw new Error("Failed to start PNG decompression");
773
+ }
774
+ this.rowBufferPtr = this.module._sip_png_decoder_get_row_buffer(this.decoder);
775
+ if (!this.rowBufferPtr) {
776
+ throw new Error("Failed to get row buffer");
777
+ }
778
+ this.started = true;
779
+ this.currentRow = 0;
780
+ }
781
+ /**
782
+ * Read next scanline
783
+ *
784
+ * @returns Scanline object or null if no more scanlines
785
+ */
786
+ readScanline() {
787
+ if (!this.started || this.finished) {
788
+ return null;
789
+ }
790
+ if (this.currentRow >= this.height) {
791
+ this.finished = true;
792
+ return null;
793
+ }
794
+ const result = this.module._sip_png_decoder_read_row(this.decoder);
795
+ if (result < 0) {
796
+ throw new Error("Failed to read PNG row");
797
+ }
798
+ const rowSize = this.width * 3;
799
+ const data = new Uint8Array(
800
+ this.module.HEAPU8.buffer,
801
+ this.rowBufferPtr,
802
+ rowSize
803
+ ).slice();
804
+ const y = this.currentRow;
805
+ this.currentRow++;
806
+ if (result === 0 || this.currentRow >= this.height) {
807
+ this.finished = true;
808
+ }
809
+ return {
810
+ data,
811
+ width: this.width,
812
+ y
813
+ };
814
+ }
815
+ /**
816
+ * Read all remaining scanlines
817
+ *
818
+ * @yields Scanline objects
819
+ */
820
+ *readAllScanlines() {
821
+ let scanline;
822
+ while ((scanline = this.readScanline()) !== null) {
823
+ yield scanline;
824
+ }
825
+ }
826
+ /**
827
+ * Decode entire image to RGB buffer
828
+ *
829
+ * @returns Full RGB pixel buffer
830
+ */
831
+ decodeAll() {
832
+ if (!this.started) {
833
+ this.start();
834
+ }
835
+ const pixels = new Uint8Array(this.width * this.height * 3);
836
+ const rowSize = this.width * 3;
837
+ for (const scanline of this.readAllScanlines()) {
838
+ pixels.set(scanline.data, scanline.y * rowSize);
839
+ }
840
+ return {
841
+ pixels,
842
+ width: this.width,
843
+ height: this.height
844
+ };
845
+ }
846
+ /**
847
+ * Clean up resources
848
+ */
849
+ dispose() {
850
+ if (this.decoder) {
851
+ this.module._sip_png_decoder_destroy(this.decoder);
852
+ this.decoder = 0;
853
+ }
854
+ if (this.dataPtr) {
855
+ this.module._free(this.dataPtr);
856
+ this.dataPtr = 0;
857
+ }
858
+ this.started = false;
859
+ this.finished = false;
860
+ this.rowBufferPtr = 0;
861
+ this.currentRow = 0;
862
+ }
863
+ };
864
+
865
+ // src/encoder.ts
866
+ var NativeEncoder = class {
867
+ supportsScanline = true;
868
+ width = 0;
869
+ height = 0;
870
+ quality = 85;
871
+ wasmEncoder = null;
872
+ async init(width, height, quality) {
873
+ this.width = width;
874
+ this.height = height;
875
+ this.quality = quality;
876
+ await loadWasm();
877
+ this.wasmEncoder = new WasmJpegEncoder();
878
+ this.wasmEncoder.init(width, height, quality);
879
+ }
880
+ async encode(pixels) {
881
+ if (!this.wasmEncoder) {
882
+ throw new Error("Encoder not initialized. Call init() first.");
883
+ }
884
+ return this.wasmEncoder.encodeAll(pixels);
885
+ }
886
+ dispose() {
887
+ if (this.wasmEncoder) {
888
+ this.wasmEncoder.dispose();
889
+ this.wasmEncoder = null;
890
+ }
891
+ }
892
+ };
893
+ async function createEncoder(width, height, quality) {
894
+ const encoder = new NativeEncoder();
895
+ await encoder.init(width, height, quality);
896
+ return encoder;
897
+ }
898
+
899
+ // src/resize.ts
900
+ function createResizeState(srcWidth, srcHeight, dstWidth, dstHeight) {
901
+ return {
902
+ srcWidth,
903
+ srcHeight,
904
+ dstWidth,
905
+ dstHeight,
906
+ bufferA: null,
907
+ bufferB: null,
908
+ bufferAY: -1,
909
+ bufferBY: -1,
910
+ currentOutputY: 0
911
+ };
912
+ }
913
+ function resizeRowHorizontal(src, srcWidth, dstWidth) {
914
+ const dst = new Uint8Array(dstWidth * 3);
915
+ const xScale = srcWidth / dstWidth;
916
+ for (let dstX = 0; dstX < dstWidth; dstX++) {
917
+ const srcXFloat = dstX * xScale;
918
+ const srcX0 = Math.floor(srcXFloat);
919
+ const srcX1 = Math.min(srcX0 + 1, srcWidth - 1);
920
+ const t = srcXFloat - srcX0;
921
+ const invT = 1 - t;
922
+ const src0 = srcX0 * 3;
923
+ const src1 = srcX1 * 3;
924
+ const dstOffset = dstX * 3;
925
+ dst[dstOffset] = Math.round(src[src0] * invT + src[src1] * t);
926
+ dst[dstOffset + 1] = Math.round(src[src0 + 1] * invT + src[src1 + 1] * t);
927
+ dst[dstOffset + 2] = Math.round(src[src0 + 2] * invT + src[src1 + 2] * t);
928
+ }
929
+ return dst;
930
+ }
931
+ function blendRows(rowA, rowB, t, width) {
932
+ const result = new Uint8Array(width * 3);
933
+ const invT = 1 - t;
934
+ for (let i = 0; i < width * 3; i++) {
935
+ result[i] = Math.round(rowA[i] * invT + rowB[i] * t);
936
+ }
937
+ return result;
938
+ }
939
+ function processScanline(state, srcScanline, srcY) {
940
+ const { srcWidth, srcHeight, dstWidth, dstHeight } = state;
941
+ const yScale = srcHeight / dstHeight;
942
+ const output = [];
943
+ const resizedRow = resizeRowHorizontal(srcScanline, srcWidth, dstWidth);
944
+ state.bufferA = state.bufferB;
945
+ state.bufferAY = state.bufferBY;
946
+ state.bufferB = resizedRow;
947
+ state.bufferBY = srcY;
948
+ while (state.currentOutputY < dstHeight) {
949
+ const srcYFloat = state.currentOutputY * yScale;
950
+ const srcYFloor = Math.floor(srcYFloat);
951
+ const srcYCeil = Math.min(srcYFloor + 1, srcHeight - 1);
952
+ if (srcYCeil > srcY) {
953
+ break;
954
+ }
955
+ if (state.bufferA === null) {
956
+ output.push({
957
+ data: state.bufferB,
958
+ width: dstWidth,
959
+ y: state.currentOutputY
960
+ });
961
+ state.currentOutputY++;
962
+ continue;
963
+ }
964
+ const t = srcYFloat - srcYFloor;
965
+ let rowA = state.bufferA;
966
+ let rowB = state.bufferB;
967
+ if (srcYFloor === state.bufferBY) {
968
+ rowA = state.bufferB;
969
+ rowB = state.bufferB;
970
+ } else if (srcYCeil === state.bufferAY) {
971
+ rowA = state.bufferA;
972
+ rowB = state.bufferA;
973
+ }
974
+ const blended = blendRows(rowA, rowB, t, dstWidth);
975
+ output.push({
976
+ data: blended,
977
+ width: dstWidth,
978
+ y: state.currentOutputY
979
+ });
980
+ state.currentOutputY++;
981
+ }
982
+ return output;
983
+ }
984
+ function flushResize(state) {
985
+ const output = [];
986
+ while (state.currentOutputY < state.dstHeight) {
987
+ if (state.bufferB === null) break;
988
+ output.push({
989
+ data: state.bufferB,
990
+ width: state.dstWidth,
991
+ y: state.currentOutputY
992
+ });
993
+ state.currentOutputY++;
994
+ }
995
+ return output;
996
+ }
997
+ function calculateTargetDimensions(srcWidth, srcHeight, maxWidth, maxHeight) {
998
+ const scaleX = maxWidth / srcWidth;
999
+ const scaleY = maxHeight / srcHeight;
1000
+ const scale = Math.min(scaleX, scaleY, 1);
1001
+ return {
1002
+ width: Math.round(srcWidth * scale),
1003
+ height: Math.round(srcHeight * scale),
1004
+ scale
1005
+ };
1006
+ }
1007
+ function calculateDctScaleFactor(srcWidth, srcHeight, targetWidth, targetHeight) {
1008
+ const scales = [8, 4, 2, 1];
1009
+ for (const scale of scales) {
1010
+ const scaledWidth = Math.ceil(srcWidth / scale);
1011
+ const scaledHeight = Math.ceil(srcHeight / scale);
1012
+ if (scaledWidth >= targetWidth && scaledHeight >= targetHeight) {
1013
+ return scale;
1014
+ }
1015
+ }
1016
+ return 1;
1017
+ }
1018
+
1019
+ // src/streaming.ts
1020
+ var DEFAULT_OPTIONS = {
1021
+ maxWidth: 4096,
1022
+ maxHeight: 4096,
1023
+ maxBytes: 1.5 * 1024 * 1024,
1024
+ quality: 85
1025
+ };
1026
+ async function processJpegStreaming(input, options = {}) {
1027
+ const opts = { ...DEFAULT_OPTIONS, ...options };
1028
+ await loadWasm();
1029
+ const decoder = new WasmJpegDecoder();
1030
+ try {
1031
+ const { width: srcWidth, height: srcHeight } = decoder.init(input);
1032
+ const target = calculateTargetDimensions(
1033
+ srcWidth,
1034
+ srcHeight,
1035
+ opts.maxWidth,
1036
+ opts.maxHeight
1037
+ );
1038
+ const dctScale = calculateOptimalScale(
1039
+ srcWidth,
1040
+ srcHeight,
1041
+ target.width,
1042
+ target.height
1043
+ );
1044
+ const { width: decodeWidth, height: decodeHeight } = decoder.setScale(dctScale);
1045
+ const resizeState = createResizeState(
1046
+ decodeWidth,
1047
+ decodeHeight,
1048
+ target.width,
1049
+ target.height
1050
+ );
1051
+ const encoder = new WasmJpegEncoder();
1052
+ encoder.init(target.width, target.height, opts.quality);
1053
+ encoder.start();
1054
+ decoder.start();
1055
+ let decodedLine = 0;
1056
+ for (const scanline of decoder.readAllScanlines()) {
1057
+ const outputScanlines = processScanline(resizeState, scanline.data, decodedLine);
1058
+ decodedLine++;
1059
+ for (const outScanline of outputScanlines) {
1060
+ encoder.writeScanline(outScanline);
1061
+ }
1062
+ }
1063
+ const remaining = flushResize(resizeState);
1064
+ for (const outScanline of remaining) {
1065
+ encoder.writeScanline(outScanline);
1066
+ }
1067
+ const jpegData = encoder.finish();
1068
+ if (jpegData.byteLength > opts.maxBytes && opts.quality > 45) {
1069
+ encoder.dispose();
1070
+ decoder.dispose();
1071
+ return processJpegStreaming(input, {
1072
+ ...opts,
1073
+ quality: opts.quality - 10
1074
+ });
1075
+ }
1076
+ encoder.dispose();
1077
+ return {
1078
+ data: jpegData,
1079
+ width: target.width,
1080
+ height: target.height,
1081
+ mimeType: "image/jpeg",
1082
+ originalFormat: "jpeg"
1083
+ };
1084
+ } finally {
1085
+ decoder.dispose();
1086
+ }
1087
+ }
1088
+ async function processPngStreaming(input, options = {}) {
1089
+ const opts = { ...DEFAULT_OPTIONS, ...options };
1090
+ await loadWasm();
1091
+ const decoder = new WasmPngDecoder();
1092
+ try {
1093
+ const { width: srcWidth, height: srcHeight } = decoder.init(input);
1094
+ const target = calculateTargetDimensions(
1095
+ srcWidth,
1096
+ srcHeight,
1097
+ opts.maxWidth,
1098
+ opts.maxHeight
1099
+ );
1100
+ const resizeState = createResizeState(
1101
+ srcWidth,
1102
+ srcHeight,
1103
+ target.width,
1104
+ target.height
1105
+ );
1106
+ const encoder = new WasmJpegEncoder();
1107
+ encoder.init(target.width, target.height, opts.quality);
1108
+ encoder.start();
1109
+ decoder.start();
1110
+ let decodedLine = 0;
1111
+ for (const scanline of decoder.readAllScanlines()) {
1112
+ const outputScanlines = processScanline(resizeState, scanline.data, decodedLine);
1113
+ decodedLine++;
1114
+ for (const outScanline of outputScanlines) {
1115
+ encoder.writeScanline(outScanline);
1116
+ }
1117
+ }
1118
+ const remaining = flushResize(resizeState);
1119
+ for (const outScanline of remaining) {
1120
+ encoder.writeScanline(outScanline);
1121
+ }
1122
+ const jpegData = encoder.finish();
1123
+ if (jpegData.byteLength > opts.maxBytes && opts.quality > 45) {
1124
+ encoder.dispose();
1125
+ decoder.dispose();
1126
+ return processPngStreaming(input, {
1127
+ ...opts,
1128
+ quality: opts.quality - 10
1129
+ });
1130
+ }
1131
+ encoder.dispose();
1132
+ return {
1133
+ data: jpegData,
1134
+ width: target.width,
1135
+ height: target.height,
1136
+ mimeType: "image/jpeg",
1137
+ originalFormat: "png"
1138
+ };
1139
+ } finally {
1140
+ decoder.dispose();
1141
+ }
1142
+ }
1143
+ function isStreamingAvailable() {
1144
+ return isWasmAvailable();
1145
+ }
1146
+ async function initStreaming() {
1147
+ try {
1148
+ await loadWasm();
1149
+ return true;
1150
+ } catch {
1151
+ return false;
1152
+ }
1153
+ }
1154
+
1155
+ // src/pipeline.ts
1156
+ var DEFAULT_OPTIONS2 = {
1157
+ maxWidth: 4096,
1158
+ maxHeight: 4096,
1159
+ maxBytes: 1.5 * 1024 * 1024,
1160
+ // 1.5MB
1161
+ quality: 85
1162
+ };
1163
+ async function process2(input, options = {}) {
1164
+ const opts = { ...DEFAULT_OPTIONS2, ...options };
1165
+ const probeResult = probe(input);
1166
+ if (probeResult.format === "unknown") {
1167
+ throw new Error("Unknown image format");
1168
+ }
1169
+ const { format, width: srcWidth, height: srcHeight } = probeResult;
1170
+ if (format === "jpeg") {
1171
+ return await processJpegStreaming(input, opts);
1172
+ }
1173
+ if (format === "png") {
1174
+ return await processPngStreaming(input, opts);
1175
+ }
1176
+ await loadWasm();
1177
+ const target = calculateTargetDimensions(
1178
+ srcWidth,
1179
+ srcHeight,
1180
+ opts.maxWidth,
1181
+ opts.maxHeight
1182
+ );
1183
+ const decoder = await createDecoder(format, input);
1184
+ const { pixels: srcPixels, width: decodedWidth, height: decodedHeight } = await decoder.decode();
1185
+ decoder.dispose();
1186
+ const resizedPixels = resizePixelBuffer(
1187
+ srcPixels,
1188
+ decodedWidth,
1189
+ decodedHeight,
1190
+ target.width,
1191
+ target.height
1192
+ );
1193
+ let quality = opts.quality;
1194
+ let jpegData = await encodeToJpeg(resizedPixels, target.width, target.height, quality);
1195
+ while (jpegData.byteLength > opts.maxBytes && quality > 45) {
1196
+ quality -= 10;
1197
+ jpegData = await encodeToJpeg(resizedPixels, target.width, target.height, quality);
1198
+ }
1199
+ if (jpegData.byteLength > opts.maxBytes) {
1200
+ const scaleFactor = Math.sqrt(opts.maxBytes / jpegData.byteLength) * 0.9;
1201
+ const newWidth = Math.round(target.width * scaleFactor);
1202
+ const newHeight = Math.round(target.height * scaleFactor);
1203
+ const smallerPixels = resizePixelBuffer(
1204
+ resizedPixels,
1205
+ target.width,
1206
+ target.height,
1207
+ newWidth,
1208
+ newHeight
1209
+ );
1210
+ jpegData = await encodeToJpeg(smallerPixels, newWidth, newHeight, quality);
1211
+ return {
1212
+ data: jpegData,
1213
+ width: newWidth,
1214
+ height: newHeight,
1215
+ mimeType: "image/jpeg",
1216
+ originalFormat: format
1217
+ };
1218
+ }
1219
+ return {
1220
+ data: jpegData,
1221
+ width: target.width,
1222
+ height: target.height,
1223
+ mimeType: "image/jpeg",
1224
+ originalFormat: format
1225
+ };
1226
+ }
1227
+ function resizePixelBuffer(srcPixels, srcWidth, srcHeight, dstWidth, dstHeight) {
1228
+ if (srcWidth === dstWidth && srcHeight === dstHeight) {
1229
+ return srcPixels;
1230
+ }
1231
+ const state = createResizeState(srcWidth, srcHeight, dstWidth, dstHeight);
1232
+ const outputRows = new Array(dstHeight);
1233
+ const srcRowSize = srcWidth * 3;
1234
+ for (let y = 0; y < srcHeight; y++) {
1235
+ const srcRow = srcPixels.subarray(y * srcRowSize, (y + 1) * srcRowSize);
1236
+ const outputScanlines = processScanline(state, srcRow, y);
1237
+ for (const scanline of outputScanlines) {
1238
+ outputRows[scanline.y] = scanline.data;
1239
+ }
1240
+ }
1241
+ const remaining = flushResize(state);
1242
+ for (const scanline of remaining) {
1243
+ outputRows[scanline.y] = scanline.data;
1244
+ }
1245
+ const dstRowSize = dstWidth * 3;
1246
+ const result = new Uint8Array(dstWidth * dstHeight * 3);
1247
+ for (let y = 0; y < dstHeight; y++) {
1248
+ if (outputRows[y]) {
1249
+ result.set(outputRows[y], y * dstRowSize);
1250
+ }
1251
+ }
1252
+ return result;
1253
+ }
1254
+ async function encodeToJpeg(pixels, width, height, quality) {
1255
+ const encoder = await createEncoder(width, height, quality);
1256
+ const result = await encoder.encode(pixels);
1257
+ encoder.dispose();
1258
+ return result;
1259
+ }
1260
+
1261
+ // src/index.ts
1262
+ var sip = {
1263
+ process: process2,
1264
+ probe,
1265
+ detectImageFormat,
1266
+ initStreaming,
1267
+ isStreamingAvailable
1268
+ };
1269
+
1270
+ export { WasmJpegDecoder, WasmJpegEncoder, WasmPngDecoder, calculateDctScaleFactor, calculateOptimalScale, calculateTargetDimensions, createResizeState, detectImageFormat, flushResize, getWasmModule, initStreaming, initWithWasmModule, isStreamingAvailable, isWasmAvailable, loadWasm, probe, process2 as process, processJpegStreaming, processScanline, sip };
1271
+ //# sourceMappingURL=index.js.map
1272
+ //# sourceMappingURL=index.js.map