cross-image 0.2.2 → 0.2.4

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 (88) hide show
  1. package/README.md +333 -168
  2. package/esm/mod.d.ts +2 -0
  3. package/esm/mod.js +2 -0
  4. package/esm/src/formats/apng.d.ts +13 -1
  5. package/esm/src/formats/apng.js +97 -0
  6. package/esm/src/formats/ascii.d.ts +11 -1
  7. package/esm/src/formats/ascii.js +24 -0
  8. package/esm/src/formats/avif.d.ts +96 -0
  9. package/esm/src/formats/avif.js +607 -0
  10. package/esm/src/formats/bmp.d.ts +11 -1
  11. package/esm/src/formats/bmp.js +73 -0
  12. package/esm/src/formats/dng.d.ts +13 -1
  13. package/esm/src/formats/dng.js +26 -4
  14. package/esm/src/formats/gif.d.ts +15 -2
  15. package/esm/src/formats/gif.js +146 -4
  16. package/esm/src/formats/heic.d.ts +96 -0
  17. package/esm/src/formats/heic.js +608 -0
  18. package/esm/src/formats/ico.d.ts +11 -1
  19. package/esm/src/formats/ico.js +28 -0
  20. package/esm/src/formats/jpeg.d.ts +19 -1
  21. package/esm/src/formats/jpeg.js +709 -4
  22. package/esm/src/formats/pam.d.ts +11 -1
  23. package/esm/src/formats/pam.js +66 -0
  24. package/esm/src/formats/pcx.d.ts +11 -1
  25. package/esm/src/formats/pcx.js +45 -0
  26. package/esm/src/formats/png.d.ts +13 -1
  27. package/esm/src/formats/png.js +87 -0
  28. package/esm/src/formats/png_base.d.ts +8 -0
  29. package/esm/src/formats/png_base.js +176 -3
  30. package/esm/src/formats/ppm.d.ts +11 -1
  31. package/esm/src/formats/ppm.js +34 -0
  32. package/esm/src/formats/tiff.d.ts +13 -1
  33. package/esm/src/formats/tiff.js +165 -0
  34. package/esm/src/formats/webp.d.ts +16 -2
  35. package/esm/src/formats/webp.js +303 -62
  36. package/esm/src/image.d.ts +60 -0
  37. package/esm/src/image.js +253 -5
  38. package/esm/src/types.d.ts +59 -1
  39. package/esm/src/utils/image_processing.d.ts +55 -0
  40. package/esm/src/utils/image_processing.js +210 -0
  41. package/esm/src/utils/metadata/xmp.d.ts +52 -0
  42. package/esm/src/utils/metadata/xmp.js +325 -0
  43. package/esm/src/utils/resize.d.ts +4 -0
  44. package/esm/src/utils/resize.js +74 -0
  45. package/package.json +18 -1
  46. package/script/mod.d.ts +2 -0
  47. package/script/mod.js +5 -1
  48. package/script/src/formats/apng.d.ts +13 -1
  49. package/script/src/formats/apng.js +97 -0
  50. package/script/src/formats/ascii.d.ts +11 -1
  51. package/script/src/formats/ascii.js +24 -0
  52. package/script/src/formats/avif.d.ts +96 -0
  53. package/script/src/formats/avif.js +611 -0
  54. package/script/src/formats/bmp.d.ts +11 -1
  55. package/script/src/formats/bmp.js +73 -0
  56. package/script/src/formats/dng.d.ts +13 -1
  57. package/script/src/formats/dng.js +26 -4
  58. package/script/src/formats/gif.d.ts +15 -2
  59. package/script/src/formats/gif.js +146 -4
  60. package/script/src/formats/heic.d.ts +96 -0
  61. package/script/src/formats/heic.js +612 -0
  62. package/script/src/formats/ico.d.ts +11 -1
  63. package/script/src/formats/ico.js +28 -0
  64. package/script/src/formats/jpeg.d.ts +19 -1
  65. package/script/src/formats/jpeg.js +709 -4
  66. package/script/src/formats/pam.d.ts +11 -1
  67. package/script/src/formats/pam.js +66 -0
  68. package/script/src/formats/pcx.d.ts +11 -1
  69. package/script/src/formats/pcx.js +45 -0
  70. package/script/src/formats/png.d.ts +13 -1
  71. package/script/src/formats/png.js +87 -0
  72. package/script/src/formats/png_base.d.ts +8 -0
  73. package/script/src/formats/png_base.js +176 -3
  74. package/script/src/formats/ppm.d.ts +11 -1
  75. package/script/src/formats/ppm.js +34 -0
  76. package/script/src/formats/tiff.d.ts +13 -1
  77. package/script/src/formats/tiff.js +165 -0
  78. package/script/src/formats/webp.d.ts +16 -2
  79. package/script/src/formats/webp.js +303 -62
  80. package/script/src/image.d.ts +60 -0
  81. package/script/src/image.js +251 -3
  82. package/script/src/types.d.ts +59 -1
  83. package/script/src/utils/image_processing.d.ts +55 -0
  84. package/script/src/utils/image_processing.js +216 -0
  85. package/script/src/utils/metadata/xmp.d.ts +52 -0
  86. package/script/src/utils/metadata/xmp.js +333 -0
  87. package/script/src/utils/resize.d.ts +4 -0
  88. package/script/src/utils/resize.js +75 -0
