cross-image 0.2.3 → 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 +292 -74
- package/esm/mod.d.ts +6 -4
- package/esm/mod.js +4 -2
- package/esm/src/formats/apng.d.ts +17 -5
- package/esm/src/formats/apng.js +104 -9
- package/esm/src/formats/ascii.d.ts +13 -3
- package/esm/src/formats/ascii.js +25 -1
- package/esm/src/formats/avif.d.ts +96 -0
- package/esm/src/formats/avif.js +607 -0
- package/esm/src/formats/bmp.d.ts +13 -3
- package/esm/src/formats/bmp.js +75 -2
- package/esm/src/formats/dng.d.ts +14 -2
- package/esm/src/formats/dng.js +27 -5
- package/esm/src/formats/gif.d.ts +18 -5
- package/esm/src/formats/gif.js +160 -14
- package/esm/src/formats/heic.d.ts +96 -0
- package/esm/src/formats/heic.js +608 -0
- package/esm/src/formats/ico.d.ts +13 -3
- package/esm/src/formats/ico.js +32 -4
- package/esm/src/formats/jpeg.d.ts +10 -3
- package/esm/src/formats/jpeg.js +99 -11
- package/esm/src/formats/pam.d.ts +13 -3
- package/esm/src/formats/pam.js +68 -2
- package/esm/src/formats/pcx.d.ts +13 -3
- package/esm/src/formats/pcx.js +47 -2
- package/esm/src/formats/png.d.ts +15 -3
- package/esm/src/formats/png.js +89 -2
- package/esm/src/formats/png_base.js +2 -5
- package/esm/src/formats/ppm.d.ts +13 -3
- package/esm/src/formats/ppm.js +36 -2
- package/esm/src/formats/tiff.d.ts +14 -18
- package/esm/src/formats/tiff.js +219 -20
- package/esm/src/formats/webp.d.ts +10 -3
- package/esm/src/formats/webp.js +103 -8
- package/esm/src/image.d.ts +20 -3
- package/esm/src/image.js +65 -21
- package/esm/src/types.d.ts +74 -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 +18 -1
- package/script/mod.d.ts +6 -4
- package/script/mod.js +7 -3
- package/script/src/formats/apng.d.ts +17 -5
- package/script/src/formats/apng.js +104 -9
- package/script/src/formats/ascii.d.ts +13 -3
- package/script/src/formats/ascii.js +25 -1
- package/script/src/formats/avif.d.ts +96 -0
- package/script/src/formats/avif.js +611 -0
- package/script/src/formats/bmp.d.ts +13 -3
- package/script/src/formats/bmp.js +75 -2
- package/script/src/formats/dng.d.ts +14 -2
- package/script/src/formats/dng.js +27 -5
- package/script/src/formats/gif.d.ts +18 -5
- package/script/src/formats/gif.js +160 -14
- package/script/src/formats/heic.d.ts +96 -0
- package/script/src/formats/heic.js +612 -0
- package/script/src/formats/ico.d.ts +13 -3
- package/script/src/formats/ico.js +32 -4
- package/script/src/formats/jpeg.d.ts +10 -3
- package/script/src/formats/jpeg.js +99 -11
- package/script/src/formats/pam.d.ts +13 -3
- package/script/src/formats/pam.js +68 -2
- package/script/src/formats/pcx.d.ts +13 -3
- package/script/src/formats/pcx.js +47 -2
- package/script/src/formats/png.d.ts +15 -3
- package/script/src/formats/png.js +89 -2
- package/script/src/formats/png_base.js +2 -5
- package/script/src/formats/ppm.d.ts +13 -3
- package/script/src/formats/ppm.js +36 -2
- package/script/src/formats/tiff.d.ts +14 -18
- package/script/src/formats/tiff.js +219 -20
- package/script/src/formats/webp.d.ts +10 -3
- package/script/src/formats/webp.js +103 -8
- package/script/src/image.d.ts +20 -3
- package/script/src/image.js +64 -20
- package/script/src/types.d.ts +74 -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
|
@@ -19,9 +19,11 @@
|
|
|
19
19
|
* @see https://developers.google.com/speed/webp/docs/riff_container
|
|
20
20
|
* @see https://developers.google.com/speed/webp/docs/webp_lossless_bitstream_specification
|
|
21
21
|
*/
|
|
22
|
+
import type { ImageDecoderOptions } from "../types.js";
|
|
22
23
|
export declare class WebPDecoder {
|
|
23
24
|
private data;
|
|
24
|
-
|
|
25
|
+
private options;
|
|
26
|
+
constructor(data: Uint8Array, settings?: ImageDecoderOptions);
|
|
25
27
|
decode(): {
|
|
26
28
|
width: number;
|
|
27
29
|
height: number;
|
|
@@ -93,7 +93,6 @@ class HuffmanTable {
|
|
|
93
93
|
const bit = reader.readBits(1);
|
|
94
94
|
node = bit === 0 ? node.left : node.right;
|
|
95
95
|
if (!node) {
|
|
96
|
-
// console.log("Invalid Huffman code - walked off tree");
|
|
97
96
|
throw new Error("Invalid Huffman code");
|
|
98
97
|
}
|
|
99
98
|
}
|
|
@@ -164,14 +163,24 @@ class BitReader {
|
|
|
164
163
|
}
|
|
165
164
|
}
|
|
166
165
|
export class WebPDecoder {
|
|
167
|
-
constructor(data) {
|
|
166
|
+
constructor(data, settings = {}) {
|
|
168
167
|
Object.defineProperty(this, "data", {
|
|
169
168
|
enumerable: true,
|
|
170
169
|
configurable: true,
|
|
171
170
|
writable: true,
|
|
172
171
|
value: void 0
|
|
173
172
|
});
|
|
173
|
+
Object.defineProperty(this, "options", {
|
|
174
|
+
enumerable: true,
|
|
175
|
+
configurable: true,
|
|
176
|
+
writable: true,
|
|
177
|
+
value: void 0
|
|
178
|
+
});
|
|
174
179
|
this.data = data;
|
|
180
|
+
this.options = {
|
|
181
|
+
tolerantDecoding: settings.tolerantDecoding ?? true,
|
|
182
|
+
onWarning: settings.onWarning,
|
|
183
|
+
};
|
|
175
184
|
}
|
|
176
185
|
decode() {
|
|
177
186
|
// Verify WebP signature
|
|
@@ -278,66 +287,142 @@ export class WebPDecoder {
|
|
|
278
287
|
const numPixels = width * height;
|
|
279
288
|
// Color cache for repeated colors
|
|
280
289
|
const colorCache = new Uint32Array(colorCacheSize);
|
|
281
|
-
|
|
282
|
-
//
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
290
|
+
if (this.options.tolerantDecoding) {
|
|
291
|
+
// Tolerant mode: continue decoding even if errors occur
|
|
292
|
+
try {
|
|
293
|
+
for (let i = 0; i < numPixels;) {
|
|
294
|
+
// Read green channel (which determines the code type)
|
|
295
|
+
const green = huffmanTables.green.readSymbol(reader);
|
|
296
|
+
if (green < 256) {
|
|
297
|
+
// Literal pixel
|
|
298
|
+
const red = huffmanTables.red.readSymbol(reader);
|
|
299
|
+
const blue = huffmanTables.blue.readSymbol(reader);
|
|
300
|
+
const alpha = alphaUsed !== 0 ? huffmanTables.alpha.readSymbol(reader) : 255;
|
|
301
|
+
pixelData[pixelIndex++] = red;
|
|
302
|
+
pixelData[pixelIndex++] = green;
|
|
303
|
+
pixelData[pixelIndex++] = blue;
|
|
304
|
+
pixelData[pixelIndex++] = alpha;
|
|
305
|
+
// Add to color cache if enabled
|
|
306
|
+
if (useColorCache) {
|
|
307
|
+
const color = (alpha << 24) | (blue << 16) | (green << 8) | red;
|
|
308
|
+
colorCache[i % colorCacheSize] = color;
|
|
309
|
+
}
|
|
310
|
+
i++;
|
|
311
|
+
}
|
|
312
|
+
else if (green < 256 + 24) {
|
|
313
|
+
// Backward reference (LZ77)
|
|
314
|
+
const lengthSymbol = green - 256;
|
|
315
|
+
const length = this.getLength(lengthSymbol, reader);
|
|
316
|
+
const distancePrefix = huffmanTables.distance.readSymbol(reader);
|
|
317
|
+
const distance = this.getDistance(distancePrefix, reader);
|
|
318
|
+
// Copy pixels from earlier in the stream
|
|
319
|
+
const srcIndex = pixelIndex - distance * 4;
|
|
320
|
+
if (srcIndex < 0) {
|
|
321
|
+
throw new Error("Invalid backward reference");
|
|
322
|
+
}
|
|
323
|
+
for (let j = 0; j < length; j++) {
|
|
324
|
+
pixelData[pixelIndex++] = pixelData[srcIndex + j * 4];
|
|
325
|
+
pixelData[pixelIndex++] = pixelData[srcIndex + j * 4 + 1];
|
|
326
|
+
pixelData[pixelIndex++] = pixelData[srcIndex + j * 4 + 2];
|
|
327
|
+
pixelData[pixelIndex++] = pixelData[srcIndex + j * 4 + 3];
|
|
328
|
+
// Add to color cache
|
|
329
|
+
if (useColorCache) {
|
|
330
|
+
const color = (pixelData[pixelIndex - 1] << 24) |
|
|
331
|
+
(pixelData[pixelIndex - 2] << 16) |
|
|
332
|
+
(pixelData[pixelIndex - 3] << 8) |
|
|
333
|
+
pixelData[pixelIndex - 4];
|
|
334
|
+
colorCache[(i + j) % colorCacheSize] = color;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
i += length;
|
|
338
|
+
}
|
|
339
|
+
else {
|
|
340
|
+
// Color cache reference
|
|
341
|
+
const cacheIndex = green - 256 - 24;
|
|
342
|
+
if (cacheIndex >= colorCacheSize) {
|
|
343
|
+
throw new Error("Invalid color cache index");
|
|
344
|
+
}
|
|
345
|
+
const color = colorCache[cacheIndex];
|
|
346
|
+
pixelData[pixelIndex++] = color & 0xff; // R
|
|
347
|
+
pixelData[pixelIndex++] = (color >> 8) & 0xff; // G
|
|
348
|
+
pixelData[pixelIndex++] = (color >> 16) & 0xff; // B
|
|
349
|
+
pixelData[pixelIndex++] = (color >> 24) & 0xff; // A
|
|
350
|
+
i++;
|
|
351
|
+
}
|
|
299
352
|
}
|
|
300
|
-
i++;
|
|
301
353
|
}
|
|
302
|
-
|
|
303
|
-
//
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
if (srcIndex < 0) {
|
|
311
|
-
throw new Error("Invalid backward reference");
|
|
354
|
+
catch (e) {
|
|
355
|
+
// Tolerant decoding: fill remaining pixels with gray (128, 128, 128, 255)
|
|
356
|
+
this.options.onWarning?.(`WebP VP8L: Partial decode at pixel ${pixelIndex / 4}/${numPixels}`, e);
|
|
357
|
+
while (pixelIndex < pixelData.length) {
|
|
358
|
+
pixelData[pixelIndex++] = 128; // R
|
|
359
|
+
pixelData[pixelIndex++] = 128; // G
|
|
360
|
+
pixelData[pixelIndex++] = 128; // B
|
|
361
|
+
pixelData[pixelIndex++] = 255; // A
|
|
312
362
|
}
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
else {
|
|
366
|
+
// Non-tolerant mode: throw on first error
|
|
367
|
+
for (let i = 0; i < numPixels;) {
|
|
368
|
+
// Read green channel (which determines the code type)
|
|
369
|
+
const green = huffmanTables.green.readSymbol(reader);
|
|
370
|
+
if (green < 256) {
|
|
371
|
+
// Literal pixel
|
|
372
|
+
const red = huffmanTables.red.readSymbol(reader);
|
|
373
|
+
const blue = huffmanTables.blue.readSymbol(reader);
|
|
374
|
+
const alpha = alphaUsed !== 0 ? huffmanTables.alpha.readSymbol(reader) : 255;
|
|
375
|
+
pixelData[pixelIndex++] = red;
|
|
376
|
+
pixelData[pixelIndex++] = green;
|
|
377
|
+
pixelData[pixelIndex++] = blue;
|
|
378
|
+
pixelData[pixelIndex++] = alpha;
|
|
379
|
+
// Add to color cache if enabled
|
|
319
380
|
if (useColorCache) {
|
|
320
|
-
const color = (
|
|
321
|
-
|
|
322
|
-
(pixelData[pixelIndex - 3] << 8) |
|
|
323
|
-
pixelData[pixelIndex - 4];
|
|
324
|
-
colorCache[(i + j) % colorCacheSize] = color;
|
|
381
|
+
const color = (alpha << 24) | (blue << 16) | (green << 8) | red;
|
|
382
|
+
colorCache[i % colorCacheSize] = color;
|
|
325
383
|
}
|
|
384
|
+
i++;
|
|
326
385
|
}
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
386
|
+
else if (green < 256 + 24) {
|
|
387
|
+
// Backward reference (LZ77)
|
|
388
|
+
const lengthSymbol = green - 256;
|
|
389
|
+
const length = this.getLength(lengthSymbol, reader);
|
|
390
|
+
const distancePrefix = huffmanTables.distance.readSymbol(reader);
|
|
391
|
+
const distance = this.getDistance(distancePrefix, reader);
|
|
392
|
+
// Copy pixels from earlier in the stream
|
|
393
|
+
const srcIndex = pixelIndex - distance * 4;
|
|
394
|
+
if (srcIndex < 0) {
|
|
395
|
+
throw new Error("Invalid backward reference");
|
|
396
|
+
}
|
|
397
|
+
for (let j = 0; j < length; j++) {
|
|
398
|
+
pixelData[pixelIndex++] = pixelData[srcIndex + j * 4];
|
|
399
|
+
pixelData[pixelIndex++] = pixelData[srcIndex + j * 4 + 1];
|
|
400
|
+
pixelData[pixelIndex++] = pixelData[srcIndex + j * 4 + 2];
|
|
401
|
+
pixelData[pixelIndex++] = pixelData[srcIndex + j * 4 + 3];
|
|
402
|
+
// Add to color cache
|
|
403
|
+
if (useColorCache) {
|
|
404
|
+
const color = (pixelData[pixelIndex - 1] << 24) |
|
|
405
|
+
(pixelData[pixelIndex - 2] << 16) |
|
|
406
|
+
(pixelData[pixelIndex - 3] << 8) |
|
|
407
|
+
pixelData[pixelIndex - 4];
|
|
408
|
+
colorCache[(i + j) % colorCacheSize] = color;
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
i += length;
|
|
412
|
+
}
|
|
413
|
+
else {
|
|
414
|
+
// Color cache reference
|
|
415
|
+
const cacheIndex = green - 256 - 24;
|
|
416
|
+
if (cacheIndex >= colorCacheSize) {
|
|
417
|
+
throw new Error("Invalid color cache index");
|
|
418
|
+
}
|
|
419
|
+
const color = colorCache[cacheIndex];
|
|
420
|
+
pixelData[pixelIndex++] = color & 0xff; // R
|
|
421
|
+
pixelData[pixelIndex++] = (color >> 8) & 0xff; // G
|
|
422
|
+
pixelData[pixelIndex++] = (color >> 16) & 0xff; // B
|
|
423
|
+
pixelData[pixelIndex++] = (color >> 24) & 0xff; // A
|
|
424
|
+
i++;
|
|
334
425
|
}
|
|
335
|
-
const color = colorCache[cacheIndex];
|
|
336
|
-
pixelData[pixelIndex++] = color & 0xff; // R
|
|
337
|
-
pixelData[pixelIndex++] = (color >> 8) & 0xff; // G
|
|
338
|
-
pixelData[pixelIndex++] = (color >> 16) & 0xff; // B
|
|
339
|
-
pixelData[pixelIndex++] = (color >> 24) & 0xff; // A
|
|
340
|
-
i++;
|
|
341
426
|
}
|
|
342
427
|
}
|
|
343
428
|
return pixelData;
|
|
@@ -378,9 +463,7 @@ export class WebPDecoder {
|
|
|
378
463
|
const isFirstEightBits = reader.readBits(1);
|
|
379
464
|
const symbols = [];
|
|
380
465
|
for (let i = 0; i < numSymbols; i++) {
|
|
381
|
-
const symbolBits = isFirstEightBits
|
|
382
|
-
? reader.readBits(8)
|
|
383
|
-
: reader.readBits(1);
|
|
466
|
+
const symbolBits = isFirstEightBits ? reader.readBits(8) : reader.readBits(1);
|
|
384
467
|
symbols.push(symbolBits);
|
|
385
468
|
}
|
|
386
469
|
// Build simple Huffman table
|
|
@@ -396,9 +479,7 @@ export class WebPDecoder {
|
|
|
396
479
|
}
|
|
397
480
|
else {
|
|
398
481
|
// Complex code - read code lengths
|
|
399
|
-
const maxSymbol = isGreen
|
|
400
|
-
? (256 + 24 + (useColorCache ? (1 << colorCacheBits) : 0))
|
|
401
|
-
: 256;
|
|
482
|
+
const maxSymbol = isGreen ? (256 + 24 + (useColorCache ? (1 << colorCacheBits) : 0)) : 256;
|
|
402
483
|
const codeLengths = this.readCodeLengths(reader, maxSymbol);
|
|
403
484
|
this.buildHuffmanTable(table, codeLengths);
|
|
404
485
|
}
|
|
@@ -406,7 +487,7 @@ export class WebPDecoder {
|
|
|
406
487
|
readCodeLengths(reader, maxSymbol) {
|
|
407
488
|
// Read code length codes (used to encode the actual code lengths)
|
|
408
489
|
const numCodeLengthCodes = reader.readBits(4) + 4;
|
|
409
|
-
const codeLengthCodeLengths = new
|
|
490
|
+
const codeLengthCodeLengths = new Uint8Array(19);
|
|
410
491
|
// Code length code order
|
|
411
492
|
const codeLengthCodeOrder = [
|
|
412
493
|
17,
|
|
@@ -442,7 +523,7 @@ export class WebPDecoder {
|
|
|
442
523
|
const codeLengthTable = new HuffmanTable();
|
|
443
524
|
this.buildHuffmanTable(codeLengthTable, codeLengthCodeLengths);
|
|
444
525
|
// Read actual code lengths
|
|
445
|
-
const codeLengths = new
|
|
526
|
+
const codeLengths = new Uint8Array(maxSymbol);
|
|
446
527
|
let i = 0;
|
|
447
528
|
while (i < maxSymbol) {
|
|
448
529
|
const code = codeLengthTable.readSymbol(reader);
|
|
@@ -369,7 +369,7 @@ export class WebPEncoder {
|
|
|
369
369
|
* Returns an array where index is the symbol and value is the code length
|
|
370
370
|
*/
|
|
371
371
|
calculateCodeLengths(frequencies, maxSymbol, maxCodeLength = 15) {
|
|
372
|
-
const codeLengths = new
|
|
372
|
+
const codeLengths = new Uint8Array(maxSymbol);
|
|
373
373
|
// Get symbols with non-zero frequencies
|
|
374
374
|
const symbols = Array.from(frequencies.keys()).sort((a, b) => a - b);
|
|
375
375
|
if (symbols.length === 0)
|
|
@@ -377,7 +377,6 @@ export class WebPEncoder {
|
|
|
377
377
|
// For a single symbol, use code length 1
|
|
378
378
|
// (Canonical Huffman codes require length >= 1)
|
|
379
379
|
if (symbols.length === 1) {
|
|
380
|
-
// console.log(`Single symbol ${symbols[0]}, forcing length 1`);
|
|
381
380
|
codeLengths[symbols[0]] = 1;
|
|
382
381
|
return codeLengths;
|
|
383
382
|
}
|
|
@@ -424,7 +423,6 @@ export class WebPEncoder {
|
|
|
424
423
|
// If tree is too deep, flatten frequencies and rebuild
|
|
425
424
|
let attempts = 0;
|
|
426
425
|
while (maxDepth > maxCodeLength && attempts < 5) {
|
|
427
|
-
// console.log(`Tree too deep (${maxDepth} > ${maxCodeLength}), flattening...`);
|
|
428
426
|
attempts++;
|
|
429
427
|
// Add bias to frequencies to flatten the tree
|
|
430
428
|
// Increase bias with each attempt
|
|
@@ -439,11 +437,8 @@ export class WebPEncoder {
|
|
|
439
437
|
maxDepth = 0;
|
|
440
438
|
checkDepth(root, 0);
|
|
441
439
|
}
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
// Force hard limit by sorting and assigning lengths?
|
|
445
|
-
// For now, let's just see if this is happening.
|
|
446
|
-
}
|
|
440
|
+
// If tree depth couldn't be reduced, encoding may fail but we'll try anyway
|
|
441
|
+
// This is an internal limitation that doesn't affect most images
|
|
447
442
|
// Calculate code lengths by traversing tree (iterative to avoid deep recursion)
|
|
448
443
|
const stack = [{
|
|
449
444
|
node: root,
|
|
@@ -485,7 +480,7 @@ export class WebPEncoder {
|
|
|
485
480
|
}
|
|
486
481
|
}
|
|
487
482
|
// Count symbols at each length
|
|
488
|
-
const lengthCounts = new
|
|
483
|
+
const lengthCounts = new Uint32Array(maxLength + 1);
|
|
489
484
|
for (let i = 0; i < codeLengths.length; i++) {
|
|
490
485
|
if (codeLengths[i] > 0) {
|
|
491
486
|
lengthCounts[codeLengths[i]]++;
|
|
@@ -493,7 +488,7 @@ export class WebPEncoder {
|
|
|
493
488
|
}
|
|
494
489
|
// Generate first code for each length
|
|
495
490
|
let code = 0;
|
|
496
|
-
const nextCode = new
|
|
491
|
+
const nextCode = new Uint32Array(maxLength + 1);
|
|
497
492
|
for (let len = 1; len <= maxLength; len++) {
|
|
498
493
|
code = (code + lengthCounts[len - 1]) << 1;
|
|
499
494
|
nextCode[len] = code;
|
|
@@ -625,7 +620,6 @@ export class WebPEncoder {
|
|
|
625
620
|
}
|
|
626
621
|
numCodeLengthCodes = Math.max(4, numCodeLengthCodes);
|
|
627
622
|
// Write number of code length codes
|
|
628
|
-
// console.log(`Complex Huffman: numCodeLengthCodes=${numCodeLengthCodes}, rleEncoded.length=${rleEncoded.length}`);
|
|
629
623
|
writer.writeBits(numCodeLengthCodes - 4, 4);
|
|
630
624
|
// Write code length code lengths
|
|
631
625
|
for (let i = 0; i < numCodeLengthCodes; i++) {
|
package/package.json
CHANGED
|
@@ -1,20 +1,34 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cross-image",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
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
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*
|
|
8
8
|
* @example
|
|
9
9
|
* ```ts
|
|
10
|
-
* import { Image } from "
|
|
10
|
+
* import { Image } from "jsr:@cross/image";
|
|
11
11
|
*
|
|
12
12
|
* // Decode an image
|
|
13
13
|
* const data = await Deno.readFile("input.png");
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
*
|
|
27
27
|
* @example
|
|
28
28
|
* ```ts
|
|
29
|
-
* import { Image } from "
|
|
29
|
+
* import { Image } from "jsr:@cross/image";
|
|
30
30
|
*
|
|
31
31
|
* // Create a blank canvas
|
|
32
32
|
* const canvas = Image.create(400, 300, 255, 255, 255);
|
|
@@ -43,13 +43,13 @@
|
|
|
43
43
|
* ```
|
|
44
44
|
*/
|
|
45
45
|
export { Image } from "./src/image.js";
|
|
46
|
-
export type {
|
|
46
|
+
export type { ASCIIEncoderOptions, FrameMetadata, ImageData, ImageDecoderOptions, ImageFormat, ImageFrame, ImageMetadata, JPEGEncoderOptions, MultiFrameImageData, ResizeOptions, TIFFEncoderOptions, WebPEncoderOptions, } from "./src/types.js";
|
|
47
47
|
export { PNGFormat } from "./src/formats/png.js";
|
|
48
48
|
export { APNGFormat } from "./src/formats/apng.js";
|
|
49
49
|
export { JPEGFormat } from "./src/formats/jpeg.js";
|
|
50
50
|
export { WebPFormat } from "./src/formats/webp.js";
|
|
51
51
|
export { GIFFormat } from "./src/formats/gif.js";
|
|
52
|
-
export {
|
|
52
|
+
export { TIFFFormat } from "./src/formats/tiff.js";
|
|
53
53
|
export { BMPFormat } from "./src/formats/bmp.js";
|
|
54
54
|
export { ICOFormat } from "./src/formats/ico.js";
|
|
55
55
|
export { DNGFormat } from "./src/formats/dng.js";
|
|
@@ -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
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*
|
|
9
9
|
* @example
|
|
10
10
|
* ```ts
|
|
11
|
-
* import { Image } from "
|
|
11
|
+
* import { Image } from "jsr:@cross/image";
|
|
12
12
|
*
|
|
13
13
|
* // Decode an image
|
|
14
14
|
* const data = await Deno.readFile("input.png");
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
*
|
|
28
28
|
* @example
|
|
29
29
|
* ```ts
|
|
30
|
-
* import { Image } from "
|
|
30
|
+
* import { Image } from "jsr:@cross/image";
|
|
31
31
|
*
|
|
32
32
|
* // Create a blank canvas
|
|
33
33
|
* const canvas = Image.create(400, 300, 255, 255, 255);
|
|
@@ -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, ImageDecoderOptions, ImageFormat, ImageMetadata, MultiFrameImageData } from "../types.js";
|
|
2
2
|
import { PNGBase } from "./png_base.js";
|
|
3
3
|
/**
|
|
4
4
|
* APNG (Animated PNG) format handler
|
|
@@ -26,25 +26,37 @@ export declare class APNGFormat extends PNGBase implements ImageFormat {
|
|
|
26
26
|
* @param data Raw APNG image data
|
|
27
27
|
* @returns Decoded image data with RGBA pixels of first frame
|
|
28
28
|
*/
|
|
29
|
-
decode(data: Uint8Array): Promise<ImageData>;
|
|
29
|
+
decode(data: Uint8Array, settings?: ImageDecoderOptions): Promise<ImageData>;
|
|
30
30
|
/**
|
|
31
31
|
* Decode all frames from APNG image
|
|
32
32
|
* @param data Raw APNG image data
|
|
33
33
|
* @returns Decoded multi-frame image data
|
|
34
34
|
*/
|
|
35
|
-
decodeFrames(data: Uint8Array): Promise<MultiFrameImageData>;
|
|
35
|
+
decodeFrames(data: Uint8Array, _settings?: ImageDecoderOptions): Promise<MultiFrameImageData>;
|
|
36
36
|
/**
|
|
37
37
|
* Encode RGBA image data to APNG format (single frame)
|
|
38
38
|
* @param imageData Image data to encode
|
|
39
39
|
* @returns Encoded APNG image bytes
|
|
40
40
|
*/
|
|
41
|
-
encode(imageData: ImageData): Promise<Uint8Array>;
|
|
41
|
+
encode(imageData: ImageData, _options?: unknown): Promise<Uint8Array>;
|
|
42
42
|
/**
|
|
43
43
|
* Encode multi-frame image data to APNG format
|
|
44
44
|
* @param imageData Multi-frame image data to encode
|
|
45
45
|
* @returns Encoded APNG image bytes
|
|
46
46
|
*/
|
|
47
|
-
encodeFrames(imageData: MultiFrameImageData): Promise<Uint8Array>;
|
|
47
|
+
encodeFrames(imageData: MultiFrameImageData, _options?: unknown): 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
|