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
@@ -9,6 +9,7 @@ exports.adjustBrightness = adjustBrightness;
9
9
  exports.adjustContrast = adjustContrast;
10
10
  exports.adjustExposure = adjustExposure;
11
11
  exports.adjustSaturation = adjustSaturation;
12
+ exports.adjustHue = adjustHue;
12
13
  exports.invert = invert;
13
14
  exports.grayscale = grayscale;
14
15
  exports.fillRect = fillRect;
@@ -18,6 +19,11 @@ exports.gaussianBlur = gaussianBlur;
18
19
  exports.sharpen = sharpen;
19
20
  exports.sepia = sepia;
20
21
  exports.medianFilter = medianFilter;
22
+ exports.rotate90 = rotate90;
23
+ exports.rotate180 = rotate180;
24
+ exports.rotate270 = rotate270;
25
+ exports.flipHorizontal = flipHorizontal;
26
+ exports.flipVertical = flipVertical;
21
27
  /**
22
28
  * Composite one image on top of another at a specified position
23
29
  * @param base Base image data (RGBA)
@@ -147,6 +153,99 @@ function adjustSaturation(data, amount) {
147
153
  }
148
154
  return result;
149
155
  }
156
+ /**
157
+ * Convert RGB to HSL color space
158
+ * @param r Red component (0-255)
159
+ * @param g Green component (0-255)
160
+ * @param b Blue component (0-255)
161
+ * @returns HSL values: [h (0-360), s (0-1), l (0-1)]
162
+ */
163
+ function rgbToHsl(r, g, b) {
164
+ r /= 255;
165
+ g /= 255;
166
+ b /= 255;
167
+ const max = Math.max(r, g, b);
168
+ const min = Math.min(r, g, b);
169
+ const delta = max - min;
170
+ let h = 0;
171
+ let s = 0;
172
+ const l = (max + min) / 2;
173
+ if (delta !== 0) {
174
+ s = l > 0.5 ? delta / (2 - max - min) : delta / (max + min);
175
+ if (max === r) {
176
+ h = ((g - b) / delta + (g < b ? 6 : 0)) / 6;
177
+ }
178
+ else if (max === g) {
179
+ h = ((b - r) / delta + 2) / 6;
180
+ }
181
+ else {
182
+ h = ((r - g) / delta + 4) / 6;
183
+ }
184
+ }
185
+ return [h * 360, s, l];
186
+ }
187
+ /**
188
+ * Convert HSL to RGB color space
189
+ * @param h Hue (0-360)
190
+ * @param s Saturation (0-1)
191
+ * @param l Lightness (0-1)
192
+ * @returns RGB values: [r (0-255), g (0-255), b (0-255)]
193
+ */
194
+ function hslToRgb(h, s, l) {
195
+ h = h / 360;
196
+ let r, g, b;
197
+ if (s === 0) {
198
+ r = g = b = l; // Achromatic
199
+ }
200
+ else {
201
+ const hue2rgb = (p, q, t) => {
202
+ if (t < 0)
203
+ t += 1;
204
+ if (t > 1)
205
+ t -= 1;
206
+ if (t < 1 / 6)
207
+ return p + (q - p) * 6 * t;
208
+ if (t < 1 / 2)
209
+ return q;
210
+ if (t < 2 / 3)
211
+ return p + (q - p) * (2 / 3 - t) * 6;
212
+ return p;
213
+ };
214
+ const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
215
+ const p = 2 * l - q;
216
+ r = hue2rgb(p, q, h + 1 / 3);
217
+ g = hue2rgb(p, q, h);
218
+ b = hue2rgb(p, q, h - 1 / 3);
219
+ }
220
+ return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
221
+ }
222
+ /**
223
+ * Adjust hue of an image by rotating the hue wheel
224
+ * @param data Image data (RGBA)
225
+ * @param degrees Hue rotation in degrees (any value accepted, wraps at 360)
226
+ * @returns New image data with adjusted hue
227
+ */
228
+ function adjustHue(data, degrees) {
229
+ const result = new Uint8Array(data.length);
230
+ // Normalize rotation to -180 to 180 range
231
+ const rotation = ((degrees % 360) + 360) % 360;
232
+ for (let i = 0; i < data.length; i += 4) {
233
+ const r = data[i];
234
+ const g = data[i + 1];
235
+ const b = data[i + 2];
236
+ // Convert to HSL
237
+ const [h, s, l] = rgbToHsl(r, g, b);
238
+ // Rotate hue
239
+ const newH = (h + rotation) % 360;
240
+ // Convert back to RGB
241
+ const [newR, newG, newB] = hslToRgb(newH, s, l);
242
+ result[i] = newR;
243
+ result[i + 1] = newG;
244
+ result[i + 2] = newB;
245
+ result[i + 3] = data[i + 3]; // Preserve alpha
246
+ }
247
+ return result;
248
+ }
150
249
  /**
151
250
  * Invert colors of an image
152
251
  * @param data Image data (RGBA)
@@ -475,3 +574,120 @@ function medianFilter(data, width, height, radius = 1) {
475
574
  }
476
575
  return result;
477
576
  }
577
+ /**
578
+ * Rotate image 90 degrees clockwise
579
+ * @param data Image data (RGBA)
580
+ * @param width Image width
581
+ * @param height Image height
582
+ * @returns Rotated image data with swapped dimensions
583
+ */
584
+ function rotate90(data, width, height) {
585
+ const result = new Uint8Array(data.length);
586
+ const newWidth = height;
587
+ const newHeight = width;
588
+ for (let y = 0; y < height; y++) {
589
+ for (let x = 0; x < width; x++) {
590
+ const srcIdx = (y * width + x) * 4;
591
+ const dstX = height - 1 - y;
592
+ const dstY = x;
593
+ const dstIdx = (dstY * newWidth + dstX) * 4;
594
+ result[dstIdx] = data[srcIdx];
595
+ result[dstIdx + 1] = data[srcIdx + 1];
596
+ result[dstIdx + 2] = data[srcIdx + 2];
597
+ result[dstIdx + 3] = data[srcIdx + 3];
598
+ }
599
+ }
600
+ return { data: result, width: newWidth, height: newHeight };
601
+ }
602
+ /**
603
+ * Rotate image 180 degrees
604
+ * @param data Image data (RGBA)
605
+ * @param width Image width
606
+ * @param height Image height
607
+ * @returns Rotated image data with same dimensions
608
+ */
609
+ function rotate180(data, width, height) {
610
+ const result = new Uint8Array(data.length);
611
+ for (let y = 0; y < height; y++) {
612
+ for (let x = 0; x < width; x++) {
613
+ const srcIdx = (y * width + x) * 4;
614
+ const dstX = width - 1 - x;
615
+ const dstY = height - 1 - y;
616
+ const dstIdx = (dstY * width + dstX) * 4;
617
+ result[dstIdx] = data[srcIdx];
618
+ result[dstIdx + 1] = data[srcIdx + 1];
619
+ result[dstIdx + 2] = data[srcIdx + 2];
620
+ result[dstIdx + 3] = data[srcIdx + 3];
621
+ }
622
+ }
623
+ return result;
624
+ }
625
+ /**
626
+ * Rotate image 270 degrees clockwise (or 90 degrees counter-clockwise)
627
+ * @param data Image data (RGBA)
628
+ * @param width Image width
629
+ * @param height Image height
630
+ * @returns Rotated image data with swapped dimensions
631
+ */
632
+ function rotate270(data, width, height) {
633
+ const result = new Uint8Array(data.length);
634
+ const newWidth = height;
635
+ const newHeight = width;
636
+ for (let y = 0; y < height; y++) {
637
+ for (let x = 0; x < width; x++) {
638
+ const srcIdx = (y * width + x) * 4;
639
+ const dstX = y;
640
+ const dstY = width - 1 - x;
641
+ const dstIdx = (dstY * newWidth + dstX) * 4;
642
+ result[dstIdx] = data[srcIdx];
643
+ result[dstIdx + 1] = data[srcIdx + 1];
644
+ result[dstIdx + 2] = data[srcIdx + 2];
645
+ result[dstIdx + 3] = data[srcIdx + 3];
646
+ }
647
+ }
648
+ return { data: result, width: newWidth, height: newHeight };
649
+ }
650
+ /**
651
+ * Flip image horizontally (mirror)
652
+ * @param data Image data (RGBA)
653
+ * @param width Image width
654
+ * @param height Image height
655
+ * @returns Flipped image data
656
+ */
657
+ function flipHorizontal(data, width, height) {
658
+ const result = new Uint8Array(data.length);
659
+ for (let y = 0; y < height; y++) {
660
+ for (let x = 0; x < width; x++) {
661
+ const srcIdx = (y * width + x) * 4;
662
+ const dstX = width - 1 - x;
663
+ const dstIdx = (y * width + dstX) * 4;
664
+ result[dstIdx] = data[srcIdx];
665
+ result[dstIdx + 1] = data[srcIdx + 1];
666
+ result[dstIdx + 2] = data[srcIdx + 2];
667
+ result[dstIdx + 3] = data[srcIdx + 3];
668
+ }
669
+ }
670
+ return result;
671
+ }
672
+ /**
673
+ * Flip image vertically
674
+ * @param data Image data (RGBA)
675
+ * @param width Image width
676
+ * @param height Image height
677
+ * @returns Flipped image data
678
+ */
679
+ function flipVertical(data, width, height) {
680
+ const result = new Uint8Array(data.length);
681
+ for (let y = 0; y < height; y++) {
682
+ for (let x = 0; x < width; x++) {
683
+ const srcIdx = (y * width + x) * 4;
684
+ const dstY = height - 1 - y;
685
+ const dstIdx = (dstY * width + x) * 4;
686
+ result[dstIdx] = data[srcIdx];
687
+ result[dstIdx + 1] = data[srcIdx + 1];
688
+ result[dstIdx + 2] = data[srcIdx + 2];
689
+ result[dstIdx + 3] = data[srcIdx + 3];
690
+ }
691
+ }
692
+ return result;
693
+ }
@@ -0,0 +1,52 @@
1
+ /**
2
+ * XMP (Extensible Metadata Platform) parsing and writing utilities
3
+ *
4
+ * This module provides utilities for reading and writing XMP metadata in image files.
5
+ * It supports Dublin Core, EXIF, and Photoshop namespaces.
6
+ */
7
+ import type { ImageMetadata } from "../../types.js";
8
+ /**
9
+ * XMP namespace URIs
10
+ */
11
+ export declare const XMP_NAMESPACES: {
12
+ readonly RDF: "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
13
+ readonly DC: "http://purl.org/dc/elements/1.1/";
14
+ readonly XMP: "http://ns.adobe.com/xap/1.0/";
15
+ readonly EXIF: "http://ns.adobe.com/exif/1.0/";
16
+ readonly TIFF: "http://ns.adobe.com/tiff/1.0/";
17
+ readonly PHOTOSHOP: "http://ns.adobe.com/photoshop/1.0/";
18
+ readonly XMP_RIGHTS: "http://ns.adobe.com/xap/1.0/rights/";
19
+ };
20
+ /**
21
+ * XMP Dublin Core field mapping to ImageMetadata
22
+ */
23
+ export interface XMPFieldMapping {
24
+ xmpPath: string;
25
+ metadataKey: keyof ImageMetadata;
26
+ namespace: string;
27
+ }
28
+ /**
29
+ * Supported XMP fields and their mappings
30
+ */
31
+ export declare const XMP_FIELD_MAPPINGS: XMPFieldMapping[];
32
+ /**
33
+ * Escape XML special characters
34
+ */
35
+ export declare function escapeXML(str: string): string;
36
+ /**
37
+ * Unescape XML special characters
38
+ */
39
+ export declare function unescapeXML(str: string): string;
40
+ /**
41
+ * Parse XMP metadata from XML string
42
+ */
43
+ export declare function parseXMP(xmpStr: string): Partial<ImageMetadata>;
44
+ /**
45
+ * Create XMP packet from metadata
46
+ */
47
+ export declare function createXMP(metadata: Partial<ImageMetadata>): string;
48
+ /**
49
+ * Get list of supported XMP metadata fields
50
+ */
51
+ export declare function getSupportedXMPFields(): Array<keyof ImageMetadata>;
52
+ //# sourceMappingURL=xmp.d.ts.map
@@ -0,0 +1,333 @@
1
+ "use strict";
2
+ /**
3
+ * XMP (Extensible Metadata Platform) parsing and writing utilities
4
+ *
5
+ * This module provides utilities for reading and writing XMP metadata in image files.
6
+ * It supports Dublin Core, EXIF, and Photoshop namespaces.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.XMP_FIELD_MAPPINGS = exports.XMP_NAMESPACES = void 0;
10
+ exports.escapeXML = escapeXML;
11
+ exports.unescapeXML = unescapeXML;
12
+ exports.parseXMP = parseXMP;
13
+ exports.createXMP = createXMP;
14
+ exports.getSupportedXMPFields = getSupportedXMPFields;
15
+ /**
16
+ * XMP namespace URIs
17
+ */
18
+ exports.XMP_NAMESPACES = {
19
+ RDF: "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
20
+ DC: "http://purl.org/dc/elements/1.1/",
21
+ XMP: "http://ns.adobe.com/xap/1.0/",
22
+ EXIF: "http://ns.adobe.com/exif/1.0/",
23
+ TIFF: "http://ns.adobe.com/tiff/1.0/",
24
+ PHOTOSHOP: "http://ns.adobe.com/photoshop/1.0/",
25
+ XMP_RIGHTS: "http://ns.adobe.com/xap/1.0/rights/",
26
+ };
27
+ /**
28
+ * Supported XMP fields and their mappings
29
+ */
30
+ exports.XMP_FIELD_MAPPINGS = [
31
+ // Dublin Core
32
+ { xmpPath: "dc:title", metadataKey: "title", namespace: exports.XMP_NAMESPACES.DC },
33
+ {
34
+ xmpPath: "dc:description",
35
+ metadataKey: "description",
36
+ namespace: exports.XMP_NAMESPACES.DC,
37
+ },
38
+ {
39
+ xmpPath: "dc:creator",
40
+ metadataKey: "author",
41
+ namespace: exports.XMP_NAMESPACES.DC,
42
+ },
43
+ {
44
+ xmpPath: "dc:rights",
45
+ metadataKey: "copyright",
46
+ namespace: exports.XMP_NAMESPACES.DC,
47
+ },
48
+ // EXIF namespace
49
+ {
50
+ xmpPath: "exif:DateTimeOriginal",
51
+ metadataKey: "creationDate",
52
+ namespace: exports.XMP_NAMESPACES.EXIF,
53
+ },
54
+ {
55
+ xmpPath: "exif:ISOSpeedRatings",
56
+ metadataKey: "iso",
57
+ namespace: exports.XMP_NAMESPACES.EXIF,
58
+ },
59
+ {
60
+ xmpPath: "exif:ExposureTime",
61
+ metadataKey: "exposureTime",
62
+ namespace: exports.XMP_NAMESPACES.EXIF,
63
+ },
64
+ {
65
+ xmpPath: "exif:FNumber",
66
+ metadataKey: "fNumber",
67
+ namespace: exports.XMP_NAMESPACES.EXIF,
68
+ },
69
+ {
70
+ xmpPath: "exif:FocalLength",
71
+ metadataKey: "focalLength",
72
+ namespace: exports.XMP_NAMESPACES.EXIF,
73
+ },
74
+ {
75
+ xmpPath: "exif:Flash",
76
+ metadataKey: "flash",
77
+ namespace: exports.XMP_NAMESPACES.EXIF,
78
+ },
79
+ {
80
+ xmpPath: "exif:WhiteBalance",
81
+ metadataKey: "whiteBalance",
82
+ namespace: exports.XMP_NAMESPACES.EXIF,
83
+ },
84
+ {
85
+ xmpPath: "exif:UserComment",
86
+ metadataKey: "userComment",
87
+ namespace: exports.XMP_NAMESPACES.EXIF,
88
+ },
89
+ // TIFF namespace
90
+ {
91
+ xmpPath: "tiff:Make",
92
+ metadataKey: "cameraMake",
93
+ namespace: exports.XMP_NAMESPACES.TIFF,
94
+ },
95
+ {
96
+ xmpPath: "tiff:Model",
97
+ metadataKey: "cameraModel",
98
+ namespace: exports.XMP_NAMESPACES.TIFF,
99
+ },
100
+ {
101
+ xmpPath: "tiff:Orientation",
102
+ metadataKey: "orientation",
103
+ namespace: exports.XMP_NAMESPACES.TIFF,
104
+ },
105
+ {
106
+ xmpPath: "tiff:Software",
107
+ metadataKey: "software",
108
+ namespace: exports.XMP_NAMESPACES.TIFF,
109
+ },
110
+ // Photoshop namespace
111
+ {
112
+ xmpPath: "photoshop:Credit",
113
+ metadataKey: "author",
114
+ namespace: exports.XMP_NAMESPACES.PHOTOSHOP,
115
+ },
116
+ ];
117
+ /**
118
+ * Escape XML special characters
119
+ */
120
+ function escapeXML(str) {
121
+ return str
122
+ .replace(/&/g, "&amp;")
123
+ .replace(/</g, "&lt;")
124
+ .replace(/>/g, "&gt;")
125
+ .replace(/"/g, "&quot;")
126
+ .replace(/'/g, "&apos;");
127
+ }
128
+ /**
129
+ * Unescape XML special characters
130
+ */
131
+ function unescapeXML(str) {
132
+ return str
133
+ .replace(/&lt;/g, "<")
134
+ .replace(/&gt;/g, ">")
135
+ .replace(/&quot;/g, '"')
136
+ .replace(/&apos;/g, "'")
137
+ .replace(/&amp;/g, "&");
138
+ }
139
+ /**
140
+ * Parse XMP metadata from XML string
141
+ */
142
+ function parseXMP(xmpStr) {
143
+ const metadata = {};
144
+ try {
145
+ // Simple regex-based parsing for common fields
146
+ // Dublin Core - title (with dotall flag 's')
147
+ const titleMatch = xmpStr.match(/<dc:title[\s\S]*?<rdf:li[^>]*>([^<]+)<\/rdf:li>/);
148
+ if (titleMatch && titleMatch[1].trim()) {
149
+ metadata.title = unescapeXML(titleMatch[1].trim());
150
+ }
151
+ // Dublin Core - description
152
+ const descMatch = xmpStr.match(/<dc:description[\s\S]*?<rdf:li[^>]*>([^<]+)<\/rdf:li>/);
153
+ if (descMatch && descMatch[1].trim()) {
154
+ metadata.description = unescapeXML(descMatch[1].trim());
155
+ }
156
+ // Dublin Core - creator
157
+ const creatorMatch = xmpStr.match(/<dc:creator[\s\S]*?<rdf:li[^>]*>([^<]+)<\/rdf:li>/);
158
+ if (creatorMatch && creatorMatch[1].trim()) {
159
+ metadata.author = unescapeXML(creatorMatch[1].trim());
160
+ }
161
+ // Dublin Core - rights
162
+ const rightsMatch = xmpStr.match(/<dc:rights[\s\S]*?<rdf:li[^>]*>([^<]+)<\/rdf:li>/);
163
+ if (rightsMatch && rightsMatch[1].trim()) {
164
+ metadata.copyright = unescapeXML(rightsMatch[1].trim());
165
+ }
166
+ // EXIF - DateTimeOriginal
167
+ const dateMatch = xmpStr.match(/<exif:DateTimeOriginal>([^<]+)<\/exif:DateTimeOriginal>/);
168
+ if (dateMatch) {
169
+ try {
170
+ metadata.creationDate = new Date(dateMatch[1]);
171
+ }
172
+ catch (_e) {
173
+ // Ignore date parse errors
174
+ }
175
+ }
176
+ // TIFF - Make and Model
177
+ const makeMatch = xmpStr.match(/<tiff:Make>([^<]+)<\/tiff:Make>/);
178
+ if (makeMatch) {
179
+ metadata.cameraMake = unescapeXML(makeMatch[1]);
180
+ }
181
+ const modelMatch = xmpStr.match(/<tiff:Model>([^<]+)<\/tiff:Model>/);
182
+ if (modelMatch) {
183
+ metadata.cameraModel = unescapeXML(modelMatch[1]);
184
+ }
185
+ const softwareMatch = xmpStr.match(/<tiff:Software>([^<]+)<\/tiff:Software>/);
186
+ if (softwareMatch) {
187
+ metadata.software = unescapeXML(softwareMatch[1]);
188
+ }
189
+ const orientationMatch = xmpStr.match(/<tiff:Orientation>([^<]+)<\/tiff:Orientation>/);
190
+ if (orientationMatch) {
191
+ metadata.orientation = parseInt(orientationMatch[1]);
192
+ }
193
+ // EXIF - Camera settings
194
+ const isoMatch = xmpStr.match(/<exif:ISOSpeedRatings>(?:<rdf:Seq[^>]*><rdf:li>)?([^<]+)/);
195
+ if (isoMatch) {
196
+ metadata.iso = parseInt(isoMatch[1]);
197
+ }
198
+ const exposureMatch = xmpStr.match(/<exif:ExposureTime>([^<]+)<\/exif:ExposureTime>/);
199
+ if (exposureMatch) {
200
+ // Handle rational format (e.g., "1/250")
201
+ if (exposureMatch[1].includes("/")) {
202
+ const [num, den] = exposureMatch[1].split("/").map(Number);
203
+ metadata.exposureTime = num / den;
204
+ }
205
+ else {
206
+ metadata.exposureTime = parseFloat(exposureMatch[1]);
207
+ }
208
+ }
209
+ const fNumberMatch = xmpStr.match(/<exif:FNumber>([^<]+)<\/exif:FNumber>/);
210
+ if (fNumberMatch) {
211
+ metadata.fNumber = parseFloat(fNumberMatch[1]);
212
+ }
213
+ const focalLengthMatch = xmpStr.match(/<exif:FocalLength>([^<]+)<\/exif:FocalLength>/);
214
+ if (focalLengthMatch) {
215
+ metadata.focalLength = parseFloat(focalLengthMatch[1]);
216
+ }
217
+ }
218
+ catch (_e) {
219
+ // Ignore XMP parsing errors
220
+ }
221
+ return metadata;
222
+ }
223
+ /**
224
+ * Create XMP packet from metadata
225
+ */
226
+ function createXMP(metadata) {
227
+ const parts = [];
228
+ parts.push('<?xpacket begin="\ufeff" id="W5M0MpCehiHzreSzNTczkc9d"?>');
229
+ parts.push('<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="@cross/image">');
230
+ parts.push('<rdf:RDF xmlns:rdf="' + exports.XMP_NAMESPACES.RDF + '">');
231
+ parts.push('<rdf:Description rdf:about=""');
232
+ parts.push(' xmlns:dc="' + exports.XMP_NAMESPACES.DC + '"');
233
+ parts.push(' xmlns:xmp="' + exports.XMP_NAMESPACES.XMP + '"');
234
+ parts.push(' xmlns:exif="' + exports.XMP_NAMESPACES.EXIF + '"');
235
+ parts.push(' xmlns:tiff="' + exports.XMP_NAMESPACES.TIFF + '"');
236
+ parts.push(' xmlns:photoshop="' + exports.XMP_NAMESPACES.PHOTOSHOP + '"');
237
+ parts.push(' xmlns:xmpRights="' + exports.XMP_NAMESPACES.XMP_RIGHTS + '">');
238
+ // Dublin Core - title
239
+ if (metadata.title) {
240
+ parts.push(" <dc:title>");
241
+ parts.push(" <rdf:Alt>");
242
+ parts.push(' <rdf:li xml:lang="x-default">' + escapeXML(metadata.title) +
243
+ "</rdf:li>");
244
+ parts.push(" </rdf:Alt>");
245
+ parts.push(" </dc:title>");
246
+ }
247
+ // Dublin Core - description
248
+ if (metadata.description) {
249
+ parts.push(" <dc:description>");
250
+ parts.push(" <rdf:Alt>");
251
+ parts.push(' <rdf:li xml:lang="x-default">' + escapeXML(metadata.description) +
252
+ "</rdf:li>");
253
+ parts.push(" </rdf:Alt>");
254
+ parts.push(" </dc:description>");
255
+ }
256
+ // Dublin Core - creator
257
+ if (metadata.author) {
258
+ parts.push(" <dc:creator>");
259
+ parts.push(" <rdf:Seq>");
260
+ parts.push(" <rdf:li>" + escapeXML(metadata.author) + "</rdf:li>");
261
+ parts.push(" </rdf:Seq>");
262
+ parts.push(" </dc:creator>");
263
+ }
264
+ // Dublin Core - rights
265
+ if (metadata.copyright) {
266
+ parts.push(" <dc:rights>");
267
+ parts.push(" <rdf:Alt>");
268
+ parts.push(' <rdf:li xml:lang="x-default">' + escapeXML(metadata.copyright) +
269
+ "</rdf:li>");
270
+ parts.push(" </rdf:Alt>");
271
+ parts.push(" </dc:rights>");
272
+ }
273
+ // EXIF - DateTimeOriginal
274
+ if (metadata.creationDate) {
275
+ const isoDate = metadata.creationDate.toISOString();
276
+ parts.push(" <exif:DateTimeOriginal>" + isoDate + "</exif:DateTimeOriginal>");
277
+ }
278
+ // TIFF - Make and Model
279
+ if (metadata.cameraMake) {
280
+ parts.push(" <tiff:Make>" + escapeXML(metadata.cameraMake) + "</tiff:Make>");
281
+ }
282
+ if (metadata.cameraModel) {
283
+ parts.push(" <tiff:Model>" + escapeXML(metadata.cameraModel) + "</tiff:Model>");
284
+ }
285
+ if (metadata.software) {
286
+ parts.push(" <tiff:Software>" + escapeXML(metadata.software) + "</tiff:Software>");
287
+ }
288
+ if (metadata.orientation !== undefined) {
289
+ parts.push(" <tiff:Orientation>" + metadata.orientation + "</tiff:Orientation>");
290
+ }
291
+ // EXIF - Camera settings
292
+ if (metadata.iso !== undefined) {
293
+ parts.push(" <exif:ISOSpeedRatings>");
294
+ parts.push(" <rdf:Seq>");
295
+ parts.push(" <rdf:li>" + metadata.iso + "</rdf:li>");
296
+ parts.push(" </rdf:Seq>");
297
+ parts.push(" </exif:ISOSpeedRatings>");
298
+ }
299
+ if (metadata.exposureTime !== undefined) {
300
+ parts.push(" <exif:ExposureTime>" + metadata.exposureTime + "</exif:ExposureTime>");
301
+ }
302
+ if (metadata.fNumber !== undefined) {
303
+ parts.push(" <exif:FNumber>" + metadata.fNumber + "</exif:FNumber>");
304
+ }
305
+ if (metadata.focalLength !== undefined) {
306
+ parts.push(" <exif:FocalLength>" + metadata.focalLength + "</exif:FocalLength>");
307
+ }
308
+ parts.push("</rdf:Description>");
309
+ parts.push("</rdf:RDF>");
310
+ parts.push("</x:xmpmeta>");
311
+ parts.push('<?xpacket end="w"?>');
312
+ return parts.join("\n");
313
+ }
314
+ /**
315
+ * Get list of supported XMP metadata fields
316
+ */
317
+ function getSupportedXMPFields() {
318
+ return [
319
+ "title",
320
+ "description",
321
+ "author",
322
+ "copyright",
323
+ "creationDate",
324
+ "cameraMake",
325
+ "cameraModel",
326
+ "orientation",
327
+ "software",
328
+ "iso",
329
+ "exposureTime",
330
+ "fNumber",
331
+ "focalLength",
332
+ ];
333
+ }
@@ -6,4 +6,8 @@ export declare function resizeBilinear(src: Uint8Array, srcWidth: number, srcHei
6
6
  * Nearest neighbor resize
7
7
  */
8
8
  export declare function resizeNearest(src: Uint8Array, srcWidth: number, srcHeight: number, dstWidth: number, dstHeight: number): Uint8Array;
9
+ /**
10
+ * Bicubic interpolation resize (Catmull-Rom)
11
+ */
12
+ export declare function resizeBicubic(src: Uint8Array, srcWidth: number, srcHeight: number, dstWidth: number, dstHeight: number): Uint8Array;
9
13
  //# sourceMappingURL=resize.d.ts.map