@standardagents/sip 0.13.0 → 1.0.0

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.d.ts CHANGED
@@ -3,45 +3,61 @@
3
3
  */
4
4
  type ImageFormat = 'jpeg' | 'png' | 'webp' | 'avif' | 'unknown';
5
5
  /**
6
- * Result from probing an image's format and dimensions
6
+ * Image metadata discovered during inspection
7
7
  */
8
- interface ProbeResult {
9
- /** Detected format */
8
+ interface ImageInfo {
10
9
  format: ImageFormat;
11
- /** Image width in pixels */
12
10
  width: number;
13
- /** Image height in pixels */
14
11
  height: number;
15
- /** Whether the image has an alpha channel */
16
12
  hasAlpha: boolean;
17
13
  }
18
14
  /**
19
- * Options for image processing
15
+ * Backward-compatible alias for callers that still import ProbeResult internally.
20
16
  */
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) */
17
+ type ProbeResult = ImageInfo;
18
+ /**
19
+ * Byte-oriented inputs accepted by the new API.
20
+ */
21
+ type ByteInput = ArrayBuffer | Uint8Array | Blob | Request | Response | ReadableStream<Uint8Array> | AsyncIterable<Uint8Array>;
22
+ interface TransformOptions {
23
+ width?: number;
24
+ height?: number;
29
25
  quality?: number;
30
26
  }
31
27
  /**
32
- * Result from processing an image
28
+ * Internal/publicly returned reusable source after inspect().
29
+ * `open()` may only be called once for streamed inputs.
33
30
  */
34
- interface ProcessResult {
35
- /** Processed image data */
36
- data: ArrayBuffer;
37
- /** Output width */
31
+ interface InputSource {
32
+ readonly kind: 'bytes' | 'stream';
33
+ readonly replayable: boolean;
34
+ readonly formatHint?: ImageFormat;
35
+ readonly byteLength?: number;
36
+ readonly headerBytes: Uint8Array<ArrayBufferLike>;
37
+ open(): AsyncIterable<Uint8Array>;
38
+ }
39
+ interface TransformStats {
40
+ peakPipelineBytes: number;
41
+ peakCodecBytes: number;
42
+ peakBufferedInputBytes: number;
43
+ peakBufferedOutputBytes: number;
44
+ bytesIn: number;
45
+ bytesOut: number;
46
+ notes: string[];
47
+ }
48
+ interface EncodedImageInfo {
38
49
  width: number;
39
- /** Output height */
40
50
  height: number;
41
- /** Output MIME type (always image/jpeg) */
42
51
  mimeType: 'image/jpeg';
43
- /** Original format that was converted */
44
- originalFormat: ImageFormat;
52
+ originalFormat: Exclude<ImageFormat, 'unknown'>;
53
+ }
54
+ interface EncodedImage extends AsyncIterable<Uint8Array> {
55
+ readonly info: Promise<EncodedImageInfo>;
56
+ readonly stats: Promise<TransformStats>;
57
+ }
58
+ interface InspectResult {
59
+ info: ImageInfo;
60
+ source: InputSource;
45
61
  }
46
62
  /**
47
63
  * Internal: A single scanline of RGB pixel data
@@ -54,6 +70,34 @@ interface Scanline {
54
70
  /** Y position in the image (0-indexed) */
55
71
  y: number;
56
72
  }
73
+ interface PixelStream extends AsyncIterable<Scanline> {
74
+ readonly info: Promise<{
75
+ width: number;
76
+ height: number;
77
+ originalFormat: Exclude<ImageFormat, 'unknown'>;
78
+ }>;
79
+ readonly stats?: Promise<TransformStats>;
80
+ }
81
+ /**
82
+ * Legacy process options retained for a small amount of internal compatibility while
83
+ * the old files remain in the tree.
84
+ */
85
+ interface ProcessOptions {
86
+ maxWidth?: number;
87
+ maxHeight?: number;
88
+ maxBytes?: number;
89
+ quality?: number;
90
+ }
91
+ /**
92
+ * Legacy process result retained for internal compatibility.
93
+ */
94
+ interface ProcessResult {
95
+ data: ArrayBuffer;
96
+ width: number;
97
+ height: number;
98
+ mimeType: 'image/jpeg';
99
+ originalFormat: ImageFormat;
100
+ }
57
101
  /**
58
102
  * Internal: Decoder state for streaming decode
59
103
  */
@@ -110,506 +154,21 @@ interface ResizeState {
110
154
  currentOutputY: number;
111
155
  }
112
156
 
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
- }
157
+ declare function inspect(input: ByteInput): Promise<InspectResult>;
572
158
 
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
- };
159
+ declare function decode(input: ByteInput | InputSource): PixelStream;
160
+ declare function resize(stream: PixelStream, options: TransformOptions): PixelStream;
161
+ declare function encodeJpeg(stream: PixelStream, options?: TransformOptions): EncodedImage;
162
+ declare function transform(input: ByteInput | InputSource, options?: TransformOptions): EncodedImage;
163
+ declare function ready(options?: {
164
+ wasm?: WebAssembly.Module | ArrayBuffer;
165
+ }): Promise<void>;
166
+ declare function collect(image: EncodedImage): Promise<{
167
+ data: ArrayBuffer;
168
+ info: EncodedImageInfo;
169
+ stats: TransformStats;
170
+ }>;
171
+ declare function toReadableStream(image: EncodedImage): ReadableStream<Uint8Array>;
172
+ declare function toResponse(image: EncodedImage, init?: ResponseInit): Response;
614
173
 
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 };
174
+ export { type ByteInput, type DecoderState, type EncodedImage, type EncodedImageInfo, type EncoderState, type ImageFormat, type ImageInfo, type InputSource, type InspectResult, type PixelStream, type ProbeResult, type ProcessOptions, type ProcessResult, type ResizeState, type Scanline, type TransformOptions, type TransformStats, collect, decode, encodeJpeg, inspect, ready, resize, toReadableStream, toResponse, transform };