cross-image 0.4.0 → 0.4.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 (50) hide show
  1. package/README.md +109 -1
  2. package/esm/mod.d.ts +3 -1
  3. package/esm/mod.js +2 -0
  4. package/esm/src/formats/apng.d.ts +5 -3
  5. package/esm/src/formats/apng.js +11 -4
  6. package/esm/src/formats/avif.d.ts +2 -2
  7. package/esm/src/formats/avif.js +11 -1
  8. package/esm/src/formats/gif.d.ts +3 -3
  9. package/esm/src/formats/gif.js +4 -4
  10. package/esm/src/formats/heic.d.ts +2 -2
  11. package/esm/src/formats/heic.js +11 -1
  12. package/esm/src/formats/png.d.ts +3 -2
  13. package/esm/src/formats/png.js +8 -2
  14. package/esm/src/formats/png_base.d.ts +42 -1
  15. package/esm/src/formats/png_base.js +198 -5
  16. package/esm/src/formats/tiff.js +76 -6
  17. package/esm/src/image.d.ts +15 -0
  18. package/esm/src/image.js +29 -1
  19. package/esm/src/types.d.ts +66 -0
  20. package/esm/src/utils/base64.d.ts +32 -0
  21. package/esm/src/utils/base64.js +173 -0
  22. package/esm/src/utils/gif_encoder.d.ts +3 -1
  23. package/esm/src/utils/gif_encoder.js +4 -2
  24. package/esm/src/utils/image_processing.d.ts +31 -0
  25. package/esm/src/utils/image_processing.js +88 -0
  26. package/package.json +1 -1
  27. package/script/mod.d.ts +3 -1
  28. package/script/mod.js +11 -1
  29. package/script/src/formats/apng.d.ts +5 -3
  30. package/script/src/formats/apng.js +11 -4
  31. package/script/src/formats/avif.d.ts +2 -2
  32. package/script/src/formats/avif.js +11 -1
  33. package/script/src/formats/gif.d.ts +3 -3
  34. package/script/src/formats/gif.js +4 -4
  35. package/script/src/formats/heic.d.ts +2 -2
  36. package/script/src/formats/heic.js +11 -1
  37. package/script/src/formats/png.d.ts +3 -2
  38. package/script/src/formats/png.js +8 -2
  39. package/script/src/formats/png_base.d.ts +42 -1
  40. package/script/src/formats/png_base.js +198 -5
  41. package/script/src/formats/tiff.js +76 -6
  42. package/script/src/image.d.ts +15 -0
  43. package/script/src/image.js +28 -0
  44. package/script/src/types.d.ts +66 -0
  45. package/script/src/utils/base64.d.ts +32 -0
  46. package/script/src/utils/base64.js +179 -0
  47. package/script/src/utils/gif_encoder.d.ts +3 -1
  48. package/script/src/utils/gif_encoder.js +4 -2
  49. package/script/src/utils/image_processing.d.ts +31 -0
  50. package/script/src/utils/image_processing.js +92 -0
