pdf-parser.js 5.2.27 → 5.2.28
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/dist/{afm-widths-BYiX2L9D.cjs → afm-widths-BHD2HZIL.cjs} +553 -642
- package/dist/{afm-widths-blUDDjlI.js → afm-widths-B_IGbGky.js} +553 -642
- package/dist/afm-widths.cjs +1 -1
- package/dist/afm-widths.js +1 -1
- package/dist/annotations.cjs +5 -3
- package/dist/annotations.js +5 -3
- package/dist/builtin-encoding.cjs +17 -6
- package/dist/builtin-encoding.js +17 -6
- package/dist/bytes/crc32.cjs +5 -3
- package/dist/bytes/crc32.js +5 -3
- package/dist/bytes/flate.cjs +0 -1
- package/dist/bytes/flate.js +0 -1
- package/dist/cff-bounds.cjs +42 -24
- package/dist/cff-bounds.js +42 -24
- package/dist/cff.cjs +13 -6
- package/dist/cff.js +13 -6
- package/dist/cmap-table.cjs +54 -26
- package/dist/cmap-table.js +54 -26
- package/dist/cmap.cjs +5 -3
- package/dist/cmap.js +5 -3
- package/dist/content-write.cjs +3 -2
- package/dist/content-write.js +3 -2
- package/dist/crypto/aes.cjs +76 -55
- package/dist/crypto/aes.js +76 -55
- package/dist/crypto/md5.cjs +345 -149
- package/dist/crypto/md5.js +345 -149
- package/dist/crypto/rc4.cjs +5 -4
- package/dist/crypto/rc4.js +5 -4
- package/dist/crypto/sha2.cjs +92 -43
- package/dist/crypto/sha2.js +92 -43
- package/dist/embedded-font.cjs +4 -2
- package/dist/embedded-font.js +4 -2
- package/dist/encoding.cjs +1 -1
- package/dist/encoding.js +1 -1
- package/dist/encrypt-write.cjs +25 -21
- package/dist/encrypt-write.js +25 -21
- package/dist/encrypt.cjs +43 -64
- package/dist/encrypt.js +43 -64
- package/dist/filters.cjs +40 -20
- package/dist/filters.js +40 -20
- package/dist/font-face.cjs +2 -1
- package/dist/font-face.js +2 -1
- package/dist/font-read.cjs +12 -6
- package/dist/font-read.js +12 -6
- package/dist/font-tables.cjs +55 -28
- package/dist/font-tables.js +55 -28
- package/dist/gdef-table.cjs +6 -3
- package/dist/gdef-table.js +6 -3
- package/dist/glyf-contours.cjs +3 -1
- package/dist/glyf-contours.js +3 -1
- package/dist/glyf.cjs +22 -11
- package/dist/glyf.js +22 -11
- package/dist/gpos-table.cjs +37 -19
- package/dist/gpos-table.js +37 -19
- package/dist/gsub-table.cjs +28 -17
- package/dist/gsub-table.js +28 -17
- package/dist/hmtx-table.cjs +5 -3
- package/dist/hmtx-table.js +5 -3
- package/dist/image/ccitt-encode.cjs +8 -5
- package/dist/image/ccitt-encode.js +8 -5
- package/dist/image/ccitt.cjs +801 -209
- package/dist/image/ccitt.js +801 -209
- package/dist/image/jbig2-arith.cjs +340 -306
- package/dist/image/jbig2-arith.js +340 -306
- package/dist/image/jbig2-bitmap.cjs +8 -5
- package/dist/image/jbig2-bitmap.js +8 -5
- package/dist/image/jbig2-generic.cjs +240 -69
- package/dist/image/jbig2-generic.js +240 -69
- package/dist/image/jbig2-text.cjs +4 -2
- package/dist/image/jbig2-text.js +4 -2
- package/dist/image/jbig2.cjs +69 -31
- package/dist/image/jbig2.js +69 -31
- package/dist/image/jp2-boxes.cjs +52 -27
- package/dist/image/jp2-boxes.js +52 -27
- package/dist/image/jpeg-info.cjs +29 -24
- package/dist/image/jpeg-info.js +29 -24
- package/dist/image/jpeg2000-codestream.cjs +44 -24
- package/dist/image/jpeg2000-codestream.js +44 -24
- package/dist/image/jpeg2000-dwt.cjs +2 -1
- package/dist/image/jpeg2000-dwt.js +2 -1
- package/dist/image/jpeg2000-t1.cjs +21 -11
- package/dist/image/jpeg2000-t1.js +21 -11
- package/dist/image/jpeg2000-t2.cjs +12 -5
- package/dist/image/jpeg2000-t2.js +12 -5
- package/dist/image/jpeg2000-tagtree.cjs +8 -4
- package/dist/image/jpeg2000-tagtree.js +8 -4
- package/dist/image/jpeg2000.cjs +11 -6
- package/dist/image/jpeg2000.js +11 -6
- package/dist/image/png-decode.cjs +62 -39
- package/dist/image/png-decode.d.cts +3 -2
- package/dist/image/png-decode.d.ts +3 -2
- package/dist/image/png-decode.js +62 -39
- package/dist/image/png-filter.cjs +23 -15
- package/dist/image/png-filter.js +23 -15
- package/dist/images-read.cjs +41 -36
- package/dist/images-read.js +41 -36
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/dist/interpret.cjs +39 -24
- package/dist/interpret.js +39 -24
- package/dist/lexer.cjs +86 -51
- package/dist/lexer.js +86 -51
- package/dist/math-content-write.cjs +9 -5
- package/dist/math-content-write.js +9 -5
- package/dist/math-font-write.cjs +2 -1
- package/dist/math-font-write.js +2 -1
- package/dist/math-font.cjs +16 -7
- package/dist/math-font.js +16 -7
- package/dist/math-table.cjs +25 -13
- package/dist/math-table.js +25 -13
- package/dist/matrix.cjs +3 -2
- package/dist/matrix.js +3 -2
- package/dist/measure.cjs +1 -1
- package/dist/measure.js +1 -1
- package/dist/navigation.cjs +10 -5
- package/dist/navigation.js +10 -5
- package/dist/ot-layout-common.cjs +4 -2
- package/dist/ot-layout-common.js +4 -2
- package/dist/parse.cjs +7 -5
- package/dist/parse.js +7 -5
- package/dist/pdf-text.cjs +5 -2
- package/dist/pdf-text.js +5 -2
- package/dist/predictors.cjs +14 -9
- package/dist/predictors.js +14 -9
- package/dist/raster.cjs +30 -19
- package/dist/raster.js +30 -19
- package/dist/read.cjs +17 -8
- package/dist/read.js +17 -8
- package/dist/serialize.cjs +6 -2
- package/dist/serialize.js +6 -2
- package/dist/sfnt-subset.cjs +25 -13
- package/dist/sfnt-subset.js +25 -13
- package/dist/sfnt.cjs +20 -10
- package/dist/sfnt.js +20 -10
- package/dist/text-group.cjs +0 -1
- package/dist/text-group.js +0 -1
- package/dist/tounicode.cjs +4 -2
- package/dist/tounicode.js +4 -2
- package/dist/winansi.cjs +1 -1
- package/dist/winansi.js +1 -1
- package/dist/write.cjs +20 -12
- package/dist/write.js +20 -12
- package/dist/xref.cjs +5 -2
- package/dist/xref.js +5 -2
- package/package.json +1 -1
|
@@ -2,6 +2,10 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
|
2
2
|
const require_image_jpeg2000_errors = require("./jpeg2000-errors.cjs");
|
|
3
3
|
//#region src/image/jpeg2000-tagtree.ts
|
|
4
4
|
const SENTINEL_VALUE = 2147483647;
|
|
5
|
+
const STUFFING_TRIGGER_BYTE = 255;
|
|
6
|
+
const MOST_SIGNIFICANT_BIT_MASK = 128;
|
|
7
|
+
const STUFFED_BYTE_BIT_COUNT = 7;
|
|
8
|
+
const BYTE_BIT_COUNT = 8;
|
|
5
9
|
var PacketBitReader = class {
|
|
6
10
|
data;
|
|
7
11
|
end;
|
|
@@ -28,12 +32,12 @@ var PacketBitReader = class {
|
|
|
28
32
|
}
|
|
29
33
|
readBit() {
|
|
30
34
|
if (this.available === 0) {
|
|
31
|
-
const stuffed = this.previousByte ===
|
|
35
|
+
const stuffed = this.previousByte === STUFFING_TRIGGER_BYTE;
|
|
32
36
|
const byte = this.nextByte();
|
|
33
|
-
if (stuffed && (byte &
|
|
37
|
+
if (stuffed && (byte & MOST_SIGNIFICANT_BIT_MASK) !== 0) throw new require_image_jpeg2000_errors.Jpeg2000ParseError("a packet header byte following 0xFF has its stuffed bit set, which ISO/IEC 15444-1 B.10.1 forbids");
|
|
34
38
|
this.buffer = byte;
|
|
35
39
|
this.previousByte = byte;
|
|
36
|
-
this.available = stuffed ?
|
|
40
|
+
this.available = stuffed ? STUFFED_BYTE_BIT_COUNT : BYTE_BIT_COUNT;
|
|
37
41
|
}
|
|
38
42
|
this.available--;
|
|
39
43
|
return this.buffer >> this.available & 1;
|
|
@@ -44,7 +48,7 @@ var PacketBitReader = class {
|
|
|
44
48
|
return value;
|
|
45
49
|
}
|
|
46
50
|
alignToByte() {
|
|
47
|
-
if (this.previousByte ===
|
|
51
|
+
if (this.previousByte === STUFFING_TRIGGER_BYTE) this.nextByte();
|
|
48
52
|
this.available = 0;
|
|
49
53
|
this.previousByte = 0;
|
|
50
54
|
}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { Jpeg2000ParseError } from "./jpeg2000-errors.js";
|
|
2
2
|
//#region src/image/jpeg2000-tagtree.ts
|
|
3
3
|
const SENTINEL_VALUE = 2147483647;
|
|
4
|
+
const STUFFING_TRIGGER_BYTE = 255;
|
|
5
|
+
const MOST_SIGNIFICANT_BIT_MASK = 128;
|
|
6
|
+
const STUFFED_BYTE_BIT_COUNT = 7;
|
|
7
|
+
const BYTE_BIT_COUNT = 8;
|
|
4
8
|
var PacketBitReader = class {
|
|
5
9
|
data;
|
|
6
10
|
end;
|
|
@@ -27,12 +31,12 @@ var PacketBitReader = class {
|
|
|
27
31
|
}
|
|
28
32
|
readBit() {
|
|
29
33
|
if (this.available === 0) {
|
|
30
|
-
const stuffed = this.previousByte ===
|
|
34
|
+
const stuffed = this.previousByte === STUFFING_TRIGGER_BYTE;
|
|
31
35
|
const byte = this.nextByte();
|
|
32
|
-
if (stuffed && (byte &
|
|
36
|
+
if (stuffed && (byte & MOST_SIGNIFICANT_BIT_MASK) !== 0) throw new Jpeg2000ParseError("a packet header byte following 0xFF has its stuffed bit set, which ISO/IEC 15444-1 B.10.1 forbids");
|
|
33
37
|
this.buffer = byte;
|
|
34
38
|
this.previousByte = byte;
|
|
35
|
-
this.available = stuffed ?
|
|
39
|
+
this.available = stuffed ? STUFFED_BYTE_BIT_COUNT : BYTE_BIT_COUNT;
|
|
36
40
|
}
|
|
37
41
|
this.available--;
|
|
38
42
|
return this.buffer >> this.available & 1;
|
|
@@ -43,7 +47,7 @@ var PacketBitReader = class {
|
|
|
43
47
|
return value;
|
|
44
48
|
}
|
|
45
49
|
alignToByte() {
|
|
46
|
-
if (this.previousByte ===
|
|
50
|
+
if (this.previousByte === STUFFING_TRIGGER_BYTE) this.nextByte();
|
|
47
51
|
this.available = 0;
|
|
48
52
|
this.previousByte = 0;
|
|
49
53
|
}
|
package/dist/image/jpeg2000.cjs
CHANGED
|
@@ -29,6 +29,8 @@ function tileDefaults(main, tile) {
|
|
|
29
29
|
if (main.cod === void 0) throw new require_image_jpeg2000_errors.Jpeg2000ParseError("no COD marker defines a coding style for this codestream");
|
|
30
30
|
return main.cod;
|
|
31
31
|
}
|
|
32
|
+
const CODE_BLOCK_STYLE_TERMINATE_ON_EACH_PASS_BIT = 4;
|
|
33
|
+
const MAX_SUPPORTED_COMPONENT_BIT_DEPTH = 31;
|
|
32
34
|
function undecodableReason(codestream) {
|
|
33
35
|
const main = codestream.main;
|
|
34
36
|
const cod = main.cod;
|
|
@@ -46,7 +48,7 @@ function undecodableReason(codestream) {
|
|
|
46
48
|
for (const header of headers) {
|
|
47
49
|
const style = resolveCoding(main, header === main ? void 0 : header, c);
|
|
48
50
|
if ((style.codeBlockStyle & 1) !== 0) return "the code-block style enables selective arithmetic coding bypass, which this decoder does not read";
|
|
49
|
-
if ((style.codeBlockStyle &
|
|
51
|
+
if ((style.codeBlockStyle & CODE_BLOCK_STYLE_TERMINATE_ON_EACH_PASS_BIT) !== 0) return "the code-block style terminates the arithmetic coder on every coding pass, which this decoder does not read";
|
|
50
52
|
}
|
|
51
53
|
}
|
|
52
54
|
for (const part of codestream.tileParts) {
|
|
@@ -60,7 +62,7 @@ function undecodableReason(codestream) {
|
|
|
60
62
|
const first = codestream.siz.components[0];
|
|
61
63
|
if (first !== void 0) {
|
|
62
64
|
for (const size of codestream.siz.components) if (size.bitDepth !== first.bitDepth || size.signed !== first.signed) return "the codestream mixes component bit depths or signedness, which this decoder does not combine into one image";
|
|
63
|
-
if (first.bitDepth >
|
|
65
|
+
if (first.bitDepth > MAX_SUPPORTED_COMPONENT_BIT_DEPTH) return `a component bit depth of ${String(first.bitDepth)} exceeds what this decoder's own 32-bit sample arithmetic can hold`;
|
|
64
66
|
}
|
|
65
67
|
}
|
|
66
68
|
function readJpeg2000Metadata(data) {
|
|
@@ -121,8 +123,9 @@ function concatTilePartData(codestream, tileIndex) {
|
|
|
121
123
|
function halveTowardZero(value) {
|
|
122
124
|
return value < 0 ? -(-value >> 1) : value >> 1;
|
|
123
125
|
}
|
|
126
|
+
const MANTISSA_FIXED_POINT_SCALE = 2048;
|
|
124
127
|
function quantizationStep(band, componentBitDepth) {
|
|
125
|
-
return 2 ** (componentBitDepth + require_image_jpeg2000_t2.subbandGainLog2(band.type) - band.stepSize.exponent) * (1 + band.stepSize.mantissa /
|
|
128
|
+
return 2 ** (componentBitDepth + require_image_jpeg2000_t2.subbandGainLog2(band.type) - band.stepSize.exponent) * (1 + band.stepSize.mantissa / MANTISSA_FIXED_POINT_SCALE);
|
|
126
129
|
}
|
|
127
130
|
function decodeSubbandBlocks(band, codeBlockStyle, data, place) {
|
|
128
131
|
for (const precinct of band.precincts) for (const block of precinct.codeBlocks) {
|
|
@@ -218,13 +221,14 @@ function decodeIrreversibleTileComponent(tile, componentIndex, componentBitDepth
|
|
|
218
221
|
}
|
|
219
222
|
return current;
|
|
220
223
|
}
|
|
224
|
+
const RCT_GREEN_RECOVERY_DIVISOR = 4;
|
|
221
225
|
function inverseReversibleComponentTransform(planes) {
|
|
222
226
|
const y = planes[0];
|
|
223
227
|
const u = planes[1];
|
|
224
228
|
const v = planes[2];
|
|
225
229
|
if (y === void 0 || u === void 0 || v === void 0) return;
|
|
226
230
|
for (let i = 0; i < y.length; i++) {
|
|
227
|
-
const green = (y[i] ?? 0) - Math.floor(((u[i] ?? 0) + (v[i] ?? 0)) /
|
|
231
|
+
const green = (y[i] ?? 0) - Math.floor(((u[i] ?? 0) + (v[i] ?? 0)) / RCT_GREEN_RECOVERY_DIVISOR);
|
|
228
232
|
const red = (v[i] ?? 0) + green;
|
|
229
233
|
const blue = (u[i] ?? 0) + green;
|
|
230
234
|
y[i] = red;
|
|
@@ -250,6 +254,7 @@ function inverseIrreversibleComponentTransform(planes) {
|
|
|
250
254
|
cr[i] = luma + ICT_BLUE_FROM_CB * blueDiff;
|
|
251
255
|
}
|
|
252
256
|
}
|
|
257
|
+
const MULTIPLE_COMPONENT_TRANSFORM_MIN_COMPONENTS = 3;
|
|
253
258
|
function decodeJpeg2000(data, options = {}) {
|
|
254
259
|
const onWarning = options.onWarning ?? (() => void 0);
|
|
255
260
|
const container = require_image_jp2_boxes.parseJp2Container(data);
|
|
@@ -285,11 +290,11 @@ function decodeJpeg2000(data, options = {}) {
|
|
|
285
290
|
const tilePlanes = [];
|
|
286
291
|
if (defaults.transform === "reversible-5-3") {
|
|
287
292
|
const reversible = Array.from({ length: componentCount }, (_, c) => decodeReversibleTileComponent(geometry, c, tileData));
|
|
288
|
-
if (defaults.multipleComponentTransform && componentCount >=
|
|
293
|
+
if (defaults.multipleComponentTransform && componentCount >= MULTIPLE_COMPONENT_TRANSFORM_MIN_COMPONENTS) inverseReversibleComponentTransform(reversible);
|
|
289
294
|
tilePlanes.push(...reversible);
|
|
290
295
|
} else {
|
|
291
296
|
const irreversible = Array.from({ length: componentCount }, (_, c) => decodeIrreversibleTileComponent(geometry, c, first.bitDepth, tileData));
|
|
292
|
-
if (defaults.multipleComponentTransform && componentCount >=
|
|
297
|
+
if (defaults.multipleComponentTransform && componentCount >= MULTIPLE_COMPONENT_TRANSFORM_MIN_COMPONENTS) inverseIrreversibleComponentTransform(irreversible);
|
|
293
298
|
tilePlanes.push(...irreversible);
|
|
294
299
|
}
|
|
295
300
|
for (let c = 0; c < componentCount; c++) {
|
package/dist/image/jpeg2000.js
CHANGED
|
@@ -28,6 +28,8 @@ function tileDefaults(main, tile) {
|
|
|
28
28
|
if (main.cod === void 0) throw new Jpeg2000ParseError("no COD marker defines a coding style for this codestream");
|
|
29
29
|
return main.cod;
|
|
30
30
|
}
|
|
31
|
+
const CODE_BLOCK_STYLE_TERMINATE_ON_EACH_PASS_BIT = 4;
|
|
32
|
+
const MAX_SUPPORTED_COMPONENT_BIT_DEPTH = 31;
|
|
31
33
|
function undecodableReason(codestream) {
|
|
32
34
|
const main = codestream.main;
|
|
33
35
|
const cod = main.cod;
|
|
@@ -45,7 +47,7 @@ function undecodableReason(codestream) {
|
|
|
45
47
|
for (const header of headers) {
|
|
46
48
|
const style = resolveCoding(main, header === main ? void 0 : header, c);
|
|
47
49
|
if ((style.codeBlockStyle & 1) !== 0) return "the code-block style enables selective arithmetic coding bypass, which this decoder does not read";
|
|
48
|
-
if ((style.codeBlockStyle &
|
|
50
|
+
if ((style.codeBlockStyle & CODE_BLOCK_STYLE_TERMINATE_ON_EACH_PASS_BIT) !== 0) return "the code-block style terminates the arithmetic coder on every coding pass, which this decoder does not read";
|
|
49
51
|
}
|
|
50
52
|
}
|
|
51
53
|
for (const part of codestream.tileParts) {
|
|
@@ -59,7 +61,7 @@ function undecodableReason(codestream) {
|
|
|
59
61
|
const first = codestream.siz.components[0];
|
|
60
62
|
if (first !== void 0) {
|
|
61
63
|
for (const size of codestream.siz.components) if (size.bitDepth !== first.bitDepth || size.signed !== first.signed) return "the codestream mixes component bit depths or signedness, which this decoder does not combine into one image";
|
|
62
|
-
if (first.bitDepth >
|
|
64
|
+
if (first.bitDepth > MAX_SUPPORTED_COMPONENT_BIT_DEPTH) return `a component bit depth of ${String(first.bitDepth)} exceeds what this decoder's own 32-bit sample arithmetic can hold`;
|
|
63
65
|
}
|
|
64
66
|
}
|
|
65
67
|
function readJpeg2000Metadata(data) {
|
|
@@ -120,8 +122,9 @@ function concatTilePartData(codestream, tileIndex) {
|
|
|
120
122
|
function halveTowardZero(value) {
|
|
121
123
|
return value < 0 ? -(-value >> 1) : value >> 1;
|
|
122
124
|
}
|
|
125
|
+
const MANTISSA_FIXED_POINT_SCALE = 2048;
|
|
123
126
|
function quantizationStep(band, componentBitDepth) {
|
|
124
|
-
return 2 ** (componentBitDepth + subbandGainLog2(band.type) - band.stepSize.exponent) * (1 + band.stepSize.mantissa /
|
|
127
|
+
return 2 ** (componentBitDepth + subbandGainLog2(band.type) - band.stepSize.exponent) * (1 + band.stepSize.mantissa / MANTISSA_FIXED_POINT_SCALE);
|
|
125
128
|
}
|
|
126
129
|
function decodeSubbandBlocks(band, codeBlockStyle, data, place) {
|
|
127
130
|
for (const precinct of band.precincts) for (const block of precinct.codeBlocks) {
|
|
@@ -217,13 +220,14 @@ function decodeIrreversibleTileComponent(tile, componentIndex, componentBitDepth
|
|
|
217
220
|
}
|
|
218
221
|
return current;
|
|
219
222
|
}
|
|
223
|
+
const RCT_GREEN_RECOVERY_DIVISOR = 4;
|
|
220
224
|
function inverseReversibleComponentTransform(planes) {
|
|
221
225
|
const y = planes[0];
|
|
222
226
|
const u = planes[1];
|
|
223
227
|
const v = planes[2];
|
|
224
228
|
if (y === void 0 || u === void 0 || v === void 0) return;
|
|
225
229
|
for (let i = 0; i < y.length; i++) {
|
|
226
|
-
const green = (y[i] ?? 0) - Math.floor(((u[i] ?? 0) + (v[i] ?? 0)) /
|
|
230
|
+
const green = (y[i] ?? 0) - Math.floor(((u[i] ?? 0) + (v[i] ?? 0)) / RCT_GREEN_RECOVERY_DIVISOR);
|
|
227
231
|
const red = (v[i] ?? 0) + green;
|
|
228
232
|
const blue = (u[i] ?? 0) + green;
|
|
229
233
|
y[i] = red;
|
|
@@ -249,6 +253,7 @@ function inverseIrreversibleComponentTransform(planes) {
|
|
|
249
253
|
cr[i] = luma + ICT_BLUE_FROM_CB * blueDiff;
|
|
250
254
|
}
|
|
251
255
|
}
|
|
256
|
+
const MULTIPLE_COMPONENT_TRANSFORM_MIN_COMPONENTS = 3;
|
|
252
257
|
function decodeJpeg2000(data, options = {}) {
|
|
253
258
|
const onWarning = options.onWarning ?? (() => void 0);
|
|
254
259
|
const container = parseJp2Container(data);
|
|
@@ -284,11 +289,11 @@ function decodeJpeg2000(data, options = {}) {
|
|
|
284
289
|
const tilePlanes = [];
|
|
285
290
|
if (defaults.transform === "reversible-5-3") {
|
|
286
291
|
const reversible = Array.from({ length: componentCount }, (_, c) => decodeReversibleTileComponent(geometry, c, tileData));
|
|
287
|
-
if (defaults.multipleComponentTransform && componentCount >=
|
|
292
|
+
if (defaults.multipleComponentTransform && componentCount >= MULTIPLE_COMPONENT_TRANSFORM_MIN_COMPONENTS) inverseReversibleComponentTransform(reversible);
|
|
288
293
|
tilePlanes.push(...reversible);
|
|
289
294
|
} else {
|
|
290
295
|
const irreversible = Array.from({ length: componentCount }, (_, c) => decodeIrreversibleTileComponent(geometry, c, first.bitDepth, tileData));
|
|
291
|
-
if (defaults.multipleComponentTransform && componentCount >=
|
|
296
|
+
if (defaults.multipleComponentTransform && componentCount >= MULTIPLE_COMPONENT_TRANSFORM_MIN_COMPONENTS) inverseIrreversibleComponentTransform(irreversible);
|
|
292
297
|
tilePlanes.push(...irreversible);
|
|
293
298
|
}
|
|
294
299
|
for (let c = 0; c < componentCount; c++) {
|
|
@@ -4,30 +4,39 @@ const require_bytes_flate = require("../bytes/flate.cjs");
|
|
|
4
4
|
const require_image_png_filter = require("./png-filter.cjs");
|
|
5
5
|
const require_bytes_crc32 = require("../bytes/crc32.cjs");
|
|
6
6
|
//#region src/image/png-decode.ts
|
|
7
|
+
const PNG_SIGNATURE_HIGH_BIT_MARKER = 137;
|
|
8
|
+
const PNG_SIGNATURE_P = 80;
|
|
9
|
+
const PNG_SIGNATURE_N = 78;
|
|
10
|
+
const PNG_SIGNATURE_G = 71;
|
|
11
|
+
const PNG_SIGNATURE_CR = 13;
|
|
12
|
+
const PNG_SIGNATURE_LF = 10;
|
|
7
13
|
const PNG_SIGNATURE = [
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
+
PNG_SIGNATURE_HIGH_BIT_MARKER,
|
|
15
|
+
PNG_SIGNATURE_P,
|
|
16
|
+
PNG_SIGNATURE_N,
|
|
17
|
+
PNG_SIGNATURE_G,
|
|
18
|
+
PNG_SIGNATURE_CR,
|
|
19
|
+
PNG_SIGNATURE_LF,
|
|
14
20
|
26,
|
|
15
|
-
|
|
21
|
+
PNG_SIGNATURE_LF
|
|
16
22
|
];
|
|
17
23
|
function requireDataView(bytes) {
|
|
18
24
|
return new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
19
25
|
}
|
|
26
|
+
const PNG_CHUNK_LENGTH_SIZE = 4;
|
|
27
|
+
const PNG_CHUNK_CRC_SIZE = 4;
|
|
28
|
+
const PNG_CHUNK_HEADER_SIZE = 8;
|
|
20
29
|
function readChunks(bytes, onWarning) {
|
|
21
30
|
const chunks = [];
|
|
22
31
|
const view = requireDataView(bytes);
|
|
23
32
|
let offset = PNG_SIGNATURE.length;
|
|
24
|
-
while (offset +
|
|
33
|
+
while (offset + PNG_CHUNK_HEADER_SIZE <= bytes.length) {
|
|
25
34
|
const length = view.getUint32(offset);
|
|
26
|
-
const typeBytes = bytes.subarray(offset +
|
|
35
|
+
const typeBytes = bytes.subarray(offset + PNG_CHUNK_LENGTH_SIZE, offset + PNG_CHUNK_HEADER_SIZE);
|
|
27
36
|
const type = new TextDecoder("latin1").decode(typeBytes);
|
|
28
|
-
const dataStart = offset +
|
|
37
|
+
const dataStart = offset + PNG_CHUNK_HEADER_SIZE;
|
|
29
38
|
const dataEnd = dataStart + length;
|
|
30
|
-
if (dataEnd +
|
|
39
|
+
if (dataEnd + PNG_CHUNK_CRC_SIZE > bytes.length) throw new Error(`PNG chunk '${type}' declares a length that runs past the end of the file`);
|
|
31
40
|
const data = bytes.subarray(dataStart, dataEnd);
|
|
32
41
|
if (onWarning !== void 0) {
|
|
33
42
|
if (view.getUint32(dataEnd) !== require_bytes_crc32.crc32(require_bytes_writer.concatBytes([typeBytes, data]))) onWarning(`PNG chunk '${type}' failed its CRC32 check`);
|
|
@@ -36,42 +45,53 @@ function readChunks(bytes, onWarning) {
|
|
|
36
45
|
type,
|
|
37
46
|
data
|
|
38
47
|
});
|
|
39
|
-
offset = dataEnd +
|
|
48
|
+
offset = dataEnd + PNG_CHUNK_CRC_SIZE;
|
|
40
49
|
if (type === "IEND") break;
|
|
41
50
|
}
|
|
42
51
|
return chunks;
|
|
43
52
|
}
|
|
53
|
+
const IHDR_HEIGHT_OFFSET = 4;
|
|
44
54
|
function parseIhdr(data) {
|
|
45
55
|
const view = requireDataView(data);
|
|
46
56
|
return {
|
|
47
57
|
width: view.getUint32(0),
|
|
48
|
-
height: view.getUint32(
|
|
58
|
+
height: view.getUint32(IHDR_HEIGHT_OFFSET),
|
|
49
59
|
bitDepth: data[8],
|
|
50
60
|
colorType: data[9],
|
|
51
61
|
interlace: data[12]
|
|
52
62
|
};
|
|
53
63
|
}
|
|
64
|
+
const PNG_COLOR_TYPE_GRAYSCALE = 0;
|
|
65
|
+
const PNG_COLOR_TYPE_TRUECOLOR = 2;
|
|
66
|
+
const PNG_COLOR_TYPE_INDEXED = 3;
|
|
67
|
+
const PNG_COLOR_TYPE_GRAYSCALE_ALPHA = 4;
|
|
68
|
+
const PNG_COLOR_TYPE_TRUECOLOR_ALPHA = 6;
|
|
69
|
+
const PNG_CHANNELS_TRUECOLOR = 3;
|
|
70
|
+
const PNG_CHANNELS_TRUECOLOR_ALPHA = 4;
|
|
54
71
|
function channelsForColorType(colorType) {
|
|
55
|
-
if (colorType ===
|
|
56
|
-
if (colorType ===
|
|
57
|
-
if (colorType ===
|
|
58
|
-
if (colorType ===
|
|
59
|
-
if (colorType ===
|
|
72
|
+
if (colorType === PNG_COLOR_TYPE_GRAYSCALE) return 1;
|
|
73
|
+
if (colorType === PNG_COLOR_TYPE_TRUECOLOR) return PNG_CHANNELS_TRUECOLOR;
|
|
74
|
+
if (colorType === PNG_COLOR_TYPE_INDEXED) return 1;
|
|
75
|
+
if (colorType === PNG_COLOR_TYPE_GRAYSCALE_ALPHA) return 2;
|
|
76
|
+
if (colorType === PNG_COLOR_TYPE_TRUECOLOR_ALPHA) return PNG_CHANNELS_TRUECOLOR_ALPHA;
|
|
60
77
|
throw new Error(`unsupported PNG colour type: ${colorType}`);
|
|
61
78
|
}
|
|
79
|
+
const BITS_PER_BYTE = 8;
|
|
62
80
|
function filterBpp(bitDepth, channels) {
|
|
63
|
-
return Math.max(1, Math.ceil(bitDepth * channels /
|
|
81
|
+
return Math.max(1, Math.ceil(bitDepth * channels / BITS_PER_BYTE));
|
|
64
82
|
}
|
|
83
|
+
const PNG_BIT_DEPTH_16 = 16;
|
|
84
|
+
const BYTE_INDEX_SHIFT = 3;
|
|
65
85
|
function unpackRow(rowBytes, width, channels, bitDepth) {
|
|
66
86
|
const sampleCount = width * channels;
|
|
67
87
|
const samples = Array.from({ length: sampleCount });
|
|
68
|
-
if (bitDepth ===
|
|
88
|
+
if (bitDepth === PNG_BIT_DEPTH_16) for (let i = 0; i < sampleCount; i++) samples[i] = rowBytes[i * 2];
|
|
69
89
|
else {
|
|
70
90
|
const mask = (1 << bitDepth) - 1;
|
|
71
91
|
for (let i = 0; i < sampleCount; i++) {
|
|
72
92
|
const bitOffset = i * bitDepth;
|
|
73
|
-
const byteIndex = bitOffset >>
|
|
74
|
-
const shift =
|
|
93
|
+
const byteIndex = bitOffset >> BYTE_INDEX_SHIFT;
|
|
94
|
+
const shift = BITS_PER_BYTE - bitDepth - (bitOffset & 7);
|
|
75
95
|
samples[i] = rowBytes[byteIndex] >> shift & mask;
|
|
76
96
|
}
|
|
77
97
|
}
|
|
@@ -80,18 +100,20 @@ function unpackRow(rowBytes, width, channels, bitDepth) {
|
|
|
80
100
|
function readTrnsGrayValue(trns) {
|
|
81
101
|
return requireDataView(trns).getUint16(0);
|
|
82
102
|
}
|
|
103
|
+
const TRNS_RGB_BLUE_OFFSET = 4;
|
|
83
104
|
function readTrnsRgbKey(trns) {
|
|
84
105
|
const view = requireDataView(trns);
|
|
85
106
|
return [
|
|
86
107
|
view.getUint16(0),
|
|
87
108
|
view.getUint16(2),
|
|
88
|
-
view.getUint16(
|
|
109
|
+
view.getUint16(TRNS_RGB_BLUE_OFFSET)
|
|
89
110
|
];
|
|
90
111
|
}
|
|
112
|
+
const MAX_BYTE_VALUE = 255;
|
|
91
113
|
function scaleToByte(sample, bitDepth) {
|
|
92
|
-
if (bitDepth ===
|
|
114
|
+
if (bitDepth === PNG_BIT_DEPTH_16) return sample;
|
|
93
115
|
const maxSample = (1 << bitDepth) - 1;
|
|
94
|
-
return Math.round(sample *
|
|
116
|
+
return Math.round(sample * MAX_BYTE_VALUE / maxSample);
|
|
95
117
|
}
|
|
96
118
|
function decodePng(bytes, options = {}) {
|
|
97
119
|
for (let i = 0; i < PNG_SIGNATURE.length; i++) if (bytes[i] !== PNG_SIGNATURE[i]) throw new Error("not a valid PNG file: bad signature");
|
|
@@ -102,23 +124,24 @@ function decodePng(bytes, options = {}) {
|
|
|
102
124
|
if (ihdr.interlace !== 0) throw new Error("Adam7-interlaced PNG images are not supported");
|
|
103
125
|
const channels = channelsForColorType(ihdr.colorType);
|
|
104
126
|
const bpp = filterBpp(ihdr.bitDepth, channels);
|
|
105
|
-
const bytesPerRow = Math.ceil(ihdr.width * channels * ihdr.bitDepth /
|
|
127
|
+
const bytesPerRow = Math.ceil(ihdr.width * channels * ihdr.bitDepth / BITS_PER_BYTE);
|
|
106
128
|
const idatChunks = chunks.filter((c) => c.type === "IDAT").map((c) => c.data);
|
|
107
129
|
if (idatChunks.length === 0) throw new Error("PNG file has no IDAT chunks");
|
|
108
130
|
const compressed = require_bytes_writer.concatBytes(idatChunks);
|
|
109
131
|
const { bytes: inflated, recovered } = require_bytes_flate.inflateTolerant(compressed);
|
|
110
132
|
if (recovered && options.onWarning !== void 0) options.onWarning("PNG IDAT stream required tolerant recovery (truncated or malformed)");
|
|
111
133
|
const unfiltered = require_image_png_filter.unfilterScanlines(inflated, ihdr.height, bytesPerRow, bpp);
|
|
112
|
-
const palette = ihdr.colorType ===
|
|
113
|
-
if (ihdr.colorType ===
|
|
134
|
+
const palette = ihdr.colorType === PNG_COLOR_TYPE_INDEXED ? chunks.find((c) => c.type === "PLTE")?.data : void 0;
|
|
135
|
+
if (ihdr.colorType === PNG_COLOR_TYPE_INDEXED && palette === void 0) throw new Error("indexed-colour PNG has no PLTE chunk");
|
|
114
136
|
const trns = chunks.find((c) => c.type === "tRNS")?.data;
|
|
115
137
|
return buildRawImage(ihdr, channels, bytesPerRow, unfiltered, palette, trns);
|
|
116
138
|
}
|
|
139
|
+
const ALPHA_SAMPLE_INDEX_IN_RGBA = 3;
|
|
117
140
|
function buildRawImage(ihdr, channels, bytesPerRow, unfiltered, palette, trns) {
|
|
118
141
|
const { width, height, bitDepth, colorType } = ihdr;
|
|
119
|
-
const outChannels = colorType === 0 || colorType ===
|
|
142
|
+
const outChannels = colorType === 0 || colorType === PNG_COLOR_TYPE_GRAYSCALE_ALPHA ? 1 : PNG_CHANNELS_TRUECOLOR;
|
|
120
143
|
const data = new Uint8Array(width * height * outChannels);
|
|
121
|
-
const alpha = colorType ===
|
|
144
|
+
const alpha = colorType === PNG_COLOR_TYPE_GRAYSCALE_ALPHA || colorType === PNG_COLOR_TYPE_TRUECOLOR_ALPHA || trns !== void 0 ? new Uint8Array(width * height).fill(MAX_BYTE_VALUE) : void 0;
|
|
122
145
|
const trnsGray = colorType === 0 && trns !== void 0 ? readTrnsGrayValue(trns) : void 0;
|
|
123
146
|
const trnsRgb = colorType === 2 && trns !== void 0 ? readTrnsRgbKey(trns) : void 0;
|
|
124
147
|
for (let y = 0; y < height; y++) {
|
|
@@ -131,7 +154,7 @@ function buildRawImage(ihdr, channels, bytesPerRow, unfiltered, palette, trns) {
|
|
|
131
154
|
if (colorType === 0) {
|
|
132
155
|
const g = samples[pixelBase];
|
|
133
156
|
data[outBase] = scaleToByte(g, bitDepth);
|
|
134
|
-
if (alpha !== void 0 && trnsGray !== void 0) alpha[alphaIndex] = g === trnsGray ? 0 :
|
|
157
|
+
if (alpha !== void 0 && trnsGray !== void 0) alpha[alphaIndex] = g === trnsGray ? 0 : MAX_BYTE_VALUE;
|
|
135
158
|
} else if (colorType === 2) {
|
|
136
159
|
const r = samples[pixelBase];
|
|
137
160
|
const g = samples[pixelBase + 1];
|
|
@@ -141,15 +164,15 @@ function buildRawImage(ihdr, channels, bytesPerRow, unfiltered, palette, trns) {
|
|
|
141
164
|
data[outBase + 2] = b;
|
|
142
165
|
if (alpha !== void 0 && trnsRgb !== void 0) {
|
|
143
166
|
const [kr, kg, kb] = trnsRgb;
|
|
144
|
-
alpha[alphaIndex] = r === kr && g === kg && b === kb ? 0 :
|
|
167
|
+
alpha[alphaIndex] = r === kr && g === kg && b === kb ? 0 : MAX_BYTE_VALUE;
|
|
145
168
|
}
|
|
146
|
-
} else if (colorType ===
|
|
169
|
+
} else if (colorType === PNG_COLOR_TYPE_INDEXED) {
|
|
147
170
|
const index = samples[pixelBase];
|
|
148
|
-
data[outBase] = palette[index *
|
|
149
|
-
data[outBase + 1] = palette[index *
|
|
150
|
-
data[outBase + 2] = palette[index *
|
|
151
|
-
if (alpha !== void 0 && trns !== void 0) alpha[alphaIndex] = index < trns.length ? trns[index] :
|
|
152
|
-
} else if (colorType ===
|
|
171
|
+
data[outBase] = palette[index * PNG_CHANNELS_TRUECOLOR];
|
|
172
|
+
data[outBase + 1] = palette[index * PNG_CHANNELS_TRUECOLOR + 1];
|
|
173
|
+
data[outBase + 2] = palette[index * PNG_CHANNELS_TRUECOLOR + 2];
|
|
174
|
+
if (alpha !== void 0 && trns !== void 0) alpha[alphaIndex] = index < trns.length ? trns[index] : MAX_BYTE_VALUE;
|
|
175
|
+
} else if (colorType === PNG_COLOR_TYPE_GRAYSCALE_ALPHA) {
|
|
153
176
|
const g = samples[pixelBase];
|
|
154
177
|
const a = samples[pixelBase + 1];
|
|
155
178
|
data[outBase] = scaleToByte(g, bitDepth);
|
|
@@ -158,7 +181,7 @@ function buildRawImage(ihdr, channels, bytesPerRow, unfiltered, palette, trns) {
|
|
|
158
181
|
data[outBase] = samples[pixelBase];
|
|
159
182
|
data[outBase + 1] = samples[pixelBase + 1];
|
|
160
183
|
data[outBase + 2] = samples[pixelBase + 2];
|
|
161
|
-
if (alpha !== void 0) alpha[alphaIndex] = samples[pixelBase +
|
|
184
|
+
if (alpha !== void 0) alpha[alphaIndex] = samples[pixelBase + ALPHA_SAMPLE_INDEX_IN_RGBA];
|
|
162
185
|
}
|
|
163
186
|
}
|
|
164
187
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
//#region src/image/png-decode.d.ts
|
|
2
|
+
type ImageChannels = 1 | 3;
|
|
2
3
|
interface RawImage {
|
|
3
4
|
readonly width: number;
|
|
4
5
|
readonly height: number;
|
|
5
|
-
readonly channels:
|
|
6
|
+
readonly channels: ImageChannels;
|
|
6
7
|
readonly data: Uint8Array<ArrayBuffer>;
|
|
7
8
|
readonly alpha?: Uint8Array<ArrayBuffer>;
|
|
8
9
|
}
|
|
@@ -11,4 +12,4 @@ interface PngDecodeOptions {
|
|
|
11
12
|
}
|
|
12
13
|
declare function decodePng(bytes: Uint8Array<ArrayBuffer>, options?: PngDecodeOptions): RawImage;
|
|
13
14
|
//#endregion
|
|
14
|
-
export { PngDecodeOptions, RawImage, decodePng };
|
|
15
|
+
export { ImageChannels, PngDecodeOptions, RawImage, decodePng };
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
//#region src/image/png-decode.d.ts
|
|
2
|
+
type ImageChannels = 1 | 3;
|
|
2
3
|
interface RawImage {
|
|
3
4
|
readonly width: number;
|
|
4
5
|
readonly height: number;
|
|
5
|
-
readonly channels:
|
|
6
|
+
readonly channels: ImageChannels;
|
|
6
7
|
readonly data: Uint8Array<ArrayBuffer>;
|
|
7
8
|
readonly alpha?: Uint8Array<ArrayBuffer>;
|
|
8
9
|
}
|
|
@@ -11,4 +12,4 @@ interface PngDecodeOptions {
|
|
|
11
12
|
}
|
|
12
13
|
declare function decodePng(bytes: Uint8Array<ArrayBuffer>, options?: PngDecodeOptions): RawImage;
|
|
13
14
|
//#endregion
|
|
14
|
-
export { PngDecodeOptions, RawImage, decodePng };
|
|
15
|
+
export { ImageChannels, PngDecodeOptions, RawImage, decodePng };
|