@@ -79,6 +79,21 @@ export declare class Image {
79
79
  * @returns Image instance
80
80
  */
81
81
  static decode(data: Uint8Array, format?: string): Promise<Image>;
82
+ /**
83
+ * Get supported metadata fields for a specific format
84
+ * @param format Format name (e.g., "jpeg", "png", "webp")
85
+ * @returns Array of supported metadata field names, or undefined if format doesn't support metadata
86
+ */
87
+ static getSupportedMetadata(format: string): Array<keyof ImageMetadata> | undefined;
88
+ /**
89
+ * Extract metadata from image data without fully decoding the pixel data
90
+ * This is useful for quickly reading EXIF, XMP, or other metadata from images
91
+ * that may have unsupported features or compression methods
92
+ * @param data Raw image data
93
+ * @param format Optional format hint (e.g., "png", "jpeg", "webp")
94
+ * @returns Metadata extracted from the image, or undefined if extraction fails or format is unsupported
95
+ */
96
+ static extractMetadata(data: Uint8Array, format?: string): Promise<ImageMetadata | undefined>;
82
97
  /**
83
98
  * Read an image from bytes
84
99
  * @deprecated Use `decode()` instead. This method will be removed in a future version.
@@ -197,6 +212,12 @@ export declare class Image {
197
212
  * @returns This image instance for chaining
198
213
  */
199
214
  saturation(amount: number): this;
215
+ /**
216
+ * Adjust hue of the image by rotating the color wheel
217
+ * @param degrees Hue rotation in degrees (any value accepted, wraps at 360)
218
+ * @returns This image instance for chaining
219
+ */
220
+ hue(degrees: number): this;
200
221
  /**
201
222
  * Invert colors of the image
202
223
  * @returns This image instance for chaining
@@ -282,5 +303,44 @@ export declare class Image {
282
303
  * @returns This image instance for chaining
283
304
  */
284
305
  setPixel(x: number, y: number, r: number, g: number, b: number, a?: number): this;
306
+ /**
307
+ * Rotate the image 90 degrees clockwise
308
+ * @returns This image instance for chaining
309
+ */
310
+ rotate90(): this;
311
+ /**
312
+ * Rotate the image 180 degrees
313
+ * @returns This image instance for chaining
314
+ */
315
+ rotate180(): this;
316
+ /**
317
+ * Rotate the image 270 degrees clockwise (or 90 degrees counter-clockwise)
318
+ * @returns This image instance for chaining
319
+ */
320
+ rotate270(): this;
321
+ /**
322
+ * Rotate the image by the specified angle in degrees
323
+ * @param degrees Rotation angle in degrees (positive = clockwise, negative = counter-clockwise)
324
+ * @returns This image instance for chaining
325
+ *
326
+ * @example
327
+ * ```ts
328
+ * image.rotate(90); // Rotate 90° clockwise
329
+ * image.rotate(-90); // Rotate 90° counter-clockwise
330
+ * image.rotate(180); // Rotate 180°
331
+ * image.rotate(45); // Rotate 45° clockwise (rounded to nearest 90°)
332
+ * ```
333
+ */
334
+ rotate(degrees: number): this;
335
+ /**
336
+ * Flip the image horizontally (mirror)
337
+ * @returns This image instance for chaining
338
+ */
339
+ flipHorizontal(): this;
340
+ /**
341
+ * Flip the image vertically
342
+ * @returns This image instance for chaining
343
+ */
344
+ flipVertical(): this;
285
345
  }
