cross-image 0.2.1 → 0.2.3
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/README.md +160 -32
- package/esm/mod.d.ts +2 -1
- package/esm/mod.js +2 -1
- package/esm/src/formats/jpeg.d.ts +12 -1
- package/esm/src/formats/jpeg.js +633 -4
- package/esm/src/formats/png_base.d.ts +8 -0
- package/esm/src/formats/png_base.js +176 -3
- package/esm/src/formats/ppm.d.ts +50 -0
- package/esm/src/formats/ppm.js +242 -0
- package/esm/src/formats/tiff.d.ts +10 -1
- package/esm/src/formats/tiff.js +194 -44
- package/esm/src/formats/webp.d.ts +9 -2
- package/esm/src/formats/webp.js +211 -62
- package/esm/src/image.d.ts +81 -0
- package/esm/src/image.js +282 -5
- package/esm/src/types.d.ts +41 -1
- package/esm/src/utils/image_processing.d.ts +98 -0
- package/esm/src/utils/image_processing.js +440 -0
- package/esm/src/utils/metadata/xmp.d.ts +52 -0
- package/esm/src/utils/metadata/xmp.js +325 -0
- package/esm/src/utils/resize.d.ts +4 -0
- package/esm/src/utils/resize.js +74 -0
- package/package.json +1 -1
- package/script/mod.d.ts +2 -1
- package/script/mod.js +4 -2
- package/script/src/formats/jpeg.d.ts +12 -1
- package/script/src/formats/jpeg.js +633 -4
- package/script/src/formats/png_base.d.ts +8 -0
- package/script/src/formats/png_base.js +176 -3
- package/script/src/formats/ppm.d.ts +50 -0
- package/script/src/formats/ppm.js +246 -0
- package/script/src/formats/tiff.d.ts +10 -1
- package/script/src/formats/tiff.js +194 -44
- package/script/src/formats/webp.d.ts +9 -2
- package/script/src/formats/webp.js +211 -62
- package/script/src/image.d.ts +81 -0
- package/script/src/image.js +280 -3
- package/script/src/types.d.ts +41 -1
- package/script/src/utils/image_processing.d.ts +98 -0
- package/script/src/utils/image_processing.js +451 -0
- package/script/src/utils/metadata/xmp.d.ts +52 -0
- package/script/src/utils/metadata/xmp.js +333 -0
- package/script/src/utils/resize.d.ts +4 -0
- package/script/src/utils/resize.js +75 -0
package/esm/src/image.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { resizeBilinear, resizeNearest } from "./utils/resize.js";
|
|
2
|
-
import { adjustBrightness, adjustContrast, adjustExposure, adjustSaturation, composite, crop, fillRect, grayscale, invert, } from "./utils/image_processing.js";
|
|
1
|
+
import { resizeBicubic, resizeBilinear, resizeNearest, } from "./utils/resize.js";
|
|
2
|
+
import { adjustBrightness, adjustContrast, adjustExposure, adjustHue, adjustSaturation, boxBlur, composite, crop, fillRect, flipHorizontal, flipVertical, gaussianBlur, grayscale, invert, medianFilter, rotate180, rotate270, rotate90, sepia, sharpen, } from "./utils/image_processing.js";
|
|
3
3
|
import { PNGFormat } from "./formats/png.js";
|
|
4
4
|
import { APNGFormat } from "./formats/apng.js";
|
|
5
5
|
import { JPEGFormat } from "./formats/jpeg.js";
|
|
@@ -11,6 +11,7 @@ import { ICOFormat } from "./formats/ico.js";
|
|
|
11
11
|
import { DNGFormat } from "./formats/dng.js";
|
|
12
12
|
import { PAMFormat } from "./formats/pam.js";
|
|
13
13
|
import { PCXFormat } from "./formats/pcx.js";
|
|
14
|
+
import { PPMFormat } from "./formats/ppm.js";
|
|
14
15
|
import { ASCIIFormat } from "./formats/ascii.js";
|
|
15
16
|
import { validateImageDimensions } from "./utils/security.js";
|
|
16
17
|
/**
|
|
@@ -180,6 +181,18 @@ export class Image {
|
|
|
180
181
|
}
|
|
181
182
|
throw new Error("Unsupported or unrecognized image format");
|
|
182
183
|
}
|
|
184
|
+
/**
|
|
185
|
+
* Get supported metadata fields for a specific format
|
|
186
|
+
* @param format Format name (e.g., "jpeg", "png", "webp")
|
|
187
|
+
* @returns Array of supported metadata field names, or undefined if format doesn't support metadata
|
|
188
|
+
*/
|
|
189
|
+
static getSupportedMetadata(format) {
|
|
190
|
+
const formatHandler = Image.formats.find((f) => f.name === format.toLowerCase());
|
|
191
|
+
if (!formatHandler) {
|
|
192
|
+
throw new Error(`Unknown image format: ${format}`);
|
|
193
|
+
}
|
|
194
|
+
return formatHandler.getSupportedMetadata?.();
|
|
195
|
+
}
|
|
183
196
|
/**
|
|
184
197
|
* Read an image from bytes
|
|
185
198
|
* @deprecated Use `decode()` instead. This method will be removed in a future version.
|
|
@@ -300,19 +313,98 @@ export class Image {
|
|
|
300
313
|
resize(options) {
|
|
301
314
|
if (!this.imageData)
|
|
302
315
|
throw new Error("No image loaded");
|
|
303
|
-
const { width, height, method = "bilinear" } = options;
|
|
316
|
+
const { width, height, method = "bilinear", fit = "stretch" } = options;
|
|
304
317
|
// Validate new dimensions for security (prevent integer overflow and heap exhaustion)
|
|
305
318
|
validateImageDimensions(width, height);
|
|
306
319
|
const { data: srcData, width: srcWidth, height: srcHeight } = this.imageData;
|
|
320
|
+
// Handle fitting modes
|
|
321
|
+
let targetWidth = width;
|
|
322
|
+
let targetHeight = height;
|
|
323
|
+
let shouldCenter = false;
|
|
324
|
+
const fitMode = fit === "contain" ? "fit" : fit === "cover" ? "fill" : fit;
|
|
325
|
+
if (fitMode === "fit" || fitMode === "fill") {
|
|
326
|
+
const srcAspect = srcWidth / srcHeight;
|
|
327
|
+
const targetAspect = width / height;
|
|
328
|
+
if (fitMode === "fit") {
|
|
329
|
+
// Fit within dimensions (letterbox)
|
|
330
|
+
if (srcAspect > targetAspect) {
|
|
331
|
+
// Source is wider - fit to width
|
|
332
|
+
targetWidth = width;
|
|
333
|
+
targetHeight = Math.round(width / srcAspect);
|
|
334
|
+
}
|
|
335
|
+
else {
|
|
336
|
+
// Source is taller - fit to height
|
|
337
|
+
targetWidth = Math.round(height * srcAspect);
|
|
338
|
+
targetHeight = height;
|
|
339
|
+
}
|
|
340
|
+
shouldCenter = true;
|
|
341
|
+
}
|
|
342
|
+
else {
|
|
343
|
+
// Fill dimensions (crop)
|
|
344
|
+
if (srcAspect > targetAspect) {
|
|
345
|
+
// Source is wider - fit to height and crop width
|
|
346
|
+
targetWidth = Math.round(height * srcAspect);
|
|
347
|
+
targetHeight = height;
|
|
348
|
+
}
|
|
349
|
+
else {
|
|
350
|
+
// Source is taller - fit to width and crop height
|
|
351
|
+
targetWidth = width;
|
|
352
|
+
targetHeight = Math.round(width / srcAspect);
|
|
353
|
+
}
|
|
354
|
+
shouldCenter = true;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
// Perform the resize
|
|
307
358
|
let resizedData;
|
|
308
359
|
if (method === "nearest") {
|
|
309
|
-
resizedData = resizeNearest(srcData, srcWidth, srcHeight,
|
|
360
|
+
resizedData = resizeNearest(srcData, srcWidth, srcHeight, targetWidth, targetHeight);
|
|
361
|
+
}
|
|
362
|
+
else if (method === "bicubic") {
|
|
363
|
+
resizedData = resizeBicubic(srcData, srcWidth, srcHeight, targetWidth, targetHeight);
|
|
310
364
|
}
|
|
311
365
|
else {
|
|
312
|
-
resizedData = resizeBilinear(srcData, srcWidth, srcHeight,
|
|
366
|
+
resizedData = resizeBilinear(srcData, srcWidth, srcHeight, targetWidth, targetHeight);
|
|
313
367
|
}
|
|
314
368
|
// Preserve metadata when resizing
|
|
315
369
|
const metadata = this.imageData.metadata;
|
|
370
|
+
// If we need to center (fit mode) or crop (fill mode), create a canvas
|
|
371
|
+
if (shouldCenter && (targetWidth !== width || targetHeight !== height)) {
|
|
372
|
+
const canvas = new Uint8Array(width * height * 4);
|
|
373
|
+
// Fill with transparent black by default
|
|
374
|
+
canvas.fill(0);
|
|
375
|
+
if (fitMode === "fit") {
|
|
376
|
+
// Center the resized image (letterbox)
|
|
377
|
+
const offsetX = Math.floor((width - targetWidth) / 2);
|
|
378
|
+
const offsetY = Math.floor((height - targetHeight) / 2);
|
|
379
|
+
for (let y = 0; y < targetHeight; y++) {
|
|
380
|
+
for (let x = 0; x < targetWidth; x++) {
|
|
381
|
+
const srcIdx = (y * targetWidth + x) * 4;
|
|
382
|
+
const dstIdx = ((y + offsetY) * width + (x + offsetX)) * 4;
|
|
383
|
+
canvas[dstIdx] = resizedData[srcIdx];
|
|
384
|
+
canvas[dstIdx + 1] = resizedData[srcIdx + 1];
|
|
385
|
+
canvas[dstIdx + 2] = resizedData[srcIdx + 2];
|
|
386
|
+
canvas[dstIdx + 3] = resizedData[srcIdx + 3];
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
resizedData = canvas;
|
|
390
|
+
}
|
|
391
|
+
else {
|
|
392
|
+
// Crop to fill (center crop)
|
|
393
|
+
const offsetX = Math.floor((targetWidth - width) / 2);
|
|
394
|
+
const offsetY = Math.floor((targetHeight - height) / 2);
|
|
395
|
+
for (let y = 0; y < height; y++) {
|
|
396
|
+
for (let x = 0; x < width; x++) {
|
|
397
|
+
const srcIdx = ((y + offsetY) * targetWidth + (x + offsetX)) * 4;
|
|
398
|
+
const dstIdx = (y * width + x) * 4;
|
|
399
|
+
canvas[dstIdx] = resizedData[srcIdx];
|
|
400
|
+
canvas[dstIdx + 1] = resizedData[srcIdx + 1];
|
|
401
|
+
canvas[dstIdx + 2] = resizedData[srcIdx + 2];
|
|
402
|
+
canvas[dstIdx + 3] = resizedData[srcIdx + 3];
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
resizedData = canvas;
|
|
406
|
+
}
|
|
407
|
+
}
|
|
316
408
|
this.imageData = {
|
|
317
409
|
width,
|
|
318
410
|
height,
|
|
@@ -438,6 +530,17 @@ export class Image {
|
|
|
438
530
|
this.imageData.data = adjustSaturation(this.imageData.data, amount);
|
|
439
531
|
return this;
|
|
440
532
|
}
|
|
533
|
+
/**
|
|
534
|
+
* Adjust hue of the image by rotating the color wheel
|
|
535
|
+
* @param degrees Hue rotation in degrees (any value accepted, wraps at 360)
|
|
536
|
+
* @returns This image instance for chaining
|
|
537
|
+
*/
|
|
538
|
+
hue(degrees) {
|
|
539
|
+
if (!this.imageData)
|
|
540
|
+
throw new Error("No image loaded");
|
|
541
|
+
this.imageData.data = adjustHue(this.imageData.data, degrees);
|
|
542
|
+
return this;
|
|
543
|
+
}
|
|
441
544
|
/**
|
|
442
545
|
* Invert colors of the image
|
|
443
546
|
* @returns This image instance for chaining
|
|
@@ -458,6 +561,61 @@ export class Image {
|
|
|
458
561
|
this.imageData.data = grayscale(this.imageData.data);
|
|
459
562
|
return this;
|
|
460
563
|
}
|
|
564
|
+
/**
|
|
565
|
+
* Apply sepia tone effect to the image
|
|
566
|
+
* @returns This image instance for chaining
|
|
567
|
+
*/
|
|
568
|
+
sepia() {
|
|
569
|
+
if (!this.imageData)
|
|
570
|
+
throw new Error("No image loaded");
|
|
571
|
+
this.imageData.data = sepia(this.imageData.data);
|
|
572
|
+
return this;
|
|
573
|
+
}
|
|
574
|
+
/**
|
|
575
|
+
* Apply box blur filter to the image
|
|
576
|
+
* @param radius Blur radius (default: 1)
|
|
577
|
+
* @returns This image instance for chaining
|
|
578
|
+
*/
|
|
579
|
+
blur(radius = 1) {
|
|
580
|
+
if (!this.imageData)
|
|
581
|
+
throw new Error("No image loaded");
|
|
582
|
+
this.imageData.data = boxBlur(this.imageData.data, this.imageData.width, this.imageData.height, radius);
|
|
583
|
+
return this;
|
|
584
|
+
}
|
|
585
|
+
/**
|
|
586
|
+
* Apply Gaussian blur filter to the image
|
|
587
|
+
* @param radius Blur radius (default: 1)
|
|
588
|
+
* @param sigma Optional standard deviation (if not provided, calculated from radius)
|
|
589
|
+
* @returns This image instance for chaining
|
|
590
|
+
*/
|
|
591
|
+
gaussianBlur(radius = 1, sigma) {
|
|
592
|
+
if (!this.imageData)
|
|
593
|
+
throw new Error("No image loaded");
|
|
594
|
+
this.imageData.data = gaussianBlur(this.imageData.data, this.imageData.width, this.imageData.height, radius, sigma);
|
|
595
|
+
return this;
|
|
596
|
+
}
|
|
597
|
+
/**
|
|
598
|
+
* Apply sharpen filter to the image
|
|
599
|
+
* @param amount Sharpening amount (0-1, default: 0.5)
|
|
600
|
+
* @returns This image instance for chaining
|
|
601
|
+
*/
|
|
602
|
+
sharpen(amount = 0.5) {
|
|
603
|
+
if (!this.imageData)
|
|
604
|
+
throw new Error("No image loaded");
|
|
605
|
+
this.imageData.data = sharpen(this.imageData.data, this.imageData.width, this.imageData.height, amount);
|
|
606
|
+
return this;
|
|
607
|
+
}
|
|
608
|
+
/**
|
|
609
|
+
* Apply median filter to reduce noise
|
|
610
|
+
* @param radius Filter radius (default: 1)
|
|
611
|
+
* @returns This image instance for chaining
|
|
612
|
+
*/
|
|
613
|
+
medianFilter(radius = 1) {
|
|
614
|
+
if (!this.imageData)
|
|
615
|
+
throw new Error("No image loaded");
|
|
616
|
+
this.imageData.data = medianFilter(this.imageData.data, this.imageData.width, this.imageData.height, radius);
|
|
617
|
+
return this;
|
|
618
|
+
}
|
|
461
619
|
/**
|
|
462
620
|
* Fill a rectangular region with a color
|
|
463
621
|
* @param x Starting X position
|
|
@@ -546,6 +704,124 @@ export class Image {
|
|
|
546
704
|
this.imageData.data[idx + 3] = a;
|
|
547
705
|
return this;
|
|
548
706
|
}
|
|
707
|
+
/**
|
|
708
|
+
* Rotate the image 90 degrees clockwise
|
|
709
|
+
* @returns This image instance for chaining
|
|
710
|
+
*/
|
|
711
|
+
rotate90() {
|
|
712
|
+
if (!this.imageData)
|
|
713
|
+
throw new Error("No image loaded");
|
|
714
|
+
const result = rotate90(this.imageData.data, this.imageData.width, this.imageData.height);
|
|
715
|
+
this.imageData.width = result.width;
|
|
716
|
+
this.imageData.height = result.height;
|
|
717
|
+
this.imageData.data = result.data;
|
|
718
|
+
// Update physical dimensions if DPI is set
|
|
719
|
+
if (this.imageData.metadata) {
|
|
720
|
+
const metadata = this.imageData.metadata;
|
|
721
|
+
if (metadata.dpiX && metadata.dpiY) {
|
|
722
|
+
// Swap physical dimensions
|
|
723
|
+
const tempPhysical = metadata.physicalWidth;
|
|
724
|
+
this.imageData.metadata.physicalWidth = metadata.physicalHeight;
|
|
725
|
+
this.imageData.metadata.physicalHeight = tempPhysical;
|
|
726
|
+
// Swap DPI
|
|
727
|
+
const tempDpi = metadata.dpiX;
|
|
728
|
+
this.imageData.metadata.dpiX = metadata.dpiY;
|
|
729
|
+
this.imageData.metadata.dpiY = tempDpi;
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
return this;
|
|
733
|
+
}
|
|
734
|
+
/**
|
|
735
|
+
* Rotate the image 180 degrees
|
|
736
|
+
* @returns This image instance for chaining
|
|
737
|
+
*/
|
|
738
|
+
rotate180() {
|
|
739
|
+
if (!this.imageData)
|
|
740
|
+
throw new Error("No image loaded");
|
|
741
|
+
this.imageData.data = rotate180(this.imageData.data, this.imageData.width, this.imageData.height);
|
|
742
|
+
return this;
|
|
743
|
+
}
|
|
744
|
+
/**
|
|
745
|
+
* Rotate the image 270 degrees clockwise (or 90 degrees counter-clockwise)
|
|
746
|
+
* @returns This image instance for chaining
|
|
747
|
+
*/
|
|
748
|
+
rotate270() {
|
|
749
|
+
if (!this.imageData)
|
|
750
|
+
throw new Error("No image loaded");
|
|
751
|
+
const result = rotate270(this.imageData.data, this.imageData.width, this.imageData.height);
|
|
752
|
+
this.imageData.width = result.width;
|
|
753
|
+
this.imageData.height = result.height;
|
|
754
|
+
this.imageData.data = result.data;
|
|
755
|
+
// Update physical dimensions if DPI is set
|
|
756
|
+
if (this.imageData.metadata) {
|
|
757
|
+
const metadata = this.imageData.metadata;
|
|
758
|
+
if (metadata.dpiX && metadata.dpiY) {
|
|
759
|
+
// Swap physical dimensions
|
|
760
|
+
const tempPhysical = metadata.physicalWidth;
|
|
761
|
+
this.imageData.metadata.physicalWidth = metadata.physicalHeight;
|
|
762
|
+
this.imageData.metadata.physicalHeight = tempPhysical;
|
|
763
|
+
// Swap DPI
|
|
764
|
+
const tempDpi = metadata.dpiX;
|
|
765
|
+
this.imageData.metadata.dpiX = metadata.dpiY;
|
|
766
|
+
this.imageData.metadata.dpiY = tempDpi;
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
return this;
|
|
770
|
+
}
|
|
771
|
+
/**
|
|
772
|
+
* Rotate the image by the specified angle in degrees
|
|
773
|
+
* @param degrees Rotation angle in degrees (positive = clockwise, negative = counter-clockwise)
|
|
774
|
+
* @returns This image instance for chaining
|
|
775
|
+
*
|
|
776
|
+
* @example
|
|
777
|
+
* ```ts
|
|
778
|
+
* image.rotate(90); // Rotate 90° clockwise
|
|
779
|
+
* image.rotate(-90); // Rotate 90° counter-clockwise
|
|
780
|
+
* image.rotate(180); // Rotate 180°
|
|
781
|
+
* image.rotate(45); // Rotate 45° clockwise (rounded to nearest 90°)
|
|
782
|
+
* ```
|
|
783
|
+
*/
|
|
784
|
+
rotate(degrees) {
|
|
785
|
+
// Normalize to 0-360 range
|
|
786
|
+
let normalizedDegrees = degrees % 360;
|
|
787
|
+
if (normalizedDegrees < 0) {
|
|
788
|
+
normalizedDegrees += 360;
|
|
789
|
+
}
|
|
790
|
+
// Round to nearest 90 degrees
|
|
791
|
+
const rounded = Math.round(normalizedDegrees / 90) * 90;
|
|
792
|
+
// Apply rotation based on rounded value
|
|
793
|
+
switch (rounded % 360) {
|
|
794
|
+
case 90:
|
|
795
|
+
return this.rotate90();
|
|
796
|
+
case 180:
|
|
797
|
+
return this.rotate180();
|
|
798
|
+
case 270:
|
|
799
|
+
return this.rotate270();
|
|
800
|
+
default:
|
|
801
|
+
// 0 or 360 degrees - no rotation needed
|
|
802
|
+
return this;
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
/**
|
|
806
|
+
* Flip the image horizontally (mirror)
|
|
807
|
+
* @returns This image instance for chaining
|
|
808
|
+
*/
|
|
809
|
+
flipHorizontal() {
|
|
810
|
+
if (!this.imageData)
|
|
811
|
+
throw new Error("No image loaded");
|
|
812
|
+
this.imageData.data = flipHorizontal(this.imageData.data, this.imageData.width, this.imageData.height);
|
|
813
|
+
return this;
|
|
814
|
+
}
|
|
815
|
+
/**
|
|
816
|
+
* Flip the image vertically
|
|
817
|
+
* @returns This image instance for chaining
|
|
818
|
+
*/
|
|
819
|
+
flipVertical() {
|
|
820
|
+
if (!this.imageData)
|
|
821
|
+
throw new Error("No image loaded");
|
|
822
|
+
this.imageData.data = flipVertical(this.imageData.data, this.imageData.width, this.imageData.height);
|
|
823
|
+
return this;
|
|
824
|
+
}
|
|
549
825
|
}
|
|
550
826
|
Object.defineProperty(Image, "formats", {
|
|
551
827
|
enumerable: true,
|
|
@@ -563,6 +839,7 @@ Object.defineProperty(Image, "formats", {
|
|
|
563
839
|
new DNGFormat(),
|
|
564
840
|
new PAMFormat(),
|
|
565
841
|
new PCXFormat(),
|
|
842
|
+
new PPMFormat(),
|
|
566
843
|
new ASCIIFormat(),
|
|
567
844
|
]
|
|
568
845
|
});
|
package/esm/src/types.d.ts
CHANGED
|
@@ -24,6 +24,32 @@ 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;
|
|
27
53
|
/** Custom metadata fields */
|
|
28
54
|
custom?: Record<string, string | number | boolean>;
|
|
29
55
|
}
|
|
@@ -88,7 +114,16 @@ export interface ResizeOptions {
|
|
|
88
114
|
/** Target height in pixels */
|
|
89
115
|
height: number;
|
|
90
116
|
/** Resize method (default: "bilinear") */
|
|
91
|
-
method?: "nearest" | "bilinear";
|
|
117
|
+
method?: "nearest" | "bilinear" | "bicubic";
|
|
118
|
+
/**
|
|
119
|
+
* Fitting mode (default: "stretch")
|
|
120
|
+
* - "stretch": Stretch image to fill dimensions (may distort)
|
|
121
|
+
* - "fit": Fit image within dimensions maintaining aspect ratio (may have letterboxing)
|
|
122
|
+
* - "fill": Fill dimensions maintaining aspect ratio (may crop)
|
|
123
|
+
* - "cover": Alias for "fill"
|
|
124
|
+
* - "contain": Alias for "fit"
|
|
125
|
+
*/
|
|
126
|
+
fit?: "stretch" | "fit" | "fill" | "cover" | "contain";
|
|
92
127
|
}
|
|
93
128
|
/**
|
|
94
129
|
* Options for ASCII art encoding
|
|
@@ -163,5 +198,10 @@ export interface ImageFormat {
|
|
|
163
198
|
* Check if the format supports multiple frames
|
|
164
199
|
*/
|
|
165
200
|
supportsMultipleFrames?(): boolean;
|
|
201
|
+
/**
|
|
202
|
+
* Get the list of metadata fields supported by this format
|
|
203
|
+
* @returns Array of metadata field names that can be persisted
|
|
204
|
+
*/
|
|
205
|
+
getSupportedMetadata?(): Array<keyof ImageMetadata>;
|
|
166
206
|
}
|
|
167
207
|
//# 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)
|
|
@@ -88,4 +95,95 @@ export declare function crop(data: Uint8Array, width: number, height: number, x:
|
|
|
88
95
|
width: number;
|
|
89
96
|
height: number;
|
|
90
97
|
};
|
|
98
|
+
/**
|
|
99
|
+
* Apply a box blur filter to an image
|
|
100
|
+
* @param data Image data (RGBA)
|
|
101
|
+
* @param width Image width
|
|
102
|
+
* @param height Image height
|
|
103
|
+
* @param radius Blur radius (default: 1)
|
|
104
|
+
* @returns New image data with box blur applied
|
|
105
|
+
*/
|
|
106
|
+
export declare function boxBlur(data: Uint8Array, width: number, height: number, radius?: number): Uint8Array;
|
|
107
|
+
/**
|
|
108
|
+
* Apply Gaussian blur to an image
|
|
109
|
+
* @param data Image data (RGBA)
|
|
110
|
+
* @param width Image width
|
|
111
|
+
* @param height Image height
|
|
112
|
+
* @param radius Blur radius (default: 1)
|
|
113
|
+
* @param sigma Optional standard deviation (if not provided, calculated from radius)
|
|
114
|
+
* @returns New image data with Gaussian blur applied
|
|
115
|
+
*/
|
|
116
|
+
export declare function gaussianBlur(data: Uint8Array, width: number, height: number, radius?: number, sigma?: number): Uint8Array;
|
|
117
|
+
/**
|
|
118
|
+
* Apply sharpen filter to an image
|
|
119
|
+
* @param data Image data (RGBA)
|
|
120
|
+
* @param width Image width
|
|
121
|
+
* @param height Image height
|
|
122
|
+
* @param amount Sharpening amount (0-1, default: 0.5)
|
|
123
|
+
* @returns New image data with sharpening applied
|
|
124
|
+
*/
|
|
125
|
+
export declare function sharpen(data: Uint8Array, width: number, height: number, amount?: number): Uint8Array;
|
|
126
|
+
/**
|
|
127
|
+
* Apply sepia tone effect to an image
|
|
128
|
+
* @param data Image data (RGBA)
|
|
129
|
+
* @returns New image data with sepia tone applied
|
|
130
|
+
*/
|
|
131
|
+
export declare function sepia(data: Uint8Array): Uint8Array;
|
|
132
|
+
/**
|
|
133
|
+
* Apply median filter to reduce noise
|
|
134
|
+
* @param data Image data (RGBA)
|
|
135
|
+
* @param width Image width
|
|
136
|
+
* @param height Image height
|
|
137
|
+
* @param radius Filter radius (default: 1)
|
|
138
|
+
* @returns New image data with median filter applied
|
|
139
|
+
*/
|
|
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;
|
|
91
189
|
//# sourceMappingURL=image_processing.d.ts.map
|