package/README.md CHANGED
@@ -196,6 +196,112 @@ const imageWithWarnings = await Image.decode(data, {
196
196
  ```
197
197
 
198
198
  **Note:** When using `Image.decode()`, the library automatically tries runtime-optimized decoders
199
+
200
+ ## CMYK Color Space Support
201
+
202
+ The library provides utilities for working with CMYK (Cyan, Magenta, Yellow, Key/Black) color space,
203
+ commonly used in professional printing and color manipulation.
204
+
205
+ ### Color Conversion Utilities
206
+
207
+ ```ts
208
+ import { cmykToRgb, rgbToCmyk } from "jsr:@cross/image";
209
+
210
+ // Convert RGB to CMYK
211
+ const [c, m, y, k] = rgbToCmyk(255, 0, 0); // Red
212
+ console.log({ c, m, y, k }); // { c: 0, m: 1, y: 1, k: 0 }
213
+
214
+ // Convert CMYK back to RGB
215
+ const [r, g, b] = cmykToRgb(c, m, y, k);
216
+ console.log({ r, g, b }); // { r: 255, g: 0, b: 0 }
217
+ ```
218
+
219
+ ### Image-Level CMYK Operations
220
+
221
+ ```ts
222
+ import { Image } from "jsr:@cross/image";
223
+
224
+ // Load an image and convert to CMYK
225
+ const data = await Deno.readFile("photo.jpg");
226
+ const image = await Image.decode(data);
227
+
228
+ // Get CMYK representation (Float32Array with 4 values per pixel)
229
+ const cmykData = image.toCMYK();
230
+
231
+ // Create an image from CMYK data
232
+ const restored = Image.fromCMYK(cmykData, image.width, image.height);
233
+
234
+ // Save the restored image
235
+ await Deno.writeFile("output.png", await restored.encode("png"));
236
+ ```
237
+
238
+ ### Batch Conversion
239
+
240
+ ```ts
241
+ import { cmykToRgba, rgbaToCmyk } from "jsr:@cross/image";
242
+
243
+ // Convert entire image data to CMYK
244
+ const rgbaData = new Uint8Array([255, 0, 0, 255]); // Red pixel
245
+ const cmykData = rgbaToCmyk(rgbaData);
246
+
247
+ // Convert CMYK data back to RGBA
248
+ const rgbaRestored = cmykToRgba(cmykData);
249
+ ```
250
+
251
+ **Use Cases:**
252
+
253
+ - Pre-press and print preparation workflows
254
+ - Color space conversion for professional printing
255
+ - Color analysis and manipulation in CMYK space
256
+ - Educational tools for understanding color models
257
+
258
+ ### CMYK TIFF Support
259
+
260
+ TIFF format has native support for CMYK images:
261
+
262
+ ```ts
263
+ import { Image } from "jsr:@cross/image";
264
+
265
+ // Decode CMYK TIFF (automatically converted to RGBA)
266
+ const cmykTiff = await Deno.readFile("cmyk-image.tif");
267
+ const image = await Image.decode(cmykTiff); // Automatic CMYK → RGBA conversion
268
+
269
+ // Encode image as CMYK TIFF
270
+ const output = await image.encode("tiff", { cmyk: true });
271
+ await Deno.writeFile("output-cmyk.tif", output);
272
+
273
+ // CMYK works with all TIFF compression methods
274
+ const compressed = await image.encode("tiff", {
275
+ cmyk: true,
276
+ compression: "lzw", // or "packbits", "deflate", "none"
277
+ });
278
+ ```
279
+
280
+ **Benefits:**
281
+
282
+ - **Seamless workflow**: CMYK TIFFs decode automatically, no special handling needed
283
+ - **Print-ready output**: Generate CMYK TIFFs for professional printing workflows
284
+ - **Full compression support**: CMYK works with all TIFF compression methods
285
+ - **Industry standard**: TIFF is the preferred format for CMYK images in print production
286
+
287
+ ## Base64 / Data URLs
288
+
289
+ The library includes small utilities for working with base64 and `data:` URLs.
290
+
291
+ ```ts
292
+ import { Image, parseDataUrl, toDataUrl } from "jsr:@cross/image";
293
+
294
+ const image = Image.create(2, 2, 255, 0, 0);
295
+ const pngBytes = await image.encode("png");
296
+
297
+ const dataUrl = toDataUrl("image/png", pngBytes);
298
+ const parsed = parseDataUrl(dataUrl);
299
+
300
+ // parsed.bytes is a Uint8Array containing the PNG
301
+ const roundtrip = await Image.decode(parsed.bytes, "png");
302
+ console.log(roundtrip.width, roundtrip.height);
303
+ ```
304
+
199
305
  (ImageDecoder API) first, falling back to the pure JS decoder with tolerant mode for maximum
200
306
  compatibility.
201
307
 
@@ -394,7 +500,7 @@ const jpegSupports = Image.getSupportedMetadata("jpeg");
394
500
  console.log(jpegSupports); // Includes ISO, camera info, GPS, etc.
395
501
 
396
502
  // Save with metadata
397
- const jpeg = await image.save("jpeg");
503
+ const jpeg = await image.encode("jpeg");
398
504
  await Deno.writeFile("output.jpg", jpeg);
399
505
 
400
506
  // Metadata is preserved on reload!
@@ -488,6 +594,8 @@ Image.getSupportedMetadata("avif"); // Full camera metadata + GPS (19 fields)
488
594
  Technical details for WebP
489
595
  - **[TIFF Implementation](https://cross-image.56k.guru/implementation/tiff-implementation/)** -
490
596
  Technical details for TIFF
597
+ - **[GIF Implementation](https://cross-image.56k.guru/implementation/gif-implementation/)** -
598
+ Technical details for GIF
491
599
 
492
600
  ## Development
493
601
 
package/esm/mod.d.ts CHANGED
@@ -43,7 +43,7 @@
43
43
  * ```
44
44
  */
45
45
  export { Image } from "./src/image.js";
46
- export type { ASCIIEncoderOptions, FrameMetadata, ImageData, ImageDecoderOptions, ImageFormat, ImageFrame, ImageMetadata, JPEGEncoderOptions, MultiFrameImageData, ResizeOptions, TIFFEncoderOptions, WebPEncoderOptions, } from "./src/types.js";
46
+ export type { APNGEncoderOptions, ASCIIEncoderOptions, AVIFEncoderOptions, FrameMetadata, GIFEncoderOptions, HEICEncoderOptions, ImageData, ImageDecoderOptions, ImageFormat, ImageFrame, ImageMetadata, JPEGEncoderOptions, MultiFrameImageData, PNGEncoderOptions, ResizeOptions, TIFFEncoderOptions, WebPEncoderOptions, } from "./src/types.js";
47
47
  export { PNGFormat } from "./src/formats/png.js";
48
48
  export { APNGFormat } from "./src/formats/apng.js";
49
49
  export { JPEGFormat } from "./src/formats/jpeg.js";
@@ -59,4 +59,6 @@ export { PPMFormat } from "./src/formats/ppm.js";
59
59
  export { ASCIIFormat } from "./src/formats/ascii.js";
60
60
  export { HEICFormat } from "./src/formats/heic.js";
61
61
  export { AVIFFormat } from "./src/formats/avif.js";
62
+ export { decodeBase64, encodeBase64, parseDataUrl, toDataUrl } from "./src/utils/base64.js";
63
+ export { cmykToRgb, cmykToRgba, rgbaToCmyk, rgbToCmyk } from "./src/utils/image_processing.js";
62
64
  //# sourceMappingURL=mod.d.ts.map
package/esm/mod.js CHANGED
@@ -58,3 +58,5 @@ export { PPMFormat } from "./src/formats/ppm.js";
58
58
  export { ASCIIFormat } from "./src/formats/ascii.js";
59
59
  export { HEICFormat } from "./src/formats/heic.js";
60
60
  export { AVIFFormat } from "./src/formats/avif.js";
61
+ export { decodeBase64, encodeBase64, parseDataUrl, toDataUrl } from "./src/utils/base64.js";
62
+ export { cmykToRgb, cmykToRgba, rgbaToCmyk, rgbToCmyk } from "./src/utils/image_processing.js";
@@ -1,4 +1,4 @@
1
- import type { ImageData, ImageDecoderOptions, ImageFormat, ImageMetadata, MultiFrameImageData } from "../types.js";
1
+ import type { APNGEncoderOptions, ImageData, ImageDecoderOptions, ImageFormat, ImageMetadata, MultiFrameImageData } from "../types.js";
2
2
  import { PNGBase } from "./png_base.js";
3
3
  /**
4
4
  * APNG (Animated PNG) format handler
@@ -36,15 +36,17 @@ export declare class APNGFormat extends PNGBase implements ImageFormat {
36
36
  /**
37
37
  * Encode RGBA image data to APNG format (single frame)
38
38
  * @param imageData Image data to encode
39
+ * @param options Encoding options (compressionLevel 0-9, default 6)
39
40
  * @returns Encoded APNG image bytes
40
41
  */
41
- encode(imageData: ImageData, _options?: unknown): Promise<Uint8Array>;
42
+ encode(imageData: ImageData, options?: APNGEncoderOptions): Promise<Uint8Array>;
42
43
  /**
43
44
  * Encode multi-frame image data to APNG format
44
45
  * @param imageData Multi-frame image data to encode
46
+ * @param options Encoding options (compressionLevel 0-9, default 6)
45
47
  * @returns Encoded APNG image bytes
46
48
  */
47
- encodeFrames(imageData: MultiFrameImageData, _options?: unknown): Promise<Uint8Array>;
49
+ encodeFrames(imageData: MultiFrameImageData, options?: APNGEncoderOptions): Promise<Uint8Array>;
48
50
  private decodeFrameData;
49
51
  /**
50
52
  * Get the list of metadata fields supported by APNG format
@@ -250,9 +250,10 @@ export class APNGFormat extends PNGBase {
250
250
  /**
251
251
  * Encode RGBA image data to APNG format (single frame)
252
252
  * @param imageData Image data to encode
253
+ * @param options Encoding options (compressionLevel 0-9, default 6)
253
254
  * @returns Encoded APNG image bytes
254
255
  */
255
- encode(imageData, _options) {
256
+ encode(imageData, options) {
256
257
  // For single frame, create a multi-frame with one frame
257
258
  const multiFrame = {
258
259
  width: imageData.width,
@@ -265,15 +266,21 @@ export class APNGFormat extends PNGBase {
265
266
  }],
266
267
  metadata: imageData.metadata,
267
268
  };
268
- return this.encodeFrames(multiFrame, _options);
269
+ return this.encodeFrames(multiFrame, options);
269
270
  }
270
271
  /**
271
272
  * Encode multi-frame image data to APNG format
272
273
  * @param imageData Multi-frame image data to encode
274
+ * @param options Encoding options (compressionLevel 0-9, default 6)
273
275
  * @returns Encoded APNG image bytes
274
276
  */
275
- async encodeFrames(imageData, _options) {
277
+ async encodeFrames(imageData, options) {
276
278
  const { width, height, frames, metadata } = imageData;
279
+ const compressionLevel = options?.compressionLevel ?? 6;
280
+ // Validate compression level
281
+ if (compressionLevel < 0 || compressionLevel > 9) {
282
+ throw new Error("Compression level must be between 0 and 9");
283
+ }
277
284
  if (frames.length === 0) {
278
285
  throw new Error("No frames to encode");
279
286
  }
@@ -331,7 +338,7 @@ export class APNGFormat extends PNGBase {
331
338
  fctl[25] = 0; // blend_op: APNG_BLEND_OP_SOURCE
332
339
  chunks.push(this.createChunk("fcTL", fctl));
333
340
  // Filter and compress frame data
334
- const filtered = this.filterData(frame.data, frame.width, frame.height);
341
+ const filtered = this.filterData(frame.data, frame.width, frame.height, compressionLevel);
335
342
  const compressed = await this.deflate(filtered);
336
343
  if (i === 0) {
337
344
  // First frame uses IDAT
@@ -1,4 +1,4 @@
1
- import type { ImageData, ImageDecoderOptions, ImageFormat, ImageMetadata } from "../types.js";
1
+ import type { AVIFEncoderOptions, ImageData, ImageDecoderOptions, ImageFormat, ImageMetadata } from "../types.js";
2
2
  /**
3
3
  * AVIF format handler
4
4
  * Supports AVIF images using runtime APIs (ImageDecoder/OffscreenCanvas)
@@ -32,7 +32,7 @@ export declare class AVIFFormat implements ImageFormat {
32
32
  * @param imageData Image data to encode
33
33
  * @returns Encoded AVIF image bytes
34
34
  */
35
- encode(imageData: ImageData, _options?: unknown): Promise<Uint8Array>;
35
+ encode(imageData: ImageData, options?: AVIFEncoderOptions): Promise<Uint8Array>;
36
36
  /**
37
37
  * Decode using runtime APIs
38
38
  * @param data Raw AVIF data
@@ -79,8 +79,9 @@ export class AVIFFormat {
79
79
  * @param imageData Image data to encode
80
80
  * @returns Encoded AVIF image bytes
81
81
  */
82
- async encode(imageData, _options) {
82
+ async encode(imageData, options) {
83
83
  const { width, height, data, metadata: _metadata } = imageData;
84
+ const requestedQuality = options?.quality;
84
85
  // Try to use runtime encoding if available
85
86
  if (typeof OffscreenCanvas !== "undefined") {
86
87
  try {
@@ -91,10 +92,19 @@ export class AVIFFormat {
91
92
  const imgDataData = new Uint8ClampedArray(data);
92
93
  imgData.data.set(imgDataData);
93
94
  ctx.putImageData(imgData, 0, 0);
95
+ const quality = requestedQuality === undefined
96
+ ? undefined
97
+ : (requestedQuality <= 1
98
+ ? Math.max(0, Math.min(1, requestedQuality))
99
+ : Math.max(1, Math.min(100, requestedQuality)) / 100);
94
100
  // Try to encode as AVIF
95
101
  const blob = await canvas.convertToBlob({
96
102
  type: "image/avif",
103
+ ...(quality === undefined ? {} : { quality }),
97
104
  });
105
+ if (blob.type !== "image/avif") {
106
+ throw new Error(`Runtime did not encode AVIF (got '${blob.type || "(empty)"}')`);
107
+ }
98
108
  const arrayBuffer = await blob.arrayBuffer();
99
109
  const encoded = new Uint8Array(arrayBuffer);
100
110
  // Note: Metadata injection for AVIF is complex and would require
@@ -1,4 +1,4 @@
1
- import type { ImageData, ImageDecoderOptions, ImageFormat, ImageMetadata, MultiFrameImageData } from "../types.js";
1
+ import type { GIFEncoderOptions, ImageData, ImageDecoderOptions, ImageFormat, ImageMetadata, MultiFrameImageData } from "../types.js";
2
2
  /**
3
3
  * GIF format handler
4
4
  * Now includes pure-JS implementation with custom LZW compression/decompression
@@ -39,7 +39,7 @@ export declare class GIFFormat implements ImageFormat {
39
39
  * @param imageData Image data to encode
40
40
  * @returns Encoded GIF image bytes
41
41
  */
42
- encode(imageData: ImageData, _options?: unknown): Promise<Uint8Array>;
42
+ encode(imageData: ImageData, options?: GIFEncoderOptions): Promise<Uint8Array>;
43
43
  /**
44
44
  * Decode all frames from an animated GIF
45
45
  */
@@ -47,7 +47,7 @@ export declare class GIFFormat implements ImageFormat {
47
47
  /**
48
48
  * Encode multi-frame image data to animated GIF
49
49
  */
50
- encodeFrames(imageData: MultiFrameImageData, _options?: unknown): Promise<Uint8Array>;
50
+ encodeFrames(imageData: MultiFrameImageData, options?: GIFEncoderOptions): Promise<Uint8Array>;
51
51
  private mapDisposalMethod;
52
52
  private decodeUsingRuntime;
53
53
  private readDataSubBlocks;
@@ -153,12 +153,12 @@ export class GIFFormat {
153
153
  * @param imageData Image data to encode
154
154
  * @returns Encoded GIF image bytes
155
155
  */
156
- async encode(imageData, _options) {
156
+ async encode(imageData, options) {
157
157
  const { width, height, data, metadata } = imageData;
158
158
  // Try pure-JS encoder first
159
159
  try {
160
160
  const encoder = new GIFEncoder(width, height, data);
161
- const encoded = encoder.encode();
161
+ const encoded = encoder.encode(options);
162
162
  // Inject metadata if present
163
163
  if (metadata && Object.keys(metadata).length > 0) {
164
164
  const injected = this.injectMetadata(encoded, metadata);
@@ -237,7 +237,7 @@ export class GIFFormat {
237
237
  /**
238
238
  * Encode multi-frame image data to animated GIF
239
239
  */
240
- encodeFrames(imageData, _options) {
240
+ encodeFrames(imageData, options) {
241
241
  if (imageData.frames.length === 0) {
242
242
  throw new Error("No frames to encode");
243
243
  }
@@ -247,7 +247,7 @@ export class GIFFormat {
247
247
  const delay = frame.frameMetadata?.delay ?? 100;
248
248
  encoder.addFrame(frame.data, delay);
249
249
  }
250
- return Promise.resolve(encoder.encode());
250
+ return Promise.resolve(encoder.encode(options));
251
251
  }
252
252
  mapDisposalMethod(disposal) {
253
253
  switch (disposal) {
@@ -1,4 +1,4 @@
1
- import type { ImageData, ImageDecoderOptions, ImageFormat, ImageMetadata } from "../types.js";
1
+ import type { HEICEncoderOptions, ImageData, ImageDecoderOptions, ImageFormat, ImageMetadata } from "../types.js";
2
2
  /**
3
3
  * HEIC format handler
4
4
  * Supports HEIC/HEIF images using runtime APIs (ImageDecoder/OffscreenCanvas)
@@ -32,7 +32,7 @@ export declare class HEICFormat implements ImageFormat {
32
32
  * @param imageData Image data to encode
33
33
  * @returns Encoded HEIC image bytes
34
34
  */
35
- encode(imageData: ImageData, _options?: unknown): Promise<Uint8Array>;
35
+ encode(imageData: ImageData, options?: HEICEncoderOptions): Promise<Uint8Array>;
36
36
  /**
37
37
  * Decode using runtime APIs
38
38
  * @param data Raw HEIC data
@@ -80,8 +80,9 @@ export class HEICFormat {
80
80
  * @param imageData Image data to encode
81
81
  * @returns Encoded HEIC image bytes
82
82
  */
83
- async encode(imageData, _options) {
83
+ async encode(imageData, options) {
84
84
  const { width, height, data, metadata: _metadata } = imageData;
85
+ const requestedQuality = options?.quality;
85
86
  // Try to use runtime encoding if available
86
87
  if (typeof OffscreenCanvas !== "undefined") {
87
88
  try {
@@ -92,10 +93,19 @@ export class HEICFormat {
92
93
  const imgDataData = new Uint8ClampedArray(data);
93
94
  imgData.data.set(imgDataData);
94
95
  ctx.putImageData(imgData, 0, 0);
96
+ const quality = requestedQuality === undefined
97
+ ? undefined
98
+ : (requestedQuality <= 1
99
+ ? Math.max(0, Math.min(1, requestedQuality))
100
+ : Math.max(1, Math.min(100, requestedQuality)) / 100);
95
101
  // Try to encode as HEIC
96
102
  const blob = await canvas.convertToBlob({
97
103
  type: "image/heic",
104
+ ...(quality === undefined ? {} : { quality }),
98
105
  });
106
+ if (blob.type !== "image/heic") {
107
+ throw new Error(`Runtime did not encode HEIC (got '${blob.type || "(empty)"}')`);
108
+ }
99
109
  const arrayBuffer = await blob.arrayBuffer();
100
110
  const encoded = new Uint8Array(arrayBuffer);
101
111
  // Note: Metadata injection for HEIC is complex and would require
@@ -1,4 +1,4 @@
1
- import type { ImageData, ImageDecoderOptions, ImageFormat, ImageMetadata } from "../types.js";
1
+ import type { ImageData, ImageDecoderOptions, ImageFormat, ImageMetadata, PNGEncoderOptions } from "../types.js";
2
2
  import { PNGBase } from "./png_base.js";
3
3
  /**
4
4
  * PNG format handler
@@ -24,9 +24,10 @@ export declare class PNGFormat extends PNGBase implements ImageFormat {
24
24
  /**
25
25
  * Encode RGBA image data to PNG format
26
26
  * @param imageData Image data to encode
27
+ * @param options Encoding options (compressionLevel 0-9, default 6)
27
28
  * @returns Encoded PNG image bytes
28
29
  */
29
- encode(imageData: ImageData, _options?: unknown): Promise<Uint8Array>;
30
+ encode(imageData: ImageData, options?: PNGEncoderOptions): Promise<Uint8Array>;
30
31
  /**
31
32
  * Get the list of metadata fields supported by PNG format
32
33
  * Delegates to PNGBase implementation
@@ -110,10 +110,16 @@ export class PNGFormat extends PNGBase {
110
110
  /**
111
111
  * Encode RGBA image data to PNG format
112
112
  * @param imageData Image data to encode
113
+ * @param options Encoding options (compressionLevel 0-9, default 6)
113
114
  * @returns Encoded PNG image bytes
114
115
  */
115
- async encode(imageData, _options) {
116
+ async encode(imageData, options) {
116
117
  const { width, height, data, metadata } = imageData;
118
+ const compressionLevel = options?.compressionLevel ?? 6;
119
+ // Validate compression level
120
+ if (compressionLevel < 0 || compressionLevel > 9) {
121
+ throw new Error("Compression level must be between 0 and 9");
122
+ }
117
123
  // Prepare IHDR chunk
118
124
  const ihdr = new Uint8Array(13);
119
125
  this.writeUint32(ihdr, 0, width);
@@ -124,7 +130,7 @@ export class PNGFormat extends PNGBase {
124
130
  ihdr[11] = 0; // filter method
125
131
  ihdr[12] = 0; // interlace method
126
132
  // Filter and compress image data
127
- const filtered = this.filterData(data, width, height);
133
+ const filtered = this.filterData(data, width, height, compressionLevel);
128
134
  const compressed = await this.deflate(filtered);
129
135
  // Build PNG
130
136
  const chunks = [];
@@ -43,7 +43,48 @@ export declare abstract class PNGBase {
43
43
  /**
44
44
  * Filter PNG data for encoding (using filter type 0 - None)
45
45
  */
46
- protected filterData(data: Uint8Array, width: number, height: number): Uint8Array;
46
+ /**
47
+ * Apply PNG filter to image data based on compression level
48
+ * @param data Raw RGBA pixel data
49
+ * @param width Image width
50
+ * @param height Image height
51
+ * @param compressionLevel Compression level (0-9, default 6)
52
+ * @returns Filtered data with filter type byte per scanline
53
+ */
54
+ protected filterData(data: Uint8Array, width: number, height: number, compressionLevel?: number): Uint8Array;
55
+ /**
56
+ * Apply filter type 0 (None) - no filtering
57
+ */
58
+ private applyNoFilter;
59
+ /**
60
+ * Apply filter type 1 (Sub) - subtract left pixel
61
+ */
62
+ private applySubFilter;
63
+ /**
64
+ * Apply filter type 2 (Up) - subtract above pixel
65
+ */
66
+ private applyUpFilter;
67
+ /**
68
+ * Apply filter type 3 (Average) - subtract average of left and above
69
+ */
70
+ private applyAverageFilter;
71
+ /**
72
+ * Apply filter type 4 (Paeth) - Paeth predictor
73
+ */
74
+ private applyPaethFilter;
75
+ /**
76
+ * Calculate sum of absolute differences for a filtered scanline
77
+ * Lower values indicate better compression potential
78
+ */
79
+ private calculateFilterScore;
80
+ /**
81
+ * Apply adaptive filtering - choose best filter per scanline
82
+ */
83
+ private applyAdaptiveFilter;
84
+ /**
85
+ * Filter a single scanline with specified filter type
86
+ */
87
+ private filterScanline;
47
88
  /**
48
89
  * Get bytes per pixel for a given color type and bit depth
49
90
  */