cross-image 0.2.3 → 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.
- package/README.md +333 -289
- package/esm/mod.d.ts +2 -0
- package/esm/mod.js +2 -0
- package/esm/src/formats/apng.d.ts +13 -1
- package/esm/src/formats/apng.js +97 -0
- package/esm/src/formats/ascii.d.ts +11 -1
- package/esm/src/formats/ascii.js +24 -0
- package/esm/src/formats/avif.d.ts +96 -0
- package/esm/src/formats/avif.js +607 -0
- package/esm/src/formats/bmp.d.ts +11 -1
- package/esm/src/formats/bmp.js +73 -0
- package/esm/src/formats/dng.d.ts +13 -1
- package/esm/src/formats/dng.js +26 -4
- package/esm/src/formats/gif.d.ts +15 -2
- package/esm/src/formats/gif.js +146 -4
- package/esm/src/formats/heic.d.ts +96 -0
- package/esm/src/formats/heic.js +608 -0
- package/esm/src/formats/ico.d.ts +11 -1
- package/esm/src/formats/ico.js +28 -0
- package/esm/src/formats/jpeg.d.ts +7 -0
- package/esm/src/formats/jpeg.js +76 -0
- package/esm/src/formats/pam.d.ts +11 -1
- package/esm/src/formats/pam.js +66 -0
- package/esm/src/formats/pcx.d.ts +11 -1
- package/esm/src/formats/pcx.js +45 -0
- package/esm/src/formats/png.d.ts +13 -1
- package/esm/src/formats/png.js +87 -0
- package/esm/src/formats/ppm.d.ts +11 -1
- package/esm/src/formats/ppm.js +34 -0
- package/esm/src/formats/tiff.d.ts +7 -0
- package/esm/src/formats/tiff.js +134 -0
- package/esm/src/formats/webp.d.ts +7 -0
- package/esm/src/formats/webp.js +92 -0
- package/esm/src/image.d.ts +9 -0
- package/esm/src/image.js +28 -0
- package/esm/src/types.d.ts +18 -0
- package/package.json +18 -1
- package/script/mod.d.ts +2 -0
- package/script/mod.js +5 -1
- package/script/src/formats/apng.d.ts +13 -1
- package/script/src/formats/apng.js +97 -0
- package/script/src/formats/ascii.d.ts +11 -1
- package/script/src/formats/ascii.js +24 -0
- package/script/src/formats/avif.d.ts +96 -0
- package/script/src/formats/avif.js +611 -0
- package/script/src/formats/bmp.d.ts +11 -1
- package/script/src/formats/bmp.js +73 -0
- package/script/src/formats/dng.d.ts +13 -1
- package/script/src/formats/dng.js +26 -4
- package/script/src/formats/gif.d.ts +15 -2
- package/script/src/formats/gif.js +146 -4
- package/script/src/formats/heic.d.ts +96 -0
- package/script/src/formats/heic.js +612 -0
- package/script/src/formats/ico.d.ts +11 -1
- package/script/src/formats/ico.js +28 -0
- package/script/src/formats/jpeg.d.ts +7 -0
- package/script/src/formats/jpeg.js +76 -0
- package/script/src/formats/pam.d.ts +11 -1
- package/script/src/formats/pam.js +66 -0
- package/script/src/formats/pcx.d.ts +11 -1
- package/script/src/formats/pcx.js +45 -0
- package/script/src/formats/png.d.ts +13 -1
- package/script/src/formats/png.js +87 -0
- package/script/src/formats/ppm.d.ts +11 -1
- package/script/src/formats/ppm.js +34 -0
- package/script/src/formats/tiff.d.ts +7 -0
- package/script/src/formats/tiff.js +134 -0
- package/script/src/formats/webp.d.ts +7 -0
- package/script/src/formats/webp.js +92 -0
- package/script/src/image.d.ts +9 -0
- package/script/src/image.js +28 -0
- package/script/src/types.d.ts +18 -0
package/esm/src/formats/webp.js
CHANGED
|
@@ -567,4 +567,96 @@ export class WebPFormat {
|
|
|
567
567
|
"focalLength",
|
|
568
568
|
];
|
|
569
569
|
}
|
|
570
|
+
/**
|
|
571
|
+
* Extract metadata from WebP data without fully decoding the pixel data
|
|
572
|
+
* This quickly parses RIFF chunks to extract EXIF and XMP metadata
|
|
573
|
+
* @param data Raw WebP data
|
|
574
|
+
* @returns Extracted metadata or undefined
|
|
575
|
+
*/
|
|
576
|
+
extractMetadata(data) {
|
|
577
|
+
if (!this.canDecode(data)) {
|
|
578
|
+
return Promise.resolve(undefined);
|
|
579
|
+
}
|
|
580
|
+
const metadata = {
|
|
581
|
+
format: "webp",
|
|
582
|
+
frameCount: 1,
|
|
583
|
+
bitDepth: 8,
|
|
584
|
+
};
|
|
585
|
+
let pos = 12; // Skip "RIFF" + size + "WEBP"
|
|
586
|
+
const readUint32LE = (data, offset) => {
|
|
587
|
+
return data[offset] | (data[offset + 1] << 8) | (data[offset + 2] << 16) |
|
|
588
|
+
(data[offset + 3] << 24);
|
|
589
|
+
};
|
|
590
|
+
const readUint16LE = (data, offset) => {
|
|
591
|
+
return data[offset] | (data[offset + 1] << 8);
|
|
592
|
+
};
|
|
593
|
+
// Parse chunks for metadata
|
|
594
|
+
while (pos + 8 <= data.length) {
|
|
595
|
+
const chunkType = String.fromCharCode(data[pos], data[pos + 1], data[pos + 2], data[pos + 3]);
|
|
596
|
+
const chunkSize = readUint32LE(data, pos + 4);
|
|
597
|
+
pos += 8;
|
|
598
|
+
// Stop if we've gone past the end
|
|
599
|
+
if (pos + chunkSize > data.length)
|
|
600
|
+
break;
|
|
601
|
+
const chunkData = data.slice(pos, pos + chunkSize);
|
|
602
|
+
if (chunkType === "VP8 ") {
|
|
603
|
+
// Lossy VP8 chunk
|
|
604
|
+
metadata.compression = "vp8";
|
|
605
|
+
metadata.colorType = "rgb";
|
|
606
|
+
}
|
|
607
|
+
else if (chunkType === "VP8L") {
|
|
608
|
+
// Lossless VP8L chunk
|
|
609
|
+
metadata.compression = "vp8l";
|
|
610
|
+
metadata.colorType = "rgba";
|
|
611
|
+
}
|
|
612
|
+
else if (chunkType === "VP8X") {
|
|
613
|
+
// Extended format chunk - contains animation info
|
|
614
|
+
if (chunkData.length >= 10) {
|
|
615
|
+
const flags = chunkData[0];
|
|
616
|
+
const _hasAnimation = (flags & 0x02) !== 0;
|
|
617
|
+
const hasAlpha = (flags & 0x10) !== 0;
|
|
618
|
+
if (hasAlpha) {
|
|
619
|
+
metadata.colorType = "rgba";
|
|
620
|
+
}
|
|
621
|
+
else {
|
|
622
|
+
metadata.colorType = "rgb";
|
|
623
|
+
}
|
|
624
|
+
// Animation is handled in ANIM chunk
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
else if (chunkType === "ANIM") {
|
|
628
|
+
// Animation parameters chunk
|
|
629
|
+
if (chunkData.length >= 6) {
|
|
630
|
+
// Background color at bytes 0-3
|
|
631
|
+
// Loop count at bytes 4-5
|
|
632
|
+
const _loopCount = readUint16LE(chunkData, 4);
|
|
633
|
+
// Note: Frame count is not directly in ANIM chunk, need to count ANMF chunks
|
|
634
|
+
// Reset frame count to 0 to start counting ANMF frames
|
|
635
|
+
metadata.frameCount = 0;
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
else if (chunkType === "ANMF") {
|
|
639
|
+
// Animation frame - count frames
|
|
640
|
+
if (metadata.frameCount !== undefined) {
|
|
641
|
+
metadata.frameCount++;
|
|
642
|
+
}
|
|
643
|
+
else {
|
|
644
|
+
metadata.frameCount = 1;
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
else if (chunkType === "EXIF") {
|
|
648
|
+
// EXIF metadata chunk
|
|
649
|
+
this.parseEXIF(chunkData, metadata);
|
|
650
|
+
}
|
|
651
|
+
else if (chunkType === "XMP ") {
|
|
652
|
+
// XMP metadata chunk
|
|
653
|
+
this.parseXMP(chunkData, metadata);
|
|
654
|
+
}
|
|
655
|
+
pos += chunkSize;
|
|
656
|
+
// Chunks are padded to even length
|
|
657
|
+
if (chunkSize % 2 === 1)
|
|
658
|
+
pos++;
|
|
659
|
+
}
|
|
660
|
+
return Promise.resolve(Object.keys(metadata).length > 0 ? metadata : undefined);
|
|
661
|
+
}
|
|
570
662
|
}
|
package/esm/src/image.d.ts
CHANGED
|
@@ -85,6 +85,15 @@ export declare class Image {
|
|
|
85
85
|
* @returns Array of supported metadata field names, or undefined if format doesn't support metadata
|
|
86
86
|
*/
|
|
87
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>;
|
|
88
97
|
/**
|
|
89
98
|
* Read an image from bytes
|
|
90
99
|
* @deprecated Use `decode()` instead. This method will be removed in a future version.
|
package/esm/src/image.js
CHANGED
|
@@ -13,6 +13,8 @@ import { PAMFormat } from "./formats/pam.js";
|
|
|
13
13
|
import { PCXFormat } from "./formats/pcx.js";
|
|
14
14
|
import { PPMFormat } from "./formats/ppm.js";
|
|
15
15
|
import { ASCIIFormat } from "./formats/ascii.js";
|
|
16
|
+
import { HEICFormat } from "./formats/heic.js";
|
|
17
|
+
import { AVIFFormat } from "./formats/avif.js";
|
|
16
18
|
import { validateImageDimensions } from "./utils/security.js";
|
|
17
19
|
/**
|
|
18
20
|
* Main Image class for reading, manipulating, and saving images
|
|
@@ -193,6 +195,30 @@ export class Image {
|
|
|
193
195
|
}
|
|
194
196
|
return formatHandler.getSupportedMetadata?.();
|
|
195
197
|
}
|
|
198
|
+
/**
|
|
199
|
+
* Extract metadata from image data without fully decoding the pixel data
|
|
200
|
+
* This is useful for quickly reading EXIF, XMP, or other metadata from images
|
|
201
|
+
* that may have unsupported features or compression methods
|
|
202
|
+
* @param data Raw image data
|
|
203
|
+
* @param format Optional format hint (e.g., "png", "jpeg", "webp")
|
|
204
|
+
* @returns Metadata extracted from the image, or undefined if extraction fails or format is unsupported
|
|
205
|
+
*/
|
|
206
|
+
static async extractMetadata(data, format) {
|
|
207
|
+
// Try specified format first
|
|
208
|
+
if (format) {
|
|
209
|
+
const handler = Image.formats.find((f) => f.name === format);
|
|
210
|
+
if (handler && handler.canDecode(data) && handler.extractMetadata) {
|
|
211
|
+
return await handler.extractMetadata(data);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
// Auto-detect format
|
|
215
|
+
for (const handler of Image.formats) {
|
|
216
|
+
if (handler.canDecode(data) && handler.extractMetadata) {
|
|
217
|
+
return await handler.extractMetadata(data);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
return undefined;
|
|
221
|
+
}
|
|
196
222
|
/**
|
|
197
223
|
* Read an image from bytes
|
|
198
224
|
* @deprecated Use `decode()` instead. This method will be removed in a future version.
|
|
@@ -841,5 +867,7 @@ Object.defineProperty(Image, "formats", {
|
|
|
841
867
|
new PCXFormat(),
|
|
842
868
|
new PPMFormat(),
|
|
843
869
|
new ASCIIFormat(),
|
|
870
|
+
new HEICFormat(),
|
|
871
|
+
new AVIFFormat(),
|
|
844
872
|
]
|
|
845
873
|
});
|
package/esm/src/types.d.ts
CHANGED
|
@@ -50,6 +50,16 @@ export interface ImageMetadata {
|
|
|
50
50
|
software?: string;
|
|
51
51
|
/** User comment / notes */
|
|
52
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;
|
|
53
63
|
/** Custom metadata fields */
|
|
54
64
|
custom?: Record<string, string | number | boolean>;
|
|
55
65
|
}
|
|
@@ -203,5 +213,13 @@ export interface ImageFormat {
|
|
|
203
213
|
* @returns Array of metadata field names that can be persisted
|
|
204
214
|
*/
|
|
205
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>;
|
|
206
224
|
}
|
|
207
225
|
//# sourceMappingURL=types.d.ts.map
|
package/package.json
CHANGED
|
@@ -1,20 +1,34 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cross-image",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.4",
|
|
4
4
|
"description": "A pure JavaScript, dependency-free, cross-runtime image processing library for Deno, Node.js, and Bun.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"image",
|
|
7
7
|
"image-processing",
|
|
8
|
+
"image-manipulation",
|
|
9
|
+
"image-resize",
|
|
10
|
+
"image-decode",
|
|
11
|
+
"image-encode",
|
|
8
12
|
"png",
|
|
13
|
+
"apng",
|
|
9
14
|
"jpeg",
|
|
10
15
|
"webp",
|
|
11
16
|
"gif",
|
|
12
17
|
"tiff",
|
|
13
18
|
"bmp",
|
|
19
|
+
"ico",
|
|
14
20
|
"dng",
|
|
21
|
+
"heic",
|
|
22
|
+
"avif",
|
|
15
23
|
"pam",
|
|
24
|
+
"ppm",
|
|
16
25
|
"pcx",
|
|
26
|
+
"ascii-art",
|
|
27
|
+
"metadata",
|
|
28
|
+
"exif",
|
|
17
29
|
"cross-runtime",
|
|
30
|
+
"pure-javascript",
|
|
31
|
+
"no-dependencies",
|
|
18
32
|
"deno",
|
|
19
33
|
"node",
|
|
20
34
|
"bun"
|
|
@@ -37,5 +51,8 @@
|
|
|
37
51
|
}
|
|
38
52
|
},
|
|
39
53
|
"scripts": {},
|
|
54
|
+
"engines": {
|
|
55
|
+
"node": ">=18.0.0"
|
|
56
|
+
},
|
|
40
57
|
"_generatedBy": "dnt@dev"
|
|
41
58
|
}
|
package/script/mod.d.ts
CHANGED
|
@@ -57,4 +57,6 @@ export { PAMFormat } from "./src/formats/pam.js";
|
|
|
57
57
|
export { PCXFormat } from "./src/formats/pcx.js";
|
|
58
58
|
export { PPMFormat } from "./src/formats/ppm.js";
|
|
59
59
|
export { ASCIIFormat } from "./src/formats/ascii.js";
|
|
60
|
+
export { HEICFormat } from "./src/formats/heic.js";
|
|
61
|
+
export { AVIFFormat } from "./src/formats/avif.js";
|
|
60
62
|
//# sourceMappingURL=mod.d.ts.map
|
package/script/mod.js
CHANGED
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
* ```
|
|
45
45
|
*/
|
|
46
46
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
47
|
-
exports.ASCIIFormat = exports.PPMFormat = exports.PCXFormat = exports.PAMFormat = exports.DNGFormat = exports.ICOFormat = exports.BMPFormat = exports.TIFFFormat = exports.GIFFormat = exports.WebPFormat = exports.JPEGFormat = exports.APNGFormat = exports.PNGFormat = exports.Image = void 0;
|
|
47
|
+
exports.AVIFFormat = exports.HEICFormat = exports.ASCIIFormat = exports.PPMFormat = exports.PCXFormat = exports.PAMFormat = exports.DNGFormat = exports.ICOFormat = exports.BMPFormat = exports.TIFFFormat = exports.GIFFormat = exports.WebPFormat = exports.JPEGFormat = exports.APNGFormat = exports.PNGFormat = exports.Image = void 0;
|
|
48
48
|
var image_js_1 = require("./src/image.js");
|
|
49
49
|
Object.defineProperty(exports, "Image", { enumerable: true, get: function () { return image_js_1.Image; } });
|
|
50
50
|
var png_js_1 = require("./src/formats/png.js");
|
|
@@ -73,3 +73,7 @@ var ppm_js_1 = require("./src/formats/ppm.js");
|
|
|
73
73
|
Object.defineProperty(exports, "PPMFormat", { enumerable: true, get: function () { return ppm_js_1.PPMFormat; } });
|
|
74
74
|
var ascii_js_1 = require("./src/formats/ascii.js");
|
|
75
75
|
Object.defineProperty(exports, "ASCIIFormat", { enumerable: true, get: function () { return ascii_js_1.ASCIIFormat; } });
|
|
76
|
+
var heic_js_1 = require("./src/formats/heic.js");
|
|
77
|
+
Object.defineProperty(exports, "HEICFormat", { enumerable: true, get: function () { return heic_js_1.HEICFormat; } });
|
|
78
|
+
var avif_js_1 = require("./src/formats/avif.js");
|
|
79
|
+
Object.defineProperty(exports, "AVIFFormat", { enumerable: true, get: function () { return avif_js_1.AVIFFormat; } });
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ImageData, ImageFormat, MultiFrameImageData } from "../types.js";
|
|
1
|
+
import type { ImageData, ImageFormat, ImageMetadata, MultiFrameImageData } from "../types.js";
|
|
2
2
|
import { PNGBase } from "./png_base.js";
|
|
3
3
|
/**
|
|
4
4
|
* APNG (Animated PNG) format handler
|
|
@@ -46,5 +46,17 @@ export declare class APNGFormat extends PNGBase implements ImageFormat {
|
|
|
46
46
|
*/
|
|
47
47
|
encodeFrames(imageData: MultiFrameImageData): Promise<Uint8Array>;
|
|
48
48
|
private decodeFrameData;
|
|
49
|
+
/**
|
|
50
|
+
* Get the list of metadata fields supported by APNG format
|
|
51
|
+
* Includes all PNG fields plus frame count
|
|
52
|
+
*/
|
|
53
|
+
getSupportedMetadata(): Array<keyof ImageMetadata>;
|
|
54
|
+
/**
|
|
55
|
+
* Extract metadata from APNG data without fully decoding the pixel data
|
|
56
|
+
* This quickly parses PNG chunks to extract metadata including frame count
|
|
57
|
+
* @param data Raw APNG data
|
|
58
|
+
* @returns Extracted metadata or undefined
|
|
59
|
+
*/
|
|
60
|
+
extractMetadata(data: Uint8Array): Promise<ImageMetadata | undefined>;
|
|
49
61
|
}
|
|
50
62
|
//# sourceMappingURL=apng.d.ts.map
|
|
@@ -364,5 +364,102 @@ class APNGFormat extends png_base_js_1.PNGBase {
|
|
|
364
364
|
const rgba = this.unfilterAndConvert(decompressed, width, height, bitDepth, colorType);
|
|
365
365
|
return rgba;
|
|
366
366
|
}
|
|
367
|
+
/**
|
|
368
|
+
* Get the list of metadata fields supported by APNG format
|
|
369
|
+
* Includes all PNG fields plus frame count
|
|
370
|
+
*/
|
|
371
|
+
getSupportedMetadata() {
|
|
372
|
+
return [
|
|
373
|
+
...super.getSupportedMetadata(),
|
|
374
|
+
"frameCount", // acTL chunk
|
|
375
|
+
];
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* Extract metadata from APNG data without fully decoding the pixel data
|
|
379
|
+
* This quickly parses PNG chunks to extract metadata including frame count
|
|
380
|
+
* @param data Raw APNG data
|
|
381
|
+
* @returns Extracted metadata or undefined
|
|
382
|
+
*/
|
|
383
|
+
extractMetadata(data) {
|
|
384
|
+
if (!this.canDecode(data)) {
|
|
385
|
+
return Promise.resolve(undefined);
|
|
386
|
+
}
|
|
387
|
+
let pos = 8; // Skip PNG signature
|
|
388
|
+
let width = 0;
|
|
389
|
+
let height = 0;
|
|
390
|
+
let frameCount = 0;
|
|
391
|
+
const metadata = {
|
|
392
|
+
format: "apng",
|
|
393
|
+
compression: "deflate",
|
|
394
|
+
};
|
|
395
|
+
// Parse chunks for metadata only
|
|
396
|
+
while (pos < data.length) {
|
|
397
|
+
if (pos + 8 > data.length)
|
|
398
|
+
break;
|
|
399
|
+
const length = this.readUint32(data, pos);
|
|
400
|
+
pos += 4;
|
|
401
|
+
const type = String.fromCharCode(data[pos], data[pos + 1], data[pos + 2], data[pos + 3]);
|
|
402
|
+
pos += 4;
|
|
403
|
+
if (pos + length + 4 > data.length)
|
|
404
|
+
break;
|
|
405
|
+
const chunkData = data.slice(pos, pos + length);
|
|
406
|
+
pos += length;
|
|
407
|
+
pos += 4; // Skip CRC
|
|
408
|
+
if (type === "IHDR") {
|
|
409
|
+
width = this.readUint32(chunkData, 0);
|
|
410
|
+
height = this.readUint32(chunkData, 4);
|
|
411
|
+
// Parse bit depth and color type from IHDR
|
|
412
|
+
if (chunkData.length >= 9) {
|
|
413
|
+
metadata.bitDepth = chunkData[8];
|
|
414
|
+
const colorTypeCode = chunkData[9];
|
|
415
|
+
// PNG color types: 0=grayscale, 2=rgb, 3=indexed, 4=grayscale+alpha, 6=rgba
|
|
416
|
+
switch (colorTypeCode) {
|
|
417
|
+
case 0:
|
|
418
|
+
metadata.colorType = "grayscale";
|
|
419
|
+
break;
|
|
420
|
+
case 2:
|
|
421
|
+
metadata.colorType = "rgb";
|
|
422
|
+
break;
|
|
423
|
+
case 3:
|
|
424
|
+
metadata.colorType = "indexed";
|
|
425
|
+
break;
|
|
426
|
+
case 4:
|
|
427
|
+
metadata.colorType = "grayscale-alpha";
|
|
428
|
+
break;
|
|
429
|
+
case 6:
|
|
430
|
+
metadata.colorType = "rgba";
|
|
431
|
+
break;
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
else if (type === "acTL") {
|
|
436
|
+
// Animation control chunk - contains frame count
|
|
437
|
+
if (chunkData.length >= 4) {
|
|
438
|
+
frameCount = this.readUint32(chunkData, 0);
|
|
439
|
+
metadata.frameCount = frameCount;
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
else if (type === "pHYs") {
|
|
443
|
+
// Physical pixel dimensions
|
|
444
|
+
this.parsePhysChunk(chunkData, metadata, width, height);
|
|
445
|
+
}
|
|
446
|
+
else if (type === "tEXt") {
|
|
447
|
+
// Text chunk
|
|
448
|
+
this.parseTextChunk(chunkData, metadata);
|
|
449
|
+
}
|
|
450
|
+
else if (type === "iTXt") {
|
|
451
|
+
// International text chunk
|
|
452
|
+
this.parseITxtChunk(chunkData, metadata);
|
|
453
|
+
}
|
|
454
|
+
else if (type === "eXIf") {
|
|
455
|
+
// EXIF chunk
|
|
456
|
+
this.parseExifChunk(chunkData, metadata);
|
|
457
|
+
}
|
|
458
|
+
else if (type === "IEND") {
|
|
459
|
+
break;
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
return Promise.resolve(Object.keys(metadata).length > 0 ? metadata : undefined);
|
|
463
|
+
}
|
|
367
464
|
}
|
|
368
465
|
exports.APNGFormat = APNGFormat;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ASCIIOptions, ImageData, ImageFormat } from "../types.js";
|
|
1
|
+
import type { ASCIIOptions, ImageData, ImageFormat, ImageMetadata } from "../types.js";
|
|
2
2
|
/**
|
|
3
3
|
* ASCII format handler
|
|
4
4
|
* Converts images to ASCII art text representation
|
|
@@ -34,5 +34,15 @@ export declare class ASCIIFormat implements ImageFormat {
|
|
|
34
34
|
* Parse options from the options line
|
|
35
35
|
*/
|
|
36
36
|
private parseOptions;
|
|
37
|
+
/**
|
|
38
|
+
* Get the list of metadata fields supported by ASCII format
|
|
39
|
+
*/
|
|
40
|
+
getSupportedMetadata(): Array<keyof ImageMetadata>;
|
|
41
|
+
/**
|
|
42
|
+
* Extract metadata from ASCII art data without fully decoding
|
|
43
|
+
* @param data Raw ASCII art data
|
|
44
|
+
* @returns Extracted metadata or undefined
|
|
45
|
+
*/
|
|
46
|
+
extractMetadata(data: Uint8Array): Promise<ImageMetadata | undefined>;
|
|
37
47
|
}
|
|
38
48
|
//# sourceMappingURL=ascii.d.ts.map
|
|
@@ -186,5 +186,29 @@ class ASCIIFormat {
|
|
|
186
186
|
}
|
|
187
187
|
return options;
|
|
188
188
|
}
|
|
189
|
+
/**
|
|
190
|
+
* Get the list of metadata fields supported by ASCII format
|
|
191
|
+
*/
|
|
192
|
+
getSupportedMetadata() {
|
|
193
|
+
return []; // ASCII art doesn't support metadata preservation
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Extract metadata from ASCII art data without fully decoding
|
|
197
|
+
* @param data Raw ASCII art data
|
|
198
|
+
* @returns Extracted metadata or undefined
|
|
199
|
+
*/
|
|
200
|
+
extractMetadata(data) {
|
|
201
|
+
if (!this.canDecode(data)) {
|
|
202
|
+
return Promise.resolve(undefined);
|
|
203
|
+
}
|
|
204
|
+
const metadata = {
|
|
205
|
+
format: "ascii",
|
|
206
|
+
compression: "none",
|
|
207
|
+
frameCount: 1,
|
|
208
|
+
bitDepth: 1, // ASCII is 1-bit (character or no character)
|
|
209
|
+
colorType: "grayscale",
|
|
210
|
+
};
|
|
211
|
+
return Promise.resolve(metadata);
|
|
212
|
+
}
|
|
189
213
|
}
|
|
190
214
|
exports.ASCIIFormat = ASCIIFormat;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import type { ImageData, ImageFormat, ImageMetadata } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* AVIF format handler
|
|
4
|
+
* Supports AVIF images using runtime APIs (ImageDecoder/OffscreenCanvas)
|
|
5
|
+
* Note: Pure JavaScript encode/decode is not supported due to complexity
|
|
6
|
+
*/
|
|
7
|
+
export declare class AVIFFormat implements ImageFormat {
|
|
8
|
+
/** Format name identifier */
|
|
9
|
+
readonly name = "avif";
|
|
10
|
+
/** MIME type for AVIF images */
|
|
11
|
+
readonly mimeType = "image/avif";
|
|
12
|
+
/**
|
|
13
|
+
* Check if the given data is an AVIF image
|
|
14
|
+
* @param data Raw image data to check
|
|
15
|
+
* @returns true if data has AVIF signature
|
|
16
|
+
*/
|
|
17
|
+
canDecode(data: Uint8Array): boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Decode AVIF image data to RGBA
|
|
20
|
+
* Uses runtime APIs (ImageDecoder) for decoding
|
|
21
|
+
* @param data Raw AVIF image data
|
|
22
|
+
* @returns Decoded image data with RGBA pixels
|
|
23
|
+
*/
|
|
24
|
+
decode(data: Uint8Array): Promise<ImageData>;
|
|
25
|
+
/**
|
|
26
|
+
* Encode RGBA image data to AVIF format
|
|
27
|
+
* Uses runtime APIs (OffscreenCanvas) for encoding
|
|
28
|
+
*
|
|
29
|
+
* Note: Metadata injection is not currently implemented. Metadata may be lost during encoding
|
|
30
|
+
* as it would require parsing and modifying the ISOBMFF container structure.
|
|
31
|
+
*
|
|
32
|
+
* @param imageData Image data to encode
|
|
33
|
+
* @returns Encoded AVIF image bytes
|
|
34
|
+
*/
|
|
35
|
+
encode(imageData: ImageData): Promise<Uint8Array>;
|
|
36
|
+
/**
|
|
37
|
+
* Decode using runtime APIs
|
|
38
|
+
* @param data Raw AVIF data
|
|
39
|
+
* @returns Decoded image dimensions and pixel data
|
|
40
|
+
*/
|
|
41
|
+
private decodeUsingRuntime;
|
|
42
|
+
/**
|
|
43
|
+
* Parse EXIF metadata from AVIF data
|
|
44
|
+
*
|
|
45
|
+
* Note: This is a simplified implementation that searches for EXIF headers linearly.
|
|
46
|
+
* A full implementation would require navigating the ISOBMFF box structure to find
|
|
47
|
+
* the 'meta' box and then the 'Exif' item. This simplified approach may not work
|
|
48
|
+
* in all cases but is suitable for basic metadata extraction when runtime APIs are
|
|
49
|
+
* not available or as a fallback.
|
|
50
|
+
*
|
|
51
|
+
* @param data Raw AVIF data
|
|
52
|
+
* @param metadata Metadata object to populate
|
|
53
|
+
*/
|
|
54
|
+
private parseEXIF;
|
|
55
|
+
/**
|
|
56
|
+
* Parse TIFF-formatted EXIF data
|
|
57
|
+
* @param data EXIF data in TIFF format
|
|
58
|
+
* @param metadata Metadata object to populate
|
|
59
|
+
*/
|
|
60
|
+
private parseTIFFExif;
|
|
61
|
+
/**
|
|
62
|
+
* Parse Exif Sub-IFD for camera settings
|
|
63
|
+
* @param data EXIF data
|
|
64
|
+
* @param exifIfdOffset Offset to Exif Sub-IFD
|
|
65
|
+
* @param littleEndian Byte order
|
|
66
|
+
* @param metadata Metadata object to populate
|
|
67
|
+
*/
|
|
68
|
+
private parseExifSubIFD;
|
|
69
|
+
/**
|
|
70
|
+
* Parse GPS IFD for location data
|
|
71
|
+
* @param data EXIF data
|
|
72
|
+
* @param gpsIfdOffset Offset to GPS IFD
|
|
73
|
+
* @param littleEndian Byte order
|
|
74
|
+
* @param metadata Metadata object to populate
|
|
75
|
+
*/
|
|
76
|
+
private parseGPSIFD;
|
|
77
|
+
/**
|
|
78
|
+
* Read a rational value (numerator/denominator)
|
|
79
|
+
* @param data Data buffer
|
|
80
|
+
* @param offset Offset to rational
|
|
81
|
+
* @param littleEndian Byte order
|
|
82
|
+
* @returns Decimal value
|
|
83
|
+
*/
|
|
84
|
+
private readRational;
|
|
85
|
+
/**
|
|
86
|
+
* Get the list of metadata fields supported by AVIF format
|
|
87
|
+
*/
|
|
88
|
+
getSupportedMetadata(): Array<keyof ImageMetadata>;
|
|
89
|
+
/**
|
|
90
|
+
* Extract metadata from AVIF data without fully decoding the pixel data
|
|
91
|
+
* @param data Raw AVIF data
|
|
92
|
+
* @returns Extracted metadata or undefined
|
|
93
|
+
*/
|
|
94
|
+
extractMetadata(data: Uint8Array): Promise<ImageMetadata | undefined>;
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=avif.d.ts.map
|