cross-image 0.2.4 → 0.4.0
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/LICENSE +21 -21
- package/README.md +507 -333
- package/esm/mod.d.ts +4 -4
- package/esm/mod.js +2 -2
- package/esm/src/formats/apng.d.ts +5 -5
- package/esm/src/formats/apng.js +7 -9
- package/esm/src/formats/ascii.d.ts +3 -3
- package/esm/src/formats/ascii.js +1 -1
- package/esm/src/formats/avif.d.ts +3 -3
- package/esm/src/formats/avif.js +7 -7
- package/esm/src/formats/bmp.d.ts +3 -3
- package/esm/src/formats/bmp.js +2 -2
- package/esm/src/formats/dng.d.ts +1 -1
- package/esm/src/formats/dng.js +1 -1
- package/esm/src/formats/gif.d.ts +4 -4
- package/esm/src/formats/gif.js +14 -10
- package/esm/src/formats/heic.d.ts +3 -3
- package/esm/src/formats/heic.js +7 -7
- package/esm/src/formats/ico.d.ts +3 -3
- package/esm/src/formats/ico.js +4 -4
- package/esm/src/formats/jpeg.d.ts +3 -3
- package/esm/src/formats/jpeg.js +23 -11
- package/esm/src/formats/pam.d.ts +3 -3
- package/esm/src/formats/pam.js +2 -2
- package/esm/src/formats/pcx.d.ts +3 -3
- package/esm/src/formats/pcx.js +2 -2
- package/esm/src/formats/png.d.ts +3 -3
- package/esm/src/formats/png.js +2 -2
- package/esm/src/formats/png_base.js +2 -5
- package/esm/src/formats/ppm.d.ts +3 -3
- package/esm/src/formats/ppm.js +2 -2
- package/esm/src/formats/tiff.d.ts +7 -18
- package/esm/src/formats/tiff.js +86 -21
- package/esm/src/formats/webp.d.ts +3 -3
- package/esm/src/formats/webp.js +11 -8
- package/esm/src/image.d.ts +11 -3
- package/esm/src/image.js +37 -21
- package/esm/src/types.d.ts +56 -4
- package/esm/src/utils/gif_decoder.d.ts +4 -1
- package/esm/src/utils/gif_decoder.js +91 -65
- package/esm/src/utils/image_processing.js +144 -70
- package/esm/src/utils/jpeg_decoder.d.ts +17 -4
- package/esm/src/utils/jpeg_decoder.js +448 -83
- package/esm/src/utils/jpeg_encoder.d.ts +15 -1
- package/esm/src/utils/jpeg_encoder.js +263 -24
- package/esm/src/utils/resize.js +51 -20
- package/esm/src/utils/tiff_deflate.d.ts +18 -0
- package/esm/src/utils/tiff_deflate.js +27 -0
- package/esm/src/utils/tiff_packbits.d.ts +24 -0
- package/esm/src/utils/tiff_packbits.js +90 -0
- package/esm/src/utils/webp_decoder.d.ts +3 -1
- package/esm/src/utils/webp_decoder.js +144 -63
- package/esm/src/utils/webp_encoder.js +5 -11
- package/package.json +1 -1
- package/script/mod.d.ts +4 -4
- package/script/mod.js +2 -2
- package/script/src/formats/apng.d.ts +5 -5
- package/script/src/formats/apng.js +7 -9
- package/script/src/formats/ascii.d.ts +3 -3
- package/script/src/formats/ascii.js +1 -1
- package/script/src/formats/avif.d.ts +3 -3
- package/script/src/formats/avif.js +7 -7
- package/script/src/formats/bmp.d.ts +3 -3
- package/script/src/formats/bmp.js +2 -2
- package/script/src/formats/dng.d.ts +1 -1
- package/script/src/formats/dng.js +1 -1
- package/script/src/formats/gif.d.ts +4 -4
- package/script/src/formats/gif.js +14 -10
- package/script/src/formats/heic.d.ts +3 -3
- package/script/src/formats/heic.js +7 -7
- package/script/src/formats/ico.d.ts +3 -3
- package/script/src/formats/ico.js +4 -4
- package/script/src/formats/jpeg.d.ts +3 -3
- package/script/src/formats/jpeg.js +23 -11
- package/script/src/formats/pam.d.ts +3 -3
- package/script/src/formats/pam.js +2 -2
- package/script/src/formats/pcx.d.ts +3 -3
- package/script/src/formats/pcx.js +2 -2
- package/script/src/formats/png.d.ts +3 -3
- package/script/src/formats/png.js +2 -2
- package/script/src/formats/png_base.js +2 -5
- package/script/src/formats/ppm.d.ts +3 -3
- package/script/src/formats/ppm.js +2 -2
- package/script/src/formats/tiff.d.ts +7 -18
- package/script/src/formats/tiff.js +86 -21
- package/script/src/formats/webp.d.ts +3 -3
- package/script/src/formats/webp.js +11 -8
- package/script/src/image.d.ts +11 -3
- package/script/src/image.js +36 -20
- package/script/src/types.d.ts +56 -4
- package/script/src/utils/gif_decoder.d.ts +4 -1
- package/script/src/utils/gif_decoder.js +91 -65
- package/script/src/utils/image_processing.js +144 -70
- package/script/src/utils/jpeg_decoder.d.ts +17 -4
- package/script/src/utils/jpeg_decoder.js +448 -83
- package/script/src/utils/jpeg_encoder.d.ts +15 -1
- package/script/src/utils/jpeg_encoder.js +263 -24
- package/script/src/utils/resize.js +51 -20
- package/script/src/utils/tiff_deflate.d.ts +18 -0
- package/script/src/utils/tiff_deflate.js +31 -0
- package/script/src/utils/tiff_packbits.d.ts +24 -0
- package/script/src/utils/tiff_packbits.js +94 -0
- package/script/src/utils/webp_decoder.d.ts +3 -1
- package/script/src/utils/webp_decoder.js +144 -63
- package/script/src/utils/webp_encoder.js +5 -11
|
@@ -2,14 +2,16 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.TIFFFormat = void 0;
|
|
4
4
|
const tiff_lzw_js_1 = require("../utils/tiff_lzw.js");
|
|
5
|
+
const tiff_packbits_js_1 = require("../utils/tiff_packbits.js");
|
|
6
|
+
const tiff_deflate_js_1 = require("../utils/tiff_deflate.js");
|
|
5
7
|
const security_js_1 = require("../utils/security.js");
|
|
6
8
|
// Constants for unit conversions
|
|
7
9
|
const DEFAULT_DPI = 72;
|
|
8
10
|
/**
|
|
9
11
|
* TIFF format handler
|
|
10
|
-
* Implements pure-JS TIFF decoder for uncompressed and
|
|
11
|
-
* and encoder for uncompressed and
|
|
12
|
-
* for
|
|
12
|
+
* Implements pure-JS TIFF decoder for uncompressed, LZW, PackBits, and Deflate-compressed RGB/RGBA images
|
|
13
|
+
* and encoder for uncompressed, LZW, PackBits, and Deflate-compressed RGBA TIFFs. Falls back to ImageDecoder
|
|
14
|
+
* for JPEG-compressed TIFFs.
|
|
13
15
|
* Supports multi-page TIFF files.
|
|
14
16
|
*/
|
|
15
17
|
class TIFFFormat {
|
|
@@ -55,7 +57,7 @@ class TIFFFormat {
|
|
|
55
57
|
* @param data Raw TIFF image data
|
|
56
58
|
* @returns Decoded image data with RGBA pixels of first page
|
|
57
59
|
*/
|
|
58
|
-
async decode(data) {
|
|
60
|
+
async decode(data, _options) {
|
|
59
61
|
if (!this.canDecode(data)) {
|
|
60
62
|
throw new Error("Invalid TIFF signature");
|
|
61
63
|
}
|
|
@@ -131,7 +133,7 @@ class TIFFFormat {
|
|
|
131
133
|
metadata: Object.keys(metadata).length > 0 ? metadata : undefined,
|
|
132
134
|
};
|
|
133
135
|
}
|
|
134
|
-
encode(imageData, options) {
|
|
136
|
+
async encode(imageData, options) {
|
|
135
137
|
const { width, height, data, metadata } = imageData;
|
|
136
138
|
const opts = options;
|
|
137
139
|
const compression = opts?.compression ?? "none";
|
|
@@ -175,6 +177,16 @@ class TIFFFormat {
|
|
|
175
177
|
pixelData = encoder.compress(sourceData);
|
|
176
178
|
compressionCode = 5;
|
|
177
179
|
}
|
|
180
|
+
else if (compression === "packbits") {
|
|
181
|
+
// PackBits compress the pixel data
|
|
182
|
+
pixelData = (0, tiff_packbits_js_1.packBitsCompress)(sourceData);
|
|
183
|
+
compressionCode = 32773;
|
|
184
|
+
}
|
|
185
|
+
else if (compression === "deflate") {
|
|
186
|
+
// Deflate compress the pixel data
|
|
187
|
+
pixelData = await (0, tiff_deflate_js_1.deflateCompress)(sourceData);
|
|
188
|
+
compressionCode = 8;
|
|
189
|
+
}
|
|
178
190
|
else {
|
|
179
191
|
// Uncompressed
|
|
180
192
|
pixelData = sourceData;
|
|
@@ -332,7 +344,7 @@ class TIFFFormat {
|
|
|
332
344
|
/**
|
|
333
345
|
* Decode all pages from a multi-page TIFF
|
|
334
346
|
*/
|
|
335
|
-
async decodeFrames(data) {
|
|
347
|
+
async decodeFrames(data, _options) {
|
|
336
348
|
if (!this.canDecode(data)) {
|
|
337
349
|
throw new Error("Invalid TIFF signature");
|
|
338
350
|
}
|
|
@@ -395,7 +407,7 @@ class TIFFFormat {
|
|
|
395
407
|
/**
|
|
396
408
|
* Encode multi-page TIFF
|
|
397
409
|
*/
|
|
398
|
-
encodeFrames(imageData, options) {
|
|
410
|
+
async encodeFrames(imageData, options) {
|
|
399
411
|
const opts = options;
|
|
400
412
|
const compression = opts?.compression ?? "none";
|
|
401
413
|
if (imageData.frames.length === 0) {
|
|
@@ -420,6 +432,12 @@ class TIFFFormat {
|
|
|
420
432
|
const encoder = new tiff_lzw_js_1.TIFFLZWEncoder();
|
|
421
433
|
pixelData = encoder.compress(frame.data);
|
|
422
434
|
}
|
|
435
|
+
else if (compression === "packbits") {
|
|
436
|
+
pixelData = (0, tiff_packbits_js_1.packBitsCompress)(frame.data);
|
|
437
|
+
}
|
|
438
|
+
else if (compression === "deflate") {
|
|
439
|
+
pixelData = await (0, tiff_deflate_js_1.deflateCompress)(frame.data);
|
|
440
|
+
}
|
|
423
441
|
else {
|
|
424
442
|
pixelData = frame.data;
|
|
425
443
|
}
|
|
@@ -456,7 +474,19 @@ class TIFFFormat {
|
|
|
456
474
|
this.writeIFDEntry(result, 0x0102, 3, 4, dataOffset);
|
|
457
475
|
dataOffset += 8;
|
|
458
476
|
// Compression
|
|
459
|
-
|
|
477
|
+
let compressionCode;
|
|
478
|
+
if (compression === "lzw") {
|
|
479
|
+
compressionCode = 5;
|
|
480
|
+
}
|
|
481
|
+
else if (compression === "packbits") {
|
|
482
|
+
compressionCode = 32773;
|
|
483
|
+
}
|
|
484
|
+
else if (compression === "deflate") {
|
|
485
|
+
compressionCode = 8;
|
|
486
|
+
}
|
|
487
|
+
else {
|
|
488
|
+
compressionCode = 1;
|
|
489
|
+
}
|
|
460
490
|
this.writeIFDEntry(result, 0x0103, 3, 1, compressionCode);
|
|
461
491
|
// PhotometricInterpretation
|
|
462
492
|
this.writeIFDEntry(result, 0x0106, 3, 1, 2);
|
|
@@ -467,9 +497,19 @@ class TIFFFormat {
|
|
|
467
497
|
// RowsPerStrip
|
|
468
498
|
this.writeIFDEntry(result, 0x0116, 4, 1, frame.height);
|
|
469
499
|
// StripByteCounts
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
500
|
+
let pixelDataSize;
|
|
501
|
+
if (compression === "lzw") {
|
|
502
|
+
pixelDataSize = new tiff_lzw_js_1.TIFFLZWEncoder().compress(frame.data).length;
|
|
503
|
+
}
|
|
504
|
+
else if (compression === "packbits") {
|
|
505
|
+
pixelDataSize = (0, tiff_packbits_js_1.packBitsCompress)(frame.data).length;
|
|
506
|
+
}
|
|
507
|
+
else if (compression === "deflate") {
|
|
508
|
+
pixelDataSize = (await (0, tiff_deflate_js_1.deflateCompress)(frame.data)).length;
|
|
509
|
+
}
|
|
510
|
+
else {
|
|
511
|
+
pixelDataSize = frame.data.length;
|
|
512
|
+
}
|
|
473
513
|
this.writeIFDEntry(result, 0x0117, 4, 1, pixelDataSize);
|
|
474
514
|
// XResolution
|
|
475
515
|
const xResOffset = dataOffset;
|
|
@@ -572,7 +612,7 @@ class TIFFFormat {
|
|
|
572
612
|
const isLittleEndian = data[0] === 0x49;
|
|
573
613
|
// Try pure JavaScript decoder first
|
|
574
614
|
try {
|
|
575
|
-
const pureJSResult = this.decodePureJSFromIFD(data, ifdOffset, width, height, isLittleEndian);
|
|
615
|
+
const pureJSResult = await this.decodePureJSFromIFD(data, ifdOffset, width, height, isLittleEndian);
|
|
576
616
|
if (pureJSResult) {
|
|
577
617
|
return pureJSResult;
|
|
578
618
|
}
|
|
@@ -696,7 +736,7 @@ class TIFFFormat {
|
|
|
696
736
|
async decodeUsingRuntime(data, width, height) {
|
|
697
737
|
// Try pure JavaScript decoder first for uncompressed TIFFs
|
|
698
738
|
try {
|
|
699
|
-
const pureJSResult = this.decodePureJS(data, width, height);
|
|
739
|
+
const pureJSResult = await this.decodePureJS(data, width, height);
|
|
700
740
|
if (pureJSResult) {
|
|
701
741
|
return pureJSResult;
|
|
702
742
|
}
|
|
@@ -734,10 +774,10 @@ class TIFFFormat {
|
|
|
734
774
|
return new TextDecoder().decode(data.slice(offset, endIndex));
|
|
735
775
|
}
|
|
736
776
|
/**
|
|
737
|
-
* Pure JavaScript TIFF decoder for uncompressed and
|
|
777
|
+
* Pure JavaScript TIFF decoder for uncompressed, LZW, PackBits, and Deflate-compressed RGB/RGBA images
|
|
738
778
|
* Returns null if the TIFF uses unsupported features
|
|
739
779
|
*/
|
|
740
|
-
decodePureJS(data, width, height) {
|
|
780
|
+
async decodePureJS(data, width, height) {
|
|
741
781
|
// Validate minimum TIFF header size
|
|
742
782
|
if (data.length < 8) {
|
|
743
783
|
return null;
|
|
@@ -748,8 +788,9 @@ class TIFFFormat {
|
|
|
748
788
|
const ifdOffset = this.readUint32(data, 4, isLittleEndian);
|
|
749
789
|
// Check compression
|
|
750
790
|
const compression = this.getIFDValue(data, ifdOffset, 0x0103, isLittleEndian);
|
|
751
|
-
if (compression !== 1 && compression !== 5
|
|
752
|
-
|
|
791
|
+
if (compression !== 1 && compression !== 5 && compression !== 8 &&
|
|
792
|
+
compression !== 32773) {
|
|
793
|
+
// Support: 1 = uncompressed, 5 = LZW, 8 = Deflate, 32773 = PackBits
|
|
753
794
|
return null;
|
|
754
795
|
}
|
|
755
796
|
// Check photometric interpretation
|
|
@@ -791,6 +832,16 @@ class TIFFFormat {
|
|
|
791
832
|
const decoder = new tiff_lzw_js_1.TIFFLZWDecoder(compressedData);
|
|
792
833
|
pixelData = decoder.decompress();
|
|
793
834
|
}
|
|
835
|
+
else if (compression === 32773) {
|
|
836
|
+
// PackBits compressed
|
|
837
|
+
const compressedData = data.slice(stripOffset, stripOffset + stripByteCount);
|
|
838
|
+
pixelData = (0, tiff_packbits_js_1.packBitsDecompress)(compressedData);
|
|
839
|
+
}
|
|
840
|
+
else if (compression === 8) {
|
|
841
|
+
// Deflate compressed
|
|
842
|
+
const compressedData = data.slice(stripOffset, stripOffset + stripByteCount);
|
|
843
|
+
pixelData = await (0, tiff_deflate_js_1.deflateDecompress)(compressedData);
|
|
844
|
+
}
|
|
794
845
|
else {
|
|
795
846
|
// Uncompressed
|
|
796
847
|
pixelData = data.slice(stripOffset, stripOffset + stripByteCount);
|
|
@@ -842,11 +893,12 @@ class TIFFFormat {
|
|
|
842
893
|
* Pure JavaScript TIFF decoder for a specific IFD
|
|
843
894
|
* Returns null if the TIFF uses unsupported features
|
|
844
895
|
*/
|
|
845
|
-
decodePureJSFromIFD(data, ifdOffset, width, height, isLittleEndian) {
|
|
896
|
+
async decodePureJSFromIFD(data, ifdOffset, width, height, isLittleEndian) {
|
|
846
897
|
// Check compression
|
|
847
898
|
const compression = this.getIFDValue(data, ifdOffset, 0x0103, isLittleEndian);
|
|
848
|
-
if (compression !== 1 && compression !== 5
|
|
849
|
-
|
|
899
|
+
if (compression !== 1 && compression !== 5 && compression !== 8 &&
|
|
900
|
+
compression !== 32773) {
|
|
901
|
+
// Support: 1 = uncompressed, 5 = LZW, 8 = Deflate, 32773 = PackBits
|
|
850
902
|
return null;
|
|
851
903
|
}
|
|
852
904
|
// Check photometric interpretation
|
|
@@ -888,6 +940,16 @@ class TIFFFormat {
|
|
|
888
940
|
const decoder = new tiff_lzw_js_1.TIFFLZWDecoder(compressedData);
|
|
889
941
|
pixelData = decoder.decompress();
|
|
890
942
|
}
|
|
943
|
+
else if (compression === 32773) {
|
|
944
|
+
// PackBits compressed
|
|
945
|
+
const compressedData = data.slice(stripOffset, stripOffset + stripByteCount);
|
|
946
|
+
pixelData = (0, tiff_packbits_js_1.packBitsDecompress)(compressedData);
|
|
947
|
+
}
|
|
948
|
+
else if (compression === 8) {
|
|
949
|
+
// Deflate compressed
|
|
950
|
+
const compressedData = data.slice(stripOffset, stripOffset + stripByteCount);
|
|
951
|
+
pixelData = await (0, tiff_deflate_js_1.deflateDecompress)(compressedData);
|
|
952
|
+
}
|
|
891
953
|
else {
|
|
892
954
|
// Uncompressed
|
|
893
955
|
pixelData = data.slice(stripOffset, stripOffset + stripByteCount);
|
|
@@ -1006,9 +1068,12 @@ class TIFFFormat {
|
|
|
1006
1068
|
else if (compression === 5) {
|
|
1007
1069
|
metadata.compression = "lzw";
|
|
1008
1070
|
}
|
|
1009
|
-
else if (compression === 7) {
|
|
1071
|
+
else if (compression === 7 || compression === 6) {
|
|
1010
1072
|
metadata.compression = "jpeg";
|
|
1011
1073
|
}
|
|
1074
|
+
else if (compression === 8) {
|
|
1075
|
+
metadata.compression = "deflate";
|
|
1076
|
+
}
|
|
1012
1077
|
else if (compression === 32773) {
|
|
1013
1078
|
metadata.compression = "packbits";
|
|
1014
1079
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ImageData, ImageFormat, ImageMetadata,
|
|
1
|
+
import type { ImageData, ImageDecoderOptions, ImageFormat, ImageMetadata, WebPEncoderOptions } from "../types.js";
|
|
2
2
|
/**
|
|
3
3
|
* WebP format handler
|
|
4
4
|
* Implements a basic WebP decoder and encoder
|
|
@@ -19,14 +19,14 @@ export declare class WebPFormat implements ImageFormat {
|
|
|
19
19
|
* @param data Raw WebP image data
|
|
20
20
|
* @returns Decoded image data with RGBA pixels
|
|
21
21
|
*/
|
|
22
|
-
decode(data: Uint8Array): Promise<ImageData>;
|
|
22
|
+
decode(data: Uint8Array, settings?: ImageDecoderOptions): Promise<ImageData>;
|
|
23
23
|
/**
|
|
24
24
|
* Encode RGBA image data to WebP format
|
|
25
25
|
* @param imageData Image data to encode
|
|
26
26
|
* @param options Optional WebP encoding options
|
|
27
27
|
* @returns Encoded WebP image bytes
|
|
28
28
|
*/
|
|
29
|
-
encode(imageData: ImageData, options?:
|
|
29
|
+
encode(imageData: ImageData, options?: WebPEncoderOptions): Promise<Uint8Array>;
|
|
30
30
|
private readUint24LE;
|
|
31
31
|
private decodeUsingRuntime;
|
|
32
32
|
private parseEXIF;
|
|
@@ -78,7 +78,7 @@ class WebPFormat {
|
|
|
78
78
|
* @param data Raw WebP image data
|
|
79
79
|
* @returns Decoded image data with RGBA pixels
|
|
80
80
|
*/
|
|
81
|
-
async decode(data) {
|
|
81
|
+
async decode(data, settings) {
|
|
82
82
|
if (!this.canDecode(data)) {
|
|
83
83
|
throw new Error("Invalid WebP signature");
|
|
84
84
|
}
|
|
@@ -144,7 +144,7 @@ class WebPFormat {
|
|
|
144
144
|
(0, security_js_1.validateImageDimensions)(width, height);
|
|
145
145
|
// For a pure JS implementation, we'd need to implement full WebP decoding
|
|
146
146
|
// which is very complex. Instead, we'll use the browser/runtime's decoder.
|
|
147
|
-
const rgba = await this.decodeUsingRuntime(data, width, height);
|
|
147
|
+
const rgba = await this.decodeUsingRuntime(data, width, height, settings);
|
|
148
148
|
return {
|
|
149
149
|
width,
|
|
150
150
|
height,
|
|
@@ -207,9 +207,10 @@ class WebPFormat {
|
|
|
207
207
|
readUint24LE(data, offset) {
|
|
208
208
|
return data[offset] | (data[offset + 1] << 8) | (data[offset + 2] << 16);
|
|
209
209
|
}
|
|
210
|
-
async decodeUsingRuntime(data, _width, _height) {
|
|
210
|
+
async decodeUsingRuntime(data, _width, _height, settings) {
|
|
211
211
|
// Try to use ImageDecoder API if available (Deno, modern browsers)
|
|
212
|
-
if (
|
|
212
|
+
if (settings?.runtimeDecoding !== "never" &&
|
|
213
|
+
typeof ImageDecoder !== "undefined") {
|
|
213
214
|
try {
|
|
214
215
|
const decoder = new ImageDecoder({ data, type: "image/webp" });
|
|
215
216
|
const result = await decoder.decode();
|
|
@@ -224,15 +225,17 @@ class WebPFormat {
|
|
|
224
225
|
bitmap.close();
|
|
225
226
|
return new Uint8Array(imageData.data.buffer);
|
|
226
227
|
}
|
|
227
|
-
catch (
|
|
228
|
+
catch (_error) {
|
|
228
229
|
// ImageDecoder API failed, fall through to pure JS decoder
|
|
229
|
-
console.warn("WebP decoding with ImageDecoder failed, using pure JS decoder:", error);
|
|
230
230
|
}
|
|
231
231
|
}
|
|
232
|
-
// Fallback to pure JavaScript decoder (VP8L lossless only)
|
|
232
|
+
// Fallback to pure JavaScript decoder (VP8L lossless only) with tolerant mode
|
|
233
233
|
try {
|
|
234
234
|
const { WebPDecoder } = await Promise.resolve().then(() => __importStar(require("../utils/webp_decoder.js")));
|
|
235
|
-
const decoder = new WebPDecoder(data
|
|
235
|
+
const decoder = new WebPDecoder(data, {
|
|
236
|
+
tolerantDecoding: settings?.tolerantDecoding ?? true,
|
|
237
|
+
onWarning: settings?.onWarning,
|
|
238
|
+
});
|
|
236
239
|
const result = decoder.decode();
|
|
237
240
|
return result.data;
|
|
238
241
|
}
|
package/script/src/image.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ImageFormat, ImageMetadata, MultiFrameImageData, ResizeOptions } from "./types.js";
|
|
1
|
+
import type { ImageDecoderOptions, ImageFormat, ImageMetadata, MultiFrameImageData, ResizeOptions } from "./types.js";
|
|
2
2
|
/**
|
|
3
3
|
* Main Image class for reading, manipulating, and saving images
|
|
4
4
|
*/
|
|
@@ -78,7 +78,11 @@ export declare class Image {
|
|
|
78
78
|
* @param format Optional format hint (e.g., "png", "jpeg", "webp")
|
|
79
79
|
* @returns Image instance
|
|
80
80
|
*/
|
|
81
|
-
static decode(data: Uint8Array
|
|
81
|
+
static decode(data: Uint8Array): Promise<Image>;
|
|
82
|
+
static decode(data: Uint8Array, format: string): Promise<Image>;
|
|
83
|
+
static decode(data: Uint8Array, format: string, options?: ImageDecoderOptions): Promise<Image>;
|
|
84
|
+
static decode(data: Uint8Array, options?: ImageDecoderOptions): Promise<Image>;
|
|
85
|
+
private static decodeWithSettings;
|
|
82
86
|
/**
|
|
83
87
|
* Get supported metadata fields for a specific format
|
|
84
88
|
* @param format Format name (e.g., "jpeg", "png", "webp")
|
|
@@ -108,7 +112,11 @@ export declare class Image {
|
|
|
108
112
|
* @param format Optional format hint (e.g., "gif", "tiff")
|
|
109
113
|
* @returns MultiFrameImageData with all frames
|
|
110
114
|
*/
|
|
111
|
-
static decodeFrames(data: Uint8Array
|
|
115
|
+
static decodeFrames(data: Uint8Array): Promise<MultiFrameImageData>;
|
|
116
|
+
static decodeFrames(data: Uint8Array, format: string): Promise<MultiFrameImageData>;
|
|
117
|
+
static decodeFrames(data: Uint8Array, format: string, options?: ImageDecoderOptions): Promise<MultiFrameImageData>;
|
|
118
|
+
static decodeFrames(data: Uint8Array, options?: ImageDecoderOptions): Promise<MultiFrameImageData>;
|
|
119
|
+
private static decodeFramesWithSettings;
|
|
112
120
|
/**
|
|
113
121
|
* Read all frames from a multi-frame image (GIF animation, multi-page TIFF)
|
|
114
122
|
* @deprecated Use `decodeFrames()` instead. This method will be removed in a future version.
|
package/script/src/image.js
CHANGED
|
@@ -161,26 +161,37 @@ class Image {
|
|
|
161
161
|
static getFormats() {
|
|
162
162
|
return Image.formats;
|
|
163
163
|
}
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
164
|
+
static async decode(data, formatOrOptions, options) {
|
|
165
|
+
// Backward-compatible overloads:
|
|
166
|
+
// - decode(data)
|
|
167
|
+
// - decode(data, "jpeg")
|
|
168
|
+
// New:
|
|
169
|
+
// - decode(data, { tolerantDecoding, onWarning, runtimeDecoding })
|
|
170
|
+
// - decode(data, "jpeg", { ...options })
|
|
171
|
+
if (typeof formatOrOptions === "string") {
|
|
172
|
+
return await Image.decodeWithSettings(data, formatOrOptions, options);
|
|
173
|
+
}
|
|
174
|
+
return await Image.decodeWithSettings(data, undefined, formatOrOptions);
|
|
175
|
+
}
|
|
176
|
+
static async decodeWithSettings(data, format, settings) {
|
|
171
177
|
const image = new Image();
|
|
178
|
+
const normalizedSettings = {
|
|
179
|
+
tolerantDecoding: settings?.tolerantDecoding ?? true,
|
|
180
|
+
onWarning: settings?.onWarning,
|
|
181
|
+
runtimeDecoding: settings?.runtimeDecoding ?? "prefer",
|
|
182
|
+
};
|
|
172
183
|
// Try specified format first
|
|
173
184
|
if (format) {
|
|
174
185
|
const handler = Image.formats.find((f) => f.name === format);
|
|
175
186
|
if (handler && handler.canDecode(data)) {
|
|
176
|
-
image.imageData = await handler.decode(data);
|
|
187
|
+
image.imageData = await handler.decode(data, normalizedSettings);
|
|
177
188
|
return image;
|
|
178
189
|
}
|
|
179
190
|
}
|
|
180
191
|
// Auto-detect format
|
|
181
192
|
for (const handler of Image.formats) {
|
|
182
193
|
if (handler.canDecode(data)) {
|
|
183
|
-
image.imageData = await handler.decode(data);
|
|
194
|
+
image.imageData = await handler.decode(data, normalizedSettings);
|
|
184
195
|
return image;
|
|
185
196
|
}
|
|
186
197
|
}
|
|
@@ -230,26 +241,31 @@ class Image {
|
|
|
230
241
|
* @returns Image instance
|
|
231
242
|
*/
|
|
232
243
|
static read(data, format) {
|
|
233
|
-
return Image.decode(data, format);
|
|
244
|
+
return format ? Image.decode(data, format) : Image.decode(data);
|
|
234
245
|
}
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
static async
|
|
246
|
+
static async decodeFrames(data, formatOrOptions, options) {
|
|
247
|
+
if (typeof formatOrOptions === "string") {
|
|
248
|
+
return await Image.decodeFramesWithSettings(data, formatOrOptions, options);
|
|
249
|
+
}
|
|
250
|
+
return await Image.decodeFramesWithSettings(data, undefined, formatOrOptions);
|
|
251
|
+
}
|
|
252
|
+
static async decodeFramesWithSettings(data, format, settings) {
|
|
253
|
+
const normalizedSettings = {
|
|
254
|
+
tolerantDecoding: settings?.tolerantDecoding ?? true,
|
|
255
|
+
onWarning: settings?.onWarning,
|
|
256
|
+
runtimeDecoding: settings?.runtimeDecoding ?? "prefer",
|
|
257
|
+
};
|
|
242
258
|
// Try specified format first
|
|
243
259
|
if (format) {
|
|
244
260
|
const handler = Image.formats.find((f) => f.name === format);
|
|
245
261
|
if (handler && handler.canDecode(data) && handler.decodeFrames) {
|
|
246
|
-
return await handler.decodeFrames(data);
|
|
262
|
+
return await handler.decodeFrames(data, normalizedSettings);
|
|
247
263
|
}
|
|
248
264
|
}
|
|
249
265
|
// Auto-detect format
|
|
250
266
|
for (const handler of Image.formats) {
|
|
251
267
|
if (handler.canDecode(data) && handler.decodeFrames) {
|
|
252
|
-
return await handler.decodeFrames(data);
|
|
268
|
+
return await handler.decodeFrames(data, normalizedSettings);
|
|
253
269
|
}
|
|
254
270
|
}
|
|
255
271
|
throw new Error("Unsupported or unrecognized multi-frame image format");
|
|
@@ -262,7 +278,7 @@ class Image {
|
|
|
262
278
|
* @returns MultiFrameImageData with all frames
|
|
263
279
|
*/
|
|
264
280
|
static readFrames(data, format) {
|
|
265
|
-
return Image.decodeFrames(data, format);
|
|
281
|
+
return format ? Image.decodeFrames(data, format) : Image.decodeFrames(data);
|
|
266
282
|
}
|
|
267
283
|
/**
|
|
268
284
|
* Encode multi-frame image data to bytes in the specified format
|
package/script/src/types.d.ts
CHANGED
|
@@ -138,7 +138,7 @@ export interface ResizeOptions {
|
|
|
138
138
|
/**
|
|
139
139
|
* Options for ASCII art encoding
|
|
140
140
|
*/
|
|
141
|
-
export interface
|
|
141
|
+
export interface ASCIIEncoderOptions {
|
|
142
142
|
/** Target width in characters (default: 80) */
|
|
143
143
|
width?: number;
|
|
144
144
|
/** Character set to use (default: "simple") */
|
|
@@ -148,10 +148,21 @@ export interface ASCIIOptions {
|
|
|
148
148
|
/** Whether to invert brightness (default: false) */
|
|
149
149
|
invert?: boolean;
|
|
150
150
|
}
|
|
151
|
+
/**
|
|
152
|
+
* Options for TIFF encoding.
|
|
153
|
+
*/
|
|
154
|
+
export interface TIFFEncoderOptions {
|
|
155
|
+
/** Compression method: "none" (default), "lzw", "packbits", or "deflate" */
|
|
156
|
+
compression?: "none" | "lzw" | "packbits" | "deflate";
|
|
157
|
+
/** Encode as grayscale instead of RGB/RGBA (default: false) */
|
|
158
|
+
grayscale?: boolean;
|
|
159
|
+
/** Encode as RGB without alpha channel (default: false, ignored if grayscale is true) */
|
|
160
|
+
rgb?: boolean;
|
|
161
|
+
}
|
|
151
162
|
/**
|
|
152
163
|
* Options for WebP encoding
|
|
153
164
|
*/
|
|
154
|
-
export interface
|
|
165
|
+
export interface WebPEncoderOptions {
|
|
155
166
|
/**
|
|
156
167
|
* Encoding quality (1-100, default: 90)
|
|
157
168
|
* - 100 = lossless (VP8L)
|
|
@@ -164,6 +175,47 @@ export interface WebPEncodeOptions {
|
|
|
164
175
|
*/
|
|
165
176
|
lossless?: boolean;
|
|
166
177
|
}
|
|
178
|
+
/**
|
|
179
|
+
* Options for JPEG encoding.
|
|
180
|
+
*/
|
|
181
|
+
export interface JPEGEncoderOptions {
|
|
182
|
+
/**
|
|
183
|
+
* Encoding quality (1-100, default depends on encoder backend).
|
|
184
|
+
*/
|
|
185
|
+
quality?: number;
|
|
186
|
+
/**
|
|
187
|
+
* Enable progressive JPEG output when using the pure-JS encoder.
|
|
188
|
+
* Runtime encoders do not currently expose a progressive toggle.
|
|
189
|
+
*/
|
|
190
|
+
progressive?: boolean;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Common options for decode APIs.
|
|
194
|
+
*
|
|
195
|
+
* These options are runtime-agnostic and can be passed to `Image.decode()` and
|
|
196
|
+
* `Image.decodeFrames()`.
|
|
197
|
+
*/
|
|
198
|
+
export interface ImageDecoderOptions {
|
|
199
|
+
/**
|
|
200
|
+
* Controls tolerant decoding in the pure-JS decoders.
|
|
201
|
+
*
|
|
202
|
+
* - true (default): try to recover from corruption and continue
|
|
203
|
+
* - false: strict mode (fail fast)
|
|
204
|
+
*/
|
|
205
|
+
tolerantDecoding?: boolean;
|
|
206
|
+
/**
|
|
207
|
+
* Optional warning callback used by pure-JS decoders when non-fatal issues are
|
|
208
|
+
* encountered.
|
|
209
|
+
*/
|
|
210
|
+
onWarning?: (message: string, details?: unknown) => void;
|
|
211
|
+
/**
|
|
212
|
+
* Runtime decoder strategy.
|
|
213
|
+
*
|
|
214
|
+
* - "prefer" (default): try runtime decoders first (ImageDecoder/Canvas), then fall back to pure JS
|
|
215
|
+
* - "never": skip runtime decoders and use pure JS when available
|
|
216
|
+
*/
|
|
217
|
+
runtimeDecoding?: "prefer" | "never";
|
|
218
|
+
}
|
|
167
219
|
/**
|
|
168
220
|
* Image format handler interface
|
|
169
221
|
*/
|
|
@@ -177,7 +229,7 @@ export interface ImageFormat {
|
|
|
177
229
|
* @param data Raw image data
|
|
178
230
|
* @returns Decoded image data
|
|
179
231
|
*/
|
|
180
|
-
decode(data: Uint8Array): Promise<ImageData>;
|
|
232
|
+
decode(data: Uint8Array, options?: ImageDecoderOptions): Promise<ImageData>;
|
|
181
233
|
/**
|
|
182
234
|
* Encode image data to bytes
|
|
183
235
|
* @param imageData Image data to encode
|
|
@@ -196,7 +248,7 @@ export interface ImageFormat {
|
|
|
196
248
|
* @param data Raw image data
|
|
197
249
|
* @returns Decoded multi-frame image data
|
|
198
250
|
*/
|
|
199
|
-
decodeFrames?(data: Uint8Array): Promise<MultiFrameImageData>;
|
|
251
|
+
decodeFrames?(data: Uint8Array, options?: ImageDecoderOptions): Promise<MultiFrameImageData>;
|
|
200
252
|
/**
|
|
201
253
|
* Encode multi-frame image data to bytes (optional)
|
|
202
254
|
* @param imageData Multi-frame image data to encode
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* Pure JavaScript GIF decoder implementation
|
|
3
3
|
* Supports GIF87a and GIF89a formats with LZW decompression
|
|
4
4
|
*/
|
|
5
|
+
import type { ImageDecoderOptions } from "../types.js";
|
|
5
6
|
interface GIFImage {
|
|
6
7
|
width: number;
|
|
7
8
|
height: number;
|
|
@@ -19,7 +20,8 @@ interface GIFFrame {
|
|
|
19
20
|
export declare class GIFDecoder {
|
|
20
21
|
private data;
|
|
21
22
|
private pos;
|
|
22
|
-
|
|
23
|
+
private options;
|
|
24
|
+
constructor(data: Uint8Array, settings?: ImageDecoderOptions);
|
|
23
25
|
private readByte;
|
|
24
26
|
private readUint16LE;
|
|
25
27
|
private readBytes;
|
|
@@ -36,6 +38,7 @@ export declare class GIFDecoder {
|
|
|
36
38
|
frames: GIFFrame[];
|
|
37
39
|
};
|
|
38
40
|
private indexedToRGBA;
|
|
41
|
+
private decodeFrame;
|
|
39
42
|
private deinterlace;
|
|
40
43
|
}
|
|
41
44
|
export {};
|