286
346
  //# sourceMappingURL=image.d.ts.map
@@ -16,6 +16,8 @@ const pam_js_1 = require("./formats/pam.js");
16
16
  const pcx_js_1 = require("./formats/pcx.js");
17
17
  const ppm_js_1 = require("./formats/ppm.js");
18
18
  const ascii_js_1 = require("./formats/ascii.js");
19
+ const heic_js_1 = require("./formats/heic.js");
20
+ const avif_js_1 = require("./formats/avif.js");
19
21
  const security_js_1 = require("./utils/security.js");
20
22
  /**
21
23
  * Main Image class for reading, manipulating, and saving images
@@ -184,6 +186,42 @@ class Image {
184
186
  }
185
187
  throw new Error("Unsupported or unrecognized image format");
186
188
  }
189
+ /**
190
+ * Get supported metadata fields for a specific format
191
+ * @param format Format name (e.g., "jpeg", "png", "webp")
192
+ * @returns Array of supported metadata field names, or undefined if format doesn't support metadata
193
+ */
194
+ static getSupportedMetadata(format) {
195
+ const formatHandler = Image.formats.find((f) => f.name === format.toLowerCase());
196
+ if (!formatHandler) {
197
+ throw new Error(`Unknown image format: ${format}`);
198
+ }
199
+ return formatHandler.getSupportedMetadata?.();
200
+ }
201
+ /**
202
+ * Extract metadata from image data without fully decoding the pixel data
203
+ * This is useful for quickly reading EXIF, XMP, or other metadata from images
204
+ * that may have unsupported features or compression methods
205
+ * @param data Raw image data
206
+ * @param format Optional format hint (e.g., "png", "jpeg", "webp")
207
+ * @returns Metadata extracted from the image, or undefined if extraction fails or format is unsupported
208
+ */
209
+ static async extractMetadata(data, format) {
210
+ // Try specified format first
211
+ if (format) {
212
+ const handler = Image.formats.find((f) => f.name === format);
213
+ if (handler && handler.canDecode(data) && handler.extractMetadata) {
214
+ return await handler.extractMetadata(data);
215
+ }
216
+ }
217
+ // Auto-detect format
218
+ for (const handler of Image.formats) {
219
+ if (handler.canDecode(data) && handler.extractMetadata) {
220
+ return await handler.extractMetadata(data);
221
+ }
222
+ }
223
+ return undefined;
224
+ }
187
225
  /**
188
226
  * Read an image from bytes
189
227
  * @deprecated Use `decode()` instead. This method will be removed in a future version.
@@ -304,19 +342,98 @@ class Image {
304
342
  resize(options) {
305
343
  if (!this.imageData)
306
344
  throw new Error("No image loaded");
307
- const { width, height, method = "bilinear" } = options;
345
+ const { width, height, method = "bilinear", fit = "stretch" } = options;
308
346
  // Validate new dimensions for security (prevent integer overflow and heap exhaustion)
309
347
  (0, security_js_1.validateImageDimensions)(width, height);
310
348
  const { data: srcData, width: srcWidth, height: srcHeight } = this.imageData;
349
+ // Handle fitting modes
350
+ let targetWidth = width;
351
+ let targetHeight = height;
352
+ let shouldCenter = false;
353
+ const fitMode = fit === "contain" ? "fit" : fit === "cover" ? "fill" : fit;
354
+ if (fitMode === "fit" || fitMode === "fill") {
355
+ const srcAspect = srcWidth / srcHeight;
356
+ const targetAspect = width / height;
357
+ if (fitMode === "fit") {
358
+ // Fit within dimensions (letterbox)
359
+ if (srcAspect > targetAspect) {
360
+ // Source is wider - fit to width
361
+ targetWidth = width;
362
+ targetHeight = Math.round(width / srcAspect);
363
+ }
364
+ else {
365
+ // Source is taller - fit to height
366
+ targetWidth = Math.round(height * srcAspect);
367
+ targetHeight = height;
368
+ }
369
+ shouldCenter = true;
370
+ }
371
+ else {
372
+ // Fill dimensions (crop)
373
+ if (srcAspect > targetAspect) {
374
+ // Source is wider - fit to height and crop width
375
+ targetWidth = Math.round(height * srcAspect);
376
+ targetHeight = height;
377
+ }
378
+ else {
379
+ // Source is taller - fit to width and crop height
380
+ targetWidth = width;
381
+ targetHeight = Math.round(width / srcAspect);
382
+ }
383
+ shouldCenter = true;
384
+ }
385
+ }
386
+ // Perform the resize
311
387
  let resizedData;
312
388
  if (method === "nearest") {
313
- resizedData = (0, resize_js_1.resizeNearest)(srcData, srcWidth, srcHeight, width, height);
389
+ resizedData = (0, resize_js_1.resizeNearest)(srcData, srcWidth, srcHeight, targetWidth, targetHeight);
390
+ }
391
+ else if (method === "bicubic") {
392
+ resizedData = (0, resize_js_1.resizeBicubic)(srcData, srcWidth, srcHeight, targetWidth, targetHeight);
314
393
  }
315
394
  else {
316
- resizedData = (0, resize_js_1.resizeBilinear)(srcData, srcWidth, srcHeight, width, height);
395
+ resizedData = (0, resize_js_1.resizeBilinear)(srcData, srcWidth, srcHeight, targetWidth, targetHeight);
317
396
  }
318
397
  // Preserve metadata when resizing
319
398
  const metadata = this.imageData.metadata;
399
+ // If we need to center (fit mode) or crop (fill mode), create a canvas
400
+ if (shouldCenter && (targetWidth !== width || targetHeight !== height)) {
401
+ const canvas = new Uint8Array(width * height * 4);
402
+ // Fill with transparent black by default
403
+ canvas.fill(0);
404
+ if (fitMode === "fit") {
405
+ // Center the resized image (letterbox)
406
+ const offsetX = Math.floor((width - targetWidth) / 2);
407
+ const offsetY = Math.floor((height - targetHeight) / 2);
408
+ for (let y = 0; y < targetHeight; y++) {
409
+ for (let x = 0; x < targetWidth; x++) {
410
+ const srcIdx = (y * targetWidth + x) * 4;
411
+ const dstIdx = ((y + offsetY) * width + (x + offsetX)) * 4;
412
+ canvas[dstIdx] = resizedData[srcIdx];
413
+ canvas[dstIdx + 1] = resizedData[srcIdx + 1];
414
+ canvas[dstIdx + 2] = resizedData[srcIdx + 2];
415
+ canvas[dstIdx + 3] = resizedData[srcIdx + 3];
416
+ }
417
+ }
418
+ resizedData = canvas;
419
+ }
420
+ else {
421
+ // Crop to fill (center crop)
422
+ const offsetX = Math.floor((targetWidth - width) / 2);
423
+ const offsetY = Math.floor((targetHeight - height) / 2);
424
+ for (let y = 0; y < height; y++) {
425
+ for (let x = 0; x < width; x++) {
426
+ const srcIdx = ((y + offsetY) * targetWidth + (x + offsetX)) * 4;
427
+ const dstIdx = (y * width + x) * 4;
428
+ canvas[dstIdx] = resizedData[srcIdx];
429
+ canvas[dstIdx + 1] = resizedData[srcIdx + 1];
430
+ canvas[dstIdx + 2] = resizedData[srcIdx + 2];
431
+ canvas[dstIdx + 3] = resizedData[srcIdx + 3];
432
+ }
433
+ }
434
+ resizedData = canvas;
435
+ }
436
+ }
320
437
  this.imageData = {
321
438
  width,
322
439
  height,
@@ -442,6 +559,17 @@ class Image {
442
559
  this.imageData.data = (0, image_processing_js_1.adjustSaturation)(this.imageData.data, amount);
443
560
  return this;
444
561
  }
562
+ /**
563
+ * Adjust hue of the image by rotating the color wheel
564
+ * @param degrees Hue rotation in degrees (any value accepted, wraps at 360)
565
+ * @returns This image instance for chaining
566
+ */
567
+ hue(degrees) {
568
+ if (!this.imageData)
569
+ throw new Error("No image loaded");
570
+ this.imageData.data = (0, image_processing_js_1.adjustHue)(this.imageData.data, degrees);
571
+ return this;
572
+ }
445
573
  /**
446
574
  * Invert colors of the image
447
575
  * @returns This image instance for chaining
@@ -605,6 +733,124 @@ class Image {
605
733
  this.imageData.data[idx + 3] = a;
606
734
  return this;
607
735
  }
736
+ /**
737
+ * Rotate the image 90 degrees clockwise
738
+ * @returns This image instance for chaining
739
+ */
740
+ rotate90() {
741
+ if (!this.imageData)
742
+ throw new Error("No image loaded");
743
+ const result = (0, image_processing_js_1.rotate90)(this.imageData.data, this.imageData.width, this.imageData.height);
744
+ this.imageData.width = result.width;
745
+ this.imageData.height = result.height;
746
+ this.imageData.data = result.data;
747
+ // Update physical dimensions if DPI is set
748
+ if (this.imageData.metadata) {
749
+ const metadata = this.imageData.metadata;
750
+ if (metadata.dpiX && metadata.dpiY) {
751
+ // Swap physical dimensions
752
+ const tempPhysical = metadata.physicalWidth;
753
+ this.imageData.metadata.physicalWidth = metadata.physicalHeight;
754
+ this.imageData.metadata.physicalHeight = tempPhysical;
755
+ // Swap DPI
756
+ const tempDpi = metadata.dpiX;
757
+ this.imageData.metadata.dpiX = metadata.dpiY;
758
+ this.imageData.metadata.dpiY = tempDpi;
759
+ }
760
+ }
761
+ return this;
762
+ }
763
+ /**
764
+ * Rotate the image 180 degrees
765
+ * @returns This image instance for chaining
766
+ */
767
+ rotate180() {
768
+ if (!this.imageData)
769
+ throw new Error("No image loaded");
770
+ this.imageData.data = (0, image_processing_js_1.rotate180)(this.imageData.data, this.imageData.width, this.imageData.height);
771
+ return this;
772
+ }
773
+ /**
774
+ * Rotate the image 270 degrees clockwise (or 90 degrees counter-clockwise)
775
+ * @returns This image instance for chaining
776
+ */
777
+ rotate270() {
778
+ if (!this.imageData)
779
+ throw new Error("No image loaded");
780
+ const result = (0, image_processing_js_1.rotate270)(this.imageData.data, this.imageData.width, this.imageData.height);
781
+ this.imageData.width = result.width;
782
+ this.imageData.height = result.height;
783
+ this.imageData.data = result.data;
784
+ // Update physical dimensions if DPI is set
785
+ if (this.imageData.metadata) {
786
+ const metadata = this.imageData.metadata;
787
+ if (metadata.dpiX && metadata.dpiY) {
788
+ // Swap physical dimensions
789
+ const tempPhysical = metadata.physicalWidth;
790
+ this.imageData.metadata.physicalWidth = metadata.physicalHeight;
791
+ this.imageData.metadata.physicalHeight = tempPhysical;
792
+ // Swap DPI
793
+ const tempDpi = metadata.dpiX;
794
+ this.imageData.metadata.dpiX = metadata.dpiY;
795
+ this.imageData.metadata.dpiY = tempDpi;
796
+ }
797
+ }
798
+ return this;
799
+ }
800
+ /**
801
+ * Rotate the image by the specified angle in degrees
802
+ * @param degrees Rotation angle in degrees (positive = clockwise, negative = counter-clockwise)
803
+ * @returns This image instance for chaining
804
+ *
805
+ * @example
806
+ * ```ts
807
+ * image.rotate(90); // Rotate 90° clockwise
808
+ * image.rotate(-90); // Rotate 90° counter-clockwise
809
+ * image.rotate(180); // Rotate 180°
810
+ * image.rotate(45); // Rotate 45° clockwise (rounded to nearest 90°)
811
+ * ```
812
+ */
813
+ rotate(degrees) {
814
+ // Normalize to 0-360 range
815
+ let normalizedDegrees = degrees % 360;
816
+ if (normalizedDegrees < 0) {
817
+ normalizedDegrees += 360;
818
+ }
819
+ // Round to nearest 90 degrees
820
+ const rounded = Math.round(normalizedDegrees / 90) * 90;
821
+ // Apply rotation based on rounded value
822
+ switch (rounded % 360) {
823
+ case 90:
824
+ return this.rotate90();
825
+ case 180:
826
+ return this.rotate180();
827
+ case 270:
828
+ return this.rotate270();
829
+ default:
830
+ // 0 or 360 degrees - no rotation needed
831
+ return this;
832
+ }
833
+ }
834
+ /**
835
+ * Flip the image horizontally (mirror)
836
+ * @returns This image instance for chaining
837
+ */
838
+ flipHorizontal() {
839
+ if (!this.imageData)
840
+ throw new Error("No image loaded");
841
+ this.imageData.data = (0, image_processing_js_1.flipHorizontal)(this.imageData.data, this.imageData.width, this.imageData.height);
842
+ return this;
843
+ }
844
+ /**
845
+ * Flip the image vertically
846
+ * @returns This image instance for chaining
847
+ */
848
+ flipVertical() {
849
+ if (!this.imageData)
850
+ throw new Error("No image loaded");
851
+ this.imageData.data = (0, image_processing_js_1.flipVertical)(this.imageData.data, this.imageData.width, this.imageData.height);
852
+ return this;
853
+ }
608
854
  }
