@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.
@@ -0,0 +1,615 @@
1
+ /**
2
+ * Supported input image formats
3
+ */
4
+ type ImageFormat = 'jpeg' | 'png' | 'webp' | 'avif' | 'unknown';
5
+ /**
6
+ * Result from probing an image's format and dimensions
7
+ */
8
+ interface ProbeResult {
9
+ /** Detected format */
10
+ format: ImageFormat;
11
+ /** Image width in pixels */
12
+ width: number;
13
+ /** Image height in pixels */
14
+ height: number;
15
+ /** Whether the image has an alpha channel */
16
+ hasAlpha: boolean;
17
+ }
18
+ /**
19
+ * Options for image processing
20
+ */
21
+ interface ProcessOptions {
22
+ /** Maximum output width */
23
+ maxWidth?: number;
24
+ /** Maximum output height */
25
+ maxHeight?: number;
26
+ /** Target output size in bytes (quality will be reduced to achieve this) */
27
+ maxBytes?: number;
28
+ /** JPEG quality (1-100, default: 85) */
29
+ quality?: number;
30
+ }
31
+ /**
32
+ * Result from processing an image
33
+ */
34
+ interface ProcessResult {
35
+ /** Processed image data */
36
+ data: ArrayBuffer;
37
+ /** Output width */
38
+ width: number;
39
+ /** Output height */
40
+ height: number;
41
+ /** Output MIME type (always image/jpeg) */
42
+ mimeType: 'image/jpeg';
43
+ /** Original format that was converted */
44
+ originalFormat: ImageFormat;
45
+ }
46
+ /**
47
+ * Internal: A single scanline of RGB pixel data
48
+ */
49
+ interface Scanline {
50
+ /** RGB pixel data (width * 3 bytes) */
51
+ data: Uint8Array;
52
+ /** Width in pixels */
53
+ width: number;
54
+ /** Y position in the image (0-indexed) */
55
+ y: number;
56
+ }
57
+ /**
58
+ * Internal: Decoder state for streaming decode
59
+ */
60
+ interface DecoderState {
61
+ /** Original image width */
62
+ width: number;
63
+ /** Original image height */
64
+ height: number;
65
+ /** Current scanline index */
66
+ currentLine: number;
67
+ /** Scale factor (1, 2, 4, or 8 for JPEG DCT scaling) */
68
+ scaleFactor: number;
69
+ /** Scaled width after DCT scaling */
70
+ scaledWidth: number;
71
+ /** Scaled height after DCT scaling */
72
+ scaledHeight: number;
73
+ }
74
+ /**
75
+ * Internal: Encoder state for streaming encode
76
+ */
77
+ interface EncoderState {
78
+ /** Output width */
79
+ width: number;
80
+ /** Output height */
81
+ height: number;
82
+ /** JPEG quality (1-100) */
83
+ quality: number;
84
+ /** Current scanline being encoded */
85
+ currentLine: number;
86
+ /** Accumulated output chunks */
87
+ chunks: Uint8Array[];
88
+ }
89
+ /**
90
+ * Internal: Resize state for scanline-based bilinear interpolation
91
+ */
92
+ interface ResizeState {
93
+ /** Source width */
94
+ srcWidth: number;
95
+ /** Source height */
96
+ srcHeight: number;
97
+ /** Target width */
98
+ dstWidth: number;
99
+ /** Target height */
100
+ dstHeight: number;
101
+ /** Buffer A (previous source row, already scaled horizontally) */
102
+ bufferA: Uint8Array | null;
103
+ /** Buffer B (current source row, already scaled horizontally) */
104
+ bufferB: Uint8Array | null;
105
+ /** Source Y index for buffer A */
106
+ bufferAY: number;
107
+ /** Source Y index for buffer B */
108
+ bufferBY: number;
109
+ /** Current output Y position */
110
+ currentOutputY: number;
111
+ }
112
+
113
+ /**
114
+ * Probe an image to get format and dimensions
115
+ * Only reads the header bytes - very memory efficient
116
+ *
117
+ * @param input - Image data as ArrayBuffer or Uint8Array
118
+ * @returns ProbeResult with format, dimensions, and alpha info
119
+ */
120
+ declare function probe(input: ArrayBuffer | Uint8Array): ProbeResult;
121
+ /**
122
+ * Detect just the format (faster if you don't need dimensions)
123
+ */
124
+ declare function detectImageFormat(input: ArrayBuffer | Uint8Array): ImageFormat;
125
+
126
+ /**
127
+ * Process an image: decode, resize, and encode to JPEG
128
+ *
129
+ * For JPEG images, uses ultra-memory-efficient streaming pipeline when WASM
130
+ * is available (DCT scaling + scanline processing). Falls back to full-memory
131
+ * decode for other formats or when WASM is not built.
132
+ *
133
+ * @param input - Image data as ArrayBuffer
134
+ * @param options - Processing options
135
+ * @returns Processed image result
136
+ */
137
+ declare function process(input: ArrayBuffer, options?: ProcessOptions): Promise<ProcessResult>;
138
+
139
+ /**
140
+ * Create a resize state for scanline-based bilinear interpolation
141
+ *
142
+ * This implements memory-efficient resizing that only needs 2 source rows
143
+ * in memory at any time, regardless of image size.
144
+ */
145
+ declare function createResizeState(srcWidth: number, srcHeight: number, dstWidth: number, dstHeight: number): ResizeState;
146
+ /**
147
+ * Process a source scanline and potentially output resized scanlines
148
+ *
149
+ * This is the core of the streaming resize algorithm. Call this for each
150
+ * source scanline in order (y = 0, 1, 2, ...). It will return output
151
+ * scanlines as they become available.
152
+ *
153
+ * Memory usage: Only keeps 2 horizontally-resized rows in memory at a time
154
+ *
155
+ * @param state - Resize state (mutated)
156
+ * @param srcScanline - Source scanline (RGB, 3 bytes per pixel)
157
+ * @param srcY - Source Y position (must be called in order)
158
+ * @returns Array of output scanlines (may be 0, 1, or more)
159
+ */
160
+ declare function processScanline(state: ResizeState, srcScanline: Uint8Array, srcY: number): Scanline[];
161
+ /**
162
+ * Flush any remaining output rows after all source rows have been processed
163
+ *
164
+ * @param state - Resize state
165
+ * @returns Remaining output scanlines
166
+ */
167
+ declare function flushResize(state: ResizeState): Scanline[];
168
+ /**
169
+ * Calculate target dimensions while preserving aspect ratio
170
+ *
171
+ * @param srcWidth - Source width
172
+ * @param srcHeight - Source height
173
+ * @param maxWidth - Maximum target width
174
+ * @param maxHeight - Maximum target height
175
+ * @returns Target dimensions
176
+ */
177
+ declare function calculateTargetDimensions(srcWidth: number, srcHeight: number, maxWidth: number, maxHeight: number): {
178
+ width: number;
179
+ height: number;
180
+ scale: number;
181
+ };
182
+ /**
183
+ * Calculate optimal JPEG DCT scale factor
184
+ *
185
+ * JPEG can decode at 1/1, 1/2, 1/4, or 1/8 scale using DCT scaling.
186
+ * This dramatically reduces memory usage during decode.
187
+ *
188
+ * @param srcWidth - Source image width
189
+ * @param srcHeight - Source image height
190
+ * @param targetWidth - Desired output width
191
+ * @param targetHeight - Desired output height
192
+ * @returns Scale denominator (1, 2, 4, or 8)
193
+ */
194
+ declare function calculateDctScaleFactor(srcWidth: number, srcHeight: number, targetWidth: number, targetHeight: number): 1 | 2 | 4 | 8;
195
+
196
+ /**
197
+ * Streaming Image Processing Pipeline
198
+ *
199
+ * Ultra memory-efficient processing that:
200
+ * 1. Decodes JPEG at reduced scale using DCT scaling
201
+ * 2. Resizes using scanline-based bilinear interpolation (2 rows in memory)
202
+ * 3. Encodes to JPEG scanline-by-scanline
203
+ *
204
+ * Peak memory usage is ~50KB regardless of input image size.
205
+ */
206
+
207
+ /**
208
+ * Process a JPEG image using streaming pipeline
209
+ *
210
+ * This is the ultra-memory-efficient path that:
211
+ * - Uses DCT scaling to decode at reduced resolution
212
+ * - Processes one scanline at a time
213
+ * - Never holds the full image in memory
214
+ *
215
+ * @param input - JPEG image data
216
+ * @param options - Processing options
217
+ * @returns Processed JPEG result
218
+ */
219
+ declare function processJpegStreaming(input: ArrayBuffer, options?: ProcessOptions): Promise<ProcessResult>;
220
+ /**
221
+ * Check if streaming processing is available
222
+ *
223
+ * Returns false if WASM module is not built/loaded.
224
+ */
225
+ declare function isStreamingAvailable(): boolean;
226
+ /**
227
+ * Try to load WASM for streaming processing
228
+ *
229
+ * Call this early to warm up the WASM module.
230
+ */
231
+ declare function initStreaming(): Promise<boolean>;
232
+
233
+ /**
234
+ * TypeScript types for SIP WASM module
235
+ */
236
+ /**
237
+ * Emscripten module interface
238
+ */
239
+ interface SipWasmModule {
240
+ HEAPU8: Uint8Array;
241
+ _malloc(size: number): number;
242
+ _free(ptr: number): void;
243
+ _sip_decoder_create(): number;
244
+ _sip_decoder_set_source(dec: number, data: number, size: number): number;
245
+ _sip_decoder_read_header(dec: number): number;
246
+ _sip_decoder_get_width(dec: number): number;
247
+ _sip_decoder_get_height(dec: number): number;
248
+ _sip_decoder_set_scale(dec: number, scale_denom: number): number;
249
+ _sip_decoder_get_output_width(dec: number): number;
250
+ _sip_decoder_get_output_height(dec: number): number;
251
+ _sip_decoder_start(dec: number): number;
252
+ _sip_decoder_get_row_buffer(dec: number): number;
253
+ _sip_decoder_read_scanline(dec: number): number;
254
+ _sip_decoder_get_scanline(dec: number): number;
255
+ _sip_decoder_finish(dec: number): number;
256
+ _sip_decoder_destroy(dec: number): void;
257
+ _sip_encoder_create(): number;
258
+ _sip_encoder_init(enc: number, width: number, height: number, quality: number): number;
259
+ _sip_encoder_start(enc: number): number;
260
+ _sip_encoder_get_row_buffer(enc: number): number;
261
+ _sip_encoder_write_scanline(enc: number): number;
262
+ _sip_encoder_write_scanline_from(enc: number, data: number): number;
263
+ _sip_encoder_get_scanline(enc: number): number;
264
+ _sip_encoder_finish(enc: number): number;
265
+ _sip_encoder_get_output(enc: number): number;
266
+ _sip_encoder_get_output_size(enc: number): number;
267
+ _sip_encoder_destroy(enc: number): void;
268
+ _sip_png_decoder_create(): number;
269
+ _sip_png_decoder_set_source(dec: number, data: number, size: number): number;
270
+ _sip_png_decoder_read_header(dec: number): number;
271
+ _sip_png_decoder_get_width(dec: number): number;
272
+ _sip_png_decoder_get_height(dec: number): number;
273
+ _sip_png_decoder_has_alpha(dec: number): number;
274
+ _sip_png_decoder_start(dec: number): number;
275
+ _sip_png_decoder_get_row_buffer(dec: number): number;
276
+ _sip_png_decoder_read_row(dec: number): number;
277
+ _sip_png_decoder_get_row(dec: number): number;
278
+ _sip_png_decoder_finish(dec: number): number;
279
+ _sip_png_decoder_destroy(dec: number): void;
280
+ _sip_get_error(): number;
281
+ _sip_malloc(size: number): number;
282
+ _sip_free(ptr: number): void;
283
+ UTF8ToString(ptr: number): string;
284
+ }
285
+ /**
286
+ * Valid DCT scale denominators
287
+ */
288
+ type DctScaleDenom = 1 | 2 | 4 | 8;
289
+
290
+ /**
291
+ * WASM Module Loader
292
+ *
293
+ * Loads the SIP WASM module with proper initialization.
294
+ * Works in both browser and Cloudflare Workers environments.
295
+ *
296
+ * For Cloudflare Workers, use initWithWasmModule() in the Durable Object
297
+ * constructor, passing the statically imported WASM module.
298
+ */
299
+
300
+ /**
301
+ * Check if WASM module is available
302
+ */
303
+ declare function isWasmAvailable(): boolean;
304
+ /**
305
+ * Initialize with a pre-compiled WebAssembly.Module
306
+ *
307
+ * For Cloudflare Workers, import the WASM file statically and pass it here.
308
+ * This allows workerd to pre-compile the WASM at bundle time.
309
+ *
310
+ * @example
311
+ * ```typescript
312
+ * import sipWasm from '@standardagents/sip/dist/sip.wasm';
313
+ * import { initWithWasmModule } from '@standardagents/sip';
314
+ *
315
+ * // At module top level or in DO constructor
316
+ * await initWithWasmModule(sipWasm);
317
+ * ```
318
+ */
319
+ declare function initWithWasmModule(compiledModule?: WebAssembly.Module): Promise<void>;
320
+ /**
321
+ * Get the WASM module, throwing if not loaded
322
+ */
323
+ declare function getWasmModule(): SipWasmModule;
324
+ /**
325
+ * Load the WASM module
326
+ *
327
+ * This function is idempotent - calling it multiple times returns the same module.
328
+ */
329
+ declare function loadWasm(): Promise<SipWasmModule>;
330
+
331
+ /**
332
+ * WASM JPEG Decoder with Scaled DCT Support
333
+ *
334
+ * Memory-efficient JPEG decoding using libjpeg-turbo's scaled DCT feature.
335
+ * Decodes at 1/2, 1/4, or 1/8 scale directly during decompression.
336
+ */
337
+
338
+ /**
339
+ * WASM-based JPEG decoder with scaled DCT support
340
+ */
341
+ declare class WasmJpegDecoder {
342
+ private module;
343
+ private decoder;
344
+ private dataPtr;
345
+ private width;
346
+ private height;
347
+ private outputWidth;
348
+ private outputHeight;
349
+ private scaleDenom;
350
+ private rowBufferPtr;
351
+ private started;
352
+ private finished;
353
+ constructor();
354
+ /**
355
+ * Initialize decoder with JPEG data
356
+ */
357
+ init(data: ArrayBuffer | Uint8Array): {
358
+ width: number;
359
+ height: number;
360
+ };
361
+ /**
362
+ * Get original image dimensions
363
+ */
364
+ getDimensions(): {
365
+ width: number;
366
+ height: number;
367
+ };
368
+ /**
369
+ * Set DCT scale factor for decoding
370
+ *
371
+ * Must be called after init() and before start()
372
+ *
373
+ * @param scaleDenom - Scale denominator: 1, 2, 4, or 8
374
+ * 1 = full size (default)
375
+ * 2 = 1/2 size
376
+ * 4 = 1/4 size
377
+ * 8 = 1/8 size
378
+ */
379
+ setScale(scaleDenom: DctScaleDenom): {
380
+ width: number;
381
+ height: number;
382
+ };
383
+ /**
384
+ * Get output dimensions (after any scaling)
385
+ */
386
+ getOutputDimensions(): {
387
+ width: number;
388
+ height: number;
389
+ };
390
+ /**
391
+ * Start decoding
392
+ */
393
+ start(): void;
394
+ /**
395
+ * Read next scanline
396
+ *
397
+ * @returns Scanline object or null if no more scanlines
398
+ */
399
+ readScanline(): Scanline | null;
400
+ /**
401
+ * Read all remaining scanlines
402
+ *
403
+ * @yields Scanline objects
404
+ */
405
+ readAllScanlines(): Generator<Scanline>;
406
+ /**
407
+ * Decode entire image to RGB buffer
408
+ *
409
+ * @returns Full RGB pixel buffer
410
+ */
411
+ decodeAll(): {
412
+ pixels: Uint8Array;
413
+ width: number;
414
+ height: number;
415
+ };
416
+ /**
417
+ * Clean up resources
418
+ */
419
+ dispose(): void;
420
+ }
421
+ /**
422
+ * Calculate optimal DCT scale factor for a target size
423
+ *
424
+ * Returns the largest scale factor that keeps the output >= target size.
425
+ *
426
+ * @param srcWidth - Original image width
427
+ * @param srcHeight - Original image height
428
+ * @param targetWidth - Desired output width
429
+ * @param targetHeight - Desired output height
430
+ */
431
+ declare function calculateOptimalScale(srcWidth: number, srcHeight: number, targetWidth: number, targetHeight: number): DctScaleDenom;
432
+
433
+ /**
434
+ * WASM JPEG Encoder with Scanline Streaming
435
+ *
436
+ * Memory-efficient JPEG encoding that processes one scanline at a time.
437
+ */
438
+
439
+ /**
440
+ * WASM-based JPEG encoder with scanline streaming
441
+ */
442
+ declare class WasmJpegEncoder {
443
+ private module;
444
+ private encoder;
445
+ private width;
446
+ private height;
447
+ private quality;
448
+ private rowBufferPtr;
449
+ private started;
450
+ private finished;
451
+ private currentLine;
452
+ constructor();
453
+ /**
454
+ * Initialize encoder with output dimensions and quality
455
+ *
456
+ * @param width - Output image width
457
+ * @param height - Output image height
458
+ * @param quality - JPEG quality (1-100, default 85)
459
+ */
460
+ init(width: number, height: number, quality?: number): void;
461
+ /**
462
+ * Start encoding
463
+ */
464
+ start(): void;
465
+ /**
466
+ * Write a scanline to the encoder
467
+ *
468
+ * @param scanline - Scanline with RGB data
469
+ */
470
+ writeScanline(scanline: Scanline): void;
471
+ /**
472
+ * Write raw RGB data as a scanline
473
+ *
474
+ * @param data - RGB data (width * 3 bytes)
475
+ */
476
+ writeScanlineData(data: Uint8Array): void;
477
+ /**
478
+ * Get current scanline number
479
+ */
480
+ getCurrentLine(): number;
481
+ /**
482
+ * Finish encoding and get output
483
+ *
484
+ * @returns JPEG data as ArrayBuffer
485
+ */
486
+ finish(): ArrayBuffer;
487
+ /**
488
+ * Encode a full RGB buffer to JPEG
489
+ *
490
+ * @param pixels - RGB pixel data (width * height * 3 bytes)
491
+ * @returns JPEG data as ArrayBuffer
492
+ */
493
+ encodeAll(pixels: Uint8Array): ArrayBuffer;
494
+ /**
495
+ * Clean up resources
496
+ */
497
+ dispose(): void;
498
+ }
499
+
500
+ /**
501
+ * WASM PNG Decoder with Row-by-Row Processing
502
+ *
503
+ * Memory-efficient PNG decoding using libspng's progressive API.
504
+ * Decodes one row at a time to minimize memory usage.
505
+ */
506
+
507
+ /**
508
+ * WASM-based PNG decoder with row-by-row decoding
509
+ */
510
+ declare class WasmPngDecoder {
511
+ private module;
512
+ private decoder;
513
+ private dataPtr;
514
+ private width;
515
+ private height;
516
+ private hasAlpha;
517
+ private rowBufferPtr;
518
+ private started;
519
+ private finished;
520
+ private currentRow;
521
+ constructor();
522
+ /**
523
+ * Initialize decoder with PNG data
524
+ */
525
+ init(data: ArrayBuffer | Uint8Array): {
526
+ width: number;
527
+ height: number;
528
+ hasAlpha: boolean;
529
+ };
530
+ /**
531
+ * Get image dimensions
532
+ */
533
+ getDimensions(): {
534
+ width: number;
535
+ height: number;
536
+ };
537
+ /**
538
+ * Check if image has alpha channel
539
+ */
540
+ getHasAlpha(): boolean;
541
+ /**
542
+ * Start decoding
543
+ */
544
+ start(): void;
545
+ /**
546
+ * Read next scanline
547
+ *
548
+ * @returns Scanline object or null if no more scanlines
549
+ */
550
+ readScanline(): Scanline | null;
551
+ /**
552
+ * Read all remaining scanlines
553
+ *
554
+ * @yields Scanline objects
555
+ */
556
+ readAllScanlines(): Generator<Scanline>;
557
+ /**
558
+ * Decode entire image to RGB buffer
559
+ *
560
+ * @returns Full RGB pixel buffer
561
+ */
562
+ decodeAll(): {
563
+ pixels: Uint8Array;
564
+ width: number;
565
+ height: number;
566
+ };
567
+ /**
568
+ * Clean up resources
569
+ */
570
+ dispose(): void;
571
+ }
572
+
573
+ /**
574
+ * @standardagents/sip - Small Image Processor
575
+ *
576
+ * Ultra memory-efficient image processing for Cloudflare Workers.
577
+ *
578
+ * Features:
579
+ * - Format detection without full decode (probe)
580
+ * - Scanline-based bilinear resize (constant memory)
581
+ * - JPEG output with quality control
582
+ * - Support for JPEG, PNG, WebP, AVIF input formats
583
+ *
584
+ * @example
585
+ * ```typescript
586
+ * import { sip } from '@standardagents/sip';
587
+ *
588
+ * // Process an image
589
+ * const result = await sip.process(imageBuffer, {
590
+ * maxWidth: 2048,
591
+ * maxHeight: 2048,
592
+ * maxBytes: 1.5 * 1024 * 1024,
593
+ * quality: 85,
594
+ * });
595
+ *
596
+ * // result.data: ArrayBuffer (JPEG)
597
+ * // result.width, result.height: output dimensions
598
+ * // result.mimeType: 'image/jpeg'
599
+ *
600
+ * // Just probe for info
601
+ * const info = sip.probe(imageBuffer);
602
+ * // info.format: 'jpeg' | 'png' | 'webp' | 'avif'
603
+ * // info.width, info.height: original dimensions
604
+ * ```
605
+ */
606
+
607
+ declare const sip: {
608
+ process: typeof process;
609
+ probe: typeof probe;
610
+ detectImageFormat: typeof detectImageFormat;
611
+ initStreaming: typeof initStreaming;
612
+ isStreamingAvailable: typeof isStreamingAvailable;
613
+ };
614
+
615
+ export { type DctScaleDenom, type DecoderState, type EncoderState, type ImageFormat, type ProbeResult, type ProcessOptions, type ProcessResult, type ResizeState, type Scanline, type SipWasmModule, WasmJpegDecoder, WasmJpegEncoder, WasmPngDecoder, calculateDctScaleFactor, calculateOptimalScale, calculateTargetDimensions, createResizeState, detectImageFormat, flushResize, getWasmModule, initStreaming, initWithWasmModule, isStreamingAvailable, isWasmAvailable, loadWasm, probe, process, processJpegStreaming, processScanline, sip };