609
855
  exports.Image = Image;
610
856
  Object.defineProperty(Image, "formats", {
@@ -625,5 +871,7 @@ Object.defineProperty(Image, "formats", {
625
871
  new pcx_js_1.PCXFormat(),
626
872
  new ppm_js_1.PPMFormat(),
627
873
  new ascii_js_1.ASCIIFormat(),
874
+ new heic_js_1.HEICFormat(),
875
+ new avif_js_1.AVIFFormat(),
628
876
  ]
629
877
  });
@@ -24,6 +24,42 @@ export interface ImageMetadata {
24
24
  copyright?: string;
25
25
  /** Creation date */
26
26
  creationDate?: Date;
27
+ /** Camera make/manufacturer (e.g., "Canon", "Nikon") */
28
+ cameraMake?: string;
29
+ /** Camera model (e.g., "Canon EOS 5D Mark IV") */
30
+ cameraModel?: string;
31
+ /** Lens make/manufacturer */
32
+ lensMake?: string;
33
+ /** Lens model */
34
+ lensModel?: string;
35
+ /** ISO speed rating (e.g., 100, 400, 3200) */
36
+ iso?: number;
37
+ /** Exposure time / Shutter speed in seconds (e.g., 0.0125 = 1/80s) */
38
+ exposureTime?: number;
39
+ /** F-number / Aperture (e.g., 2.8, 5.6, 16) */
40
+ fNumber?: number;
41
+ /** Focal length in millimeters (e.g., 50, 85, 200) */
42
+ focalLength?: number;
43
+ /** Flash mode (0 = no flash, 1 = flash fired) */
44
+ flash?: number;
45
+ /** White balance mode (0 = auto, 1 = manual) */
46
+ whiteBalance?: number;
47
+ /** Orientation (1 = normal, 3 = 180°, 6 = 90° CW, 8 = 90° CCW) */
48
+ orientation?: number;
49
+ /** Software used to create/edit the image */
50
+ software?: string;
51
+ /** User comment / notes */
52
+ userComment?: string;
53
+ /** Image file format (e.g., "png", "jpeg", "gif", "webp", "tiff") */
54
+ format?: string;
55
+ /** Compression algorithm used (e.g., "deflate", "lzw", "dct", "vp8", "vp8l", "none") */
56
+ compression?: string;
57
+ /** Number of frames in multi-frame images (e.g., animated GIFs, APNGs, multi-page TIFFs) */
58
+ frameCount?: number;
59
+ /** Bit depth per channel (e.g., 8, 16) */
60
+ bitDepth?: number;
61
+ /** Color type (e.g., "grayscale", "rgb", "rgba", "indexed", "grayscale-alpha") */
62
+ colorType?: string;
27
63
  /** Custom metadata fields */
28
64
  custom?: Record<string, string | number | boolean>;
29
65
  }
@@ -88,7 +124,16 @@ export interface ResizeOptions {
88
124
  /** Target height in pixels */
89
125
  height: number;
90
126
  /** Resize method (default: "bilinear") */
91
- method?: "nearest" | "bilinear";
127
+ method?: "nearest" | "bilinear" | "bicubic";
128
+ /**
129
+ * Fitting mode (default: "stretch")
130
+ * - "stretch": Stretch image to fill dimensions (may distort)
131
+ * - "fit": Fit image within dimensions maintaining aspect ratio (may have letterboxing)
132
+ * - "fill": Fill dimensions maintaining aspect ratio (may crop)
133
+ * - "cover": Alias for "fill"
134
+ * - "contain": Alias for "fit"
135
+ */
136
+ fit?: "stretch" | "fit" | "fill" | "cover" | "contain";
92
137
  }
93
138
  /**
94
139
  * Options for ASCII art encoding
@@ -163,5 +208,18 @@ export interface ImageFormat {
163
208
  * Check if the format supports multiple frames
164
209
  */
165
210
  supportsMultipleFrames?(): boolean;
211
+ /**
212
+ * Get the list of metadata fields supported by this format
213
+ * @returns Array of metadata field names that can be persisted
214
+ */
215
+ getSupportedMetadata?(): Array<keyof ImageMetadata>;
216
+ /**
217
+ * Extract metadata from image data without fully decoding the pixel data
218
+ * This is useful for quickly reading EXIF, XMP, or other metadata from images
219
+ * that may have unsupported features or compression methods
220
+ * @param data Raw image data
221
+ * @returns Metadata extracted from the image, or undefined if extraction fails
222
+ */
223
+ extractMetadata?(data: Uint8Array): Promise<ImageMetadata | undefined>;
166
224
  }
167
225
  //# sourceMappingURL=types.d.ts.map
@@ -44,6 +44,13 @@ export declare function adjustExposure(data: Uint8Array, amount: number): Uint8A
44
44
  * @returns New image data with adjusted saturation
45
45
  */
46
46
  export declare function adjustSaturation(data: Uint8Array, amount: number): Uint8Array;
47
+ /**
48
+ * Adjust hue of an image by rotating the hue wheel
49
+ * @param data Image data (RGBA)
50
+ * @param degrees Hue rotation in degrees (any value accepted, wraps at 360)
51
+ * @returns New image data with adjusted hue
52
+ */
53
+ export declare function adjustHue(data: Uint8Array, degrees: number): Uint8Array;
47
54
  /**
48
55
  * Invert colors of an image
49
56
  * @param data Image data (RGBA)
@@ -131,4 +138,52 @@ export declare function sepia(data: Uint8Array): Uint8Array;
131
138
  * @returns New image data with median filter applied
132
139
  */
133
140
  export declare function medianFilter(data: Uint8Array, width: number, height: number, radius?: number): Uint8Array;
141
+ /**
142
+ * Rotate image 90 degrees clockwise
143
+ * @param data Image data (RGBA)
144
+ * @param width Image width
145
+ * @param height Image height
146
+ * @returns Rotated image data with swapped dimensions
147
+ */
148
+ export declare function rotate90(data: Uint8Array, width: number, height: number): {
149
+ data: Uint8Array;
150
+ width: number;
151
+ height: number;
152
+ };
153
+ /**
154
+ * Rotate image 180 degrees
155
+ * @param data Image data (RGBA)
156
+ * @param width Image width
157
+ * @param height Image height
158
+ * @returns Rotated image data with same dimensions
159
+ */
160
+ export declare function rotate180(data: Uint8Array, width: number, height: number): Uint8Array;
161
+ /**
162
+ * Rotate image 270 degrees clockwise (or 90 degrees counter-clockwise)
163
+ * @param data Image data (RGBA)
164
+ * @param width Image width
165
+ * @param height Image height
166
+ * @returns Rotated image data with swapped dimensions
167
+ */
168
+ export declare function rotate270(data: Uint8Array, width: number, height: number): {
169
+ data: Uint8Array;
170
+ width: number;
171
+ height: number;
172
+ };
173
+ /**
174
+ * Flip image horizontally (mirror)
175
+ * @param data Image data (RGBA)
176
+ * @param width Image width
177
+ * @param height Image height
178
+ * @returns Flipped image data
179
+ */
180
+ export declare function flipHorizontal(data: Uint8Array, width: number, height: number): Uint8Array;
181
+ /**
182
+ * Flip image vertically
183
+ * @param data Image data (RGBA)
184
+ * @param width Image width
185
+ * @param height Image height
186
+ * @returns Flipped image data
187
+ */
188
+ export declare function flipVertical(data: Uint8Array, width: number, height: number): Uint8Array;
134
189
  //# sourceMappingURL=image_processing.d.ts.map