pdf-parser.js 5.2.26 → 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.d.cts +2 -2
- package/dist/annotations.d.ts +2 -2
- package/dist/annotations.js +5 -3
- package/dist/attachments.d.cts +2 -2
- package/dist/attachments.d.ts +2 -2
- 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 +73 -45
- package/dist/cff-bounds.js +73 -45
- 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-read.d.cts +1 -1
- package/dist/content-read.d.ts +1 -1
- package/dist/content-write.cjs +21 -14
- package/dist/content-write.d.cts +2 -2
- package/dist/content-write.d.ts +2 -2
- package/dist/content-write.js +21 -14
- 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/document.cjs +17 -11
- package/dist/document.d.cts +1 -1
- package/dist/document.d.ts +1 -1
- package/dist/document.js +17 -11
- package/dist/{embedded-font-Bnhh4juV.d.ts → embedded-font-ByD7ZiQS.d.ts} +1 -1
- package/dist/{embedded-font-CEf-zBCA.d.cts → embedded-font-DgVBedw6.d.cts} +1 -1
- package/dist/embedded-font-write.d.cts +2 -2
- package/dist/embedded-font-write.d.ts +2 -2
- package/dist/embedded-font.cjs +4 -2
- package/dist/embedded-font.d.cts +1 -1
- package/dist/embedded-font.d.ts +1 -1
- 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.d.cts +1 -1
- package/dist/encrypt-write.d.ts +1 -1
- package/dist/encrypt-write.js +25 -21
- package/dist/encrypt.cjs +43 -64
- package/dist/encrypt.d.cts +1 -1
- package/dist/encrypt.d.ts +1 -1
- package/dist/encrypt.js +43 -64
- package/dist/filters.cjs +46 -26
- package/dist/filters.d.cts +1 -1
- package/dist/filters.d.ts +1 -1
- package/dist/filters.js +46 -26
- 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.d.cts +1 -1
- package/dist/font-read.d.ts +1 -1
- package/dist/font-read.js +12 -6
- package/dist/font-registry.d.cts +3 -3
- package/dist/font-registry.d.ts +3 -3
- package/dist/font-tables.cjs +55 -28
- package/dist/font-tables.js +55 -28
- package/dist/form.cjs +13 -8
- package/dist/form.d.cts +2 -2
- package/dist/form.d.ts +2 -2
- package/dist/form.js +13 -8
- package/dist/gdef-table.cjs +6 -3
- package/dist/gdef-table.js +6 -3
- package/dist/{glyf-contours-C0epBNqP.d.ts → glyf-contours-B1PsI9oA.d.ts} +1 -1
- package/dist/{glyf-contours-BRpvd0rt.d.cts → glyf-contours-NHBpgks-.d.cts} +1 -1
- package/dist/glyf-contours.cjs +3 -1
- package/dist/glyf-contours.d.cts +1 -1
- package/dist/glyf-contours.d.ts +1 -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 +40 -25
- package/dist/gsub-table.js +40 -25
- 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 +61 -32
- package/dist/image/jpeg2000-codestream.js +61 -32
- 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.d.cts +2 -2
- package/dist/images-read.d.ts +2 -2
- package/dist/images-read.js +41 -36
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/interpret.cjs +68 -40
- package/dist/interpret.d.cts +1 -1
- package/dist/interpret.d.ts +1 -1
- package/dist/interpret.js +68 -40
- 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.d.cts +1 -1
- package/dist/math-font-write.d.ts +1 -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/names.cjs +7 -7
- package/dist/names.d.cts +2 -2
- package/dist/names.d.ts +2 -2
- package/dist/names.js +7 -7
- package/dist/navigation.cjs +16 -12
- package/dist/navigation.d.cts +4 -4
- package/dist/navigation.d.ts +4 -4
- package/dist/navigation.js +16 -12
- package/dist/{objects-B7HdMeWS.d.cts → objects-e2RS3-yT.d.cts} +3 -3
- package/dist/{objects-B7HdMeWS.d.ts → objects-e2RS3-yT.d.ts} +3 -3
- package/dist/objects.d.cts +1 -1
- package/dist/objects.d.ts +1 -1
- package/dist/optional-content.d.cts +2 -2
- package/dist/optional-content.d.ts +2 -2
- package/dist/ot-layout-common.cjs +22 -15
- package/dist/ot-layout-common.js +22 -15
- package/dist/parse.cjs +7 -5
- package/dist/parse.d.cts +1 -1
- package/dist/parse.d.ts +1 -1
- 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.d.cts +1 -1
- package/dist/predictors.d.ts +1 -1
- package/dist/predictors.js +14 -9
- package/dist/raster.cjs +30 -19
- package/dist/raster.d.cts +8 -8
- package/dist/raster.d.ts +8 -8
- package/dist/raster.js +30 -19
- package/dist/read.cjs +29 -16
- package/dist/read.js +29 -16
- package/dist/serialize.cjs +6 -2
- package/dist/serialize.d.cts +1 -1
- package/dist/serialize.d.ts +1 -1
- package/dist/serialize.js +6 -2
- package/dist/sfnt-subset.cjs +25 -13
- package/dist/sfnt-subset.d.cts +1 -1
- package/dist/sfnt-subset.d.ts +1 -1
- package/dist/sfnt-subset.js +25 -13
- package/dist/sfnt.cjs +20 -10
- package/dist/sfnt.js +20 -10
- package/dist/structure.d.cts +2 -2
- package/dist/structure.d.ts +2 -2
- package/dist/text-group.cjs +0 -1
- package/dist/text-group.js +0 -1
- package/dist/text-layout.d.cts +1 -1
- package/dist/text-layout.d.ts +1 -1
- package/dist/tounicode.cjs +4 -2
- package/dist/tounicode.d.cts +1 -1
- package/dist/tounicode.d.ts +1 -1
- 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.d.cts +1 -1
- package/dist/write.d.ts +1 -1
- package/dist/write.js +20 -12
- package/dist/xref.cjs +5 -2
- package/dist/xref.d.cts +1 -1
- package/dist/xref.d.ts +1 -1
- package/dist/xref.js +5 -2
- package/package.json +1 -1
|
@@ -14,7 +14,9 @@ const STYLE_TERMINATE_ALL = 4;
|
|
|
14
14
|
const STYLE_VERTICALLY_CAUSAL = 8;
|
|
15
15
|
const STYLE_SEGMENTATION_SYMBOLS = 32;
|
|
16
16
|
const SEGMENTATION_SYMBOL = 10;
|
|
17
|
+
const SEGMENTATION_SYMBOL_MSB_SHIFT = 3;
|
|
17
18
|
const STRIPE_HEIGHT = 4;
|
|
19
|
+
const HEX_RADIX = 16;
|
|
18
20
|
const PASS_SIGNIFICANCE = 0;
|
|
19
21
|
const PASS_REFINEMENT = 1;
|
|
20
22
|
const PASS_CLEANUP = 2;
|
|
@@ -22,25 +24,33 @@ function throwForUnsupportedStyle(style) {
|
|
|
22
24
|
if ((style & STYLE_SELECTIVE_BYPASS) !== 0) throw new Jpeg2000UnsupportedError("the code-block style enables selective arithmetic coding bypass (lazy mode), which splits a code-block into raw and arithmetically coded segments this decoder does not read");
|
|
23
25
|
if ((style & STYLE_TERMINATE_ALL) !== 0) throw new Jpeg2000UnsupportedError("the code-block style terminates the arithmetic coder on every coding pass, which splits a code-block into one segment per pass this decoder does not read");
|
|
24
26
|
}
|
|
27
|
+
const ZC_CONTEXT_3 = 3;
|
|
28
|
+
const ZC_CONTEXT_4 = 4;
|
|
29
|
+
const ZC_CONTEXT_5 = 5;
|
|
30
|
+
const ZC_CONTEXT_6 = 6;
|
|
31
|
+
const ZC_CONTEXT_7 = 7;
|
|
32
|
+
const ZC_CONTEXT_8 = 8;
|
|
33
|
+
const HH_DIAGONAL_NEIGHBOURS_HIGH = 3;
|
|
25
34
|
function zeroCodingContext(subband, horizontal, vertical, diagonal) {
|
|
26
35
|
if (subband === "HH") {
|
|
27
36
|
const straight = horizontal + vertical;
|
|
28
|
-
if (diagonal >=
|
|
29
|
-
if (diagonal === 2) return straight >= 1 ?
|
|
30
|
-
if (diagonal === 1) return straight >= 2 ?
|
|
37
|
+
if (diagonal >= HH_DIAGONAL_NEIGHBOURS_HIGH) return ZC_CONTEXT_8;
|
|
38
|
+
if (diagonal === 2) return straight >= 1 ? ZC_CONTEXT_7 : ZC_CONTEXT_6;
|
|
39
|
+
if (diagonal === 1) return straight >= 2 ? ZC_CONTEXT_5 : straight === 1 ? ZC_CONTEXT_4 : ZC_CONTEXT_3;
|
|
31
40
|
return straight >= 2 ? 2 : straight === 1 ? 1 : 0;
|
|
32
41
|
}
|
|
33
42
|
const primary = subband === "HL" ? vertical : horizontal;
|
|
34
43
|
const secondary = subband === "HL" ? horizontal : vertical;
|
|
35
|
-
if (primary === 2) return
|
|
44
|
+
if (primary === 2) return ZC_CONTEXT_8;
|
|
36
45
|
if (primary === 1) {
|
|
37
|
-
if (secondary >= 1) return
|
|
38
|
-
return diagonal >= 1 ?
|
|
46
|
+
if (secondary >= 1) return ZC_CONTEXT_7;
|
|
47
|
+
return diagonal >= 1 ? ZC_CONTEXT_6 : ZC_CONTEXT_5;
|
|
39
48
|
}
|
|
40
|
-
if (secondary === 2) return
|
|
41
|
-
if (secondary === 1) return
|
|
49
|
+
if (secondary === 2) return ZC_CONTEXT_4;
|
|
50
|
+
if (secondary === 1) return ZC_CONTEXT_3;
|
|
42
51
|
return diagonal >= 2 ? 2 : diagonal === 1 ? 1 : 0;
|
|
43
52
|
}
|
|
53
|
+
const SIGN_CONTEXT_TABLE_ROW_STRIDE = 3;
|
|
44
54
|
const SIGN_XOR_FLAG = 8;
|
|
45
55
|
const SIGN_CONTEXT_TABLE = [
|
|
46
56
|
12,
|
|
@@ -101,7 +111,7 @@ function decodeJpeg2000CodeBlock(options) {
|
|
|
101
111
|
const below = belowVisible(y, stripeEnd);
|
|
102
112
|
const horizontal = clampToUnit(contribution(n - 1) + contribution(n + 1));
|
|
103
113
|
const vertical = clampToUnit(contribution(n - stride) + (below ? contribution(n + stride) : 0));
|
|
104
|
-
const packed = SIGN_CONTEXT_TABLE[(horizontal + 1) *
|
|
114
|
+
const packed = SIGN_CONTEXT_TABLE[(horizontal + 1) * SIGN_CONTEXT_TABLE_ROW_STRIDE + (vertical + 1)] ?? 0;
|
|
105
115
|
const decision = mq.decode(contexts, SIGN_CONTEXT_BASE + (packed & -9));
|
|
106
116
|
negative[n] = decision ^ ((packed & SIGN_XOR_FLAG) !== 0 ? 1 : 0);
|
|
107
117
|
};
|
|
@@ -159,8 +169,8 @@ function decodeJpeg2000CodeBlock(options) {
|
|
|
159
169
|
}
|
|
160
170
|
}
|
|
161
171
|
if (segmentationSymbols) {
|
|
162
|
-
const symbol = mq.decode(contexts, UNIFORM_CONTEXT) <<
|
|
163
|
-
if (symbol !== SEGMENTATION_SYMBOL) throw new Jpeg2000ParseError(`a cleanup pass ended with segmentation symbol 0x${symbol.toString(
|
|
172
|
+
const symbol = mq.decode(contexts, UNIFORM_CONTEXT) << SEGMENTATION_SYMBOL_MSB_SHIFT | mq.decode(contexts, UNIFORM_CONTEXT) << 2 | mq.decode(contexts, UNIFORM_CONTEXT) << 1 | mq.decode(contexts, UNIFORM_CONTEXT);
|
|
173
|
+
if (symbol !== SEGMENTATION_SYMBOL) throw new Jpeg2000ParseError(`a cleanup pass ended with segmentation symbol 0x${symbol.toString(HEX_RADIX)} rather than the 0xA ISO/IEC 15444-1 D.3.4 requires, so this code-block's coded data is corrupt`);
|
|
164
174
|
}
|
|
165
175
|
codedThisPlane.fill(0);
|
|
166
176
|
};
|
|
@@ -63,8 +63,9 @@ function bandCoordinate(componentCoordinate, levels, orientation) {
|
|
|
63
63
|
const half = 2 ** (levels - 1);
|
|
64
64
|
return Math.ceil((componentCoordinate - half * orientation) / (2 * half));
|
|
65
65
|
}
|
|
66
|
+
const SUBBANDS_PER_RESOLUTION_LEVEL = 3;
|
|
66
67
|
function quantizationIndex(resolution, bandIndex) {
|
|
67
|
-
return resolution === 0 ? 0 :
|
|
68
|
+
return resolution === 0 ? 0 : SUBBANDS_PER_RESOLUTION_LEVEL * (resolution - 1) + bandIndex + 1;
|
|
68
69
|
}
|
|
69
70
|
function stepSizeFor(quantization, resolution, bandIndex) {
|
|
70
71
|
if (quantization.style === "derived") {
|
|
@@ -203,14 +204,20 @@ function buildTileGeometry(siz, tileX, tileY, codingPerComponent, quantizationPe
|
|
|
203
204
|
function subbandGainLog2(type) {
|
|
204
205
|
return SUBBAND_GAIN_LOG2[type];
|
|
205
206
|
}
|
|
207
|
+
const CODING_PASSES_RANGE_3_5_BASE = 3;
|
|
208
|
+
const CODING_PASSES_5_BIT_FIELD_WIDTH = 5;
|
|
209
|
+
const CODING_PASSES_5_BIT_FIELD_ESCAPE = 31;
|
|
210
|
+
const CODING_PASSES_RANGE_6_36_BASE = 6;
|
|
211
|
+
const CODING_PASSES_RANGE_37_164_BASE = 37;
|
|
212
|
+
const CODING_PASSES_7_BIT_FIELD_WIDTH = 7;
|
|
206
213
|
function readCodingPasses(reader) {
|
|
207
214
|
if (reader.readBit() === 0) return 1;
|
|
208
215
|
if (reader.readBit() === 0) return 2;
|
|
209
216
|
const twoBit = reader.readBits(2);
|
|
210
|
-
if (twoBit <
|
|
211
|
-
const fiveBit = reader.readBits(
|
|
212
|
-
if (fiveBit <
|
|
213
|
-
return
|
|
217
|
+
if (twoBit < CODING_PASSES_RANGE_3_5_BASE) return CODING_PASSES_RANGE_3_5_BASE + twoBit;
|
|
218
|
+
const fiveBit = reader.readBits(CODING_PASSES_5_BIT_FIELD_WIDTH);
|
|
219
|
+
if (fiveBit < CODING_PASSES_5_BIT_FIELD_ESCAPE) return CODING_PASSES_RANGE_6_36_BASE + fiveBit;
|
|
220
|
+
return CODING_PASSES_RANGE_37_164_BASE + reader.readBits(CODING_PASSES_7_BIT_FIELD_WIDTH);
|
|
214
221
|
}
|
|
215
222
|
function buildPacketSequence(tile, order, layers) {
|
|
216
223
|
const maxResolutions = Math.max(...tile.components.map((component) => component.resolutions.length));
|
|
@@ -62,8 +62,9 @@ function bandCoordinate(componentCoordinate, levels, orientation) {
|
|
|
62
62
|
const half = 2 ** (levels - 1);
|
|
63
63
|
return Math.ceil((componentCoordinate - half * orientation) / (2 * half));
|
|
64
64
|
}
|
|
65
|
+
const SUBBANDS_PER_RESOLUTION_LEVEL = 3;
|
|
65
66
|
function quantizationIndex(resolution, bandIndex) {
|
|
66
|
-
return resolution === 0 ? 0 :
|
|
67
|
+
return resolution === 0 ? 0 : SUBBANDS_PER_RESOLUTION_LEVEL * (resolution - 1) + bandIndex + 1;
|
|
67
68
|
}
|
|
68
69
|
function stepSizeFor(quantization, resolution, bandIndex) {
|
|
69
70
|
if (quantization.style === "derived") {
|
|
@@ -202,14 +203,20 @@ function buildTileGeometry(siz, tileX, tileY, codingPerComponent, quantizationPe
|
|
|
202
203
|
function subbandGainLog2(type) {
|
|
203
204
|
return SUBBAND_GAIN_LOG2[type];
|
|
204
205
|
}
|
|
206
|
+
const CODING_PASSES_RANGE_3_5_BASE = 3;
|
|
207
|
+
const CODING_PASSES_5_BIT_FIELD_WIDTH = 5;
|
|
208
|
+
const CODING_PASSES_5_BIT_FIELD_ESCAPE = 31;
|
|
209
|
+
const CODING_PASSES_RANGE_6_36_BASE = 6;
|
|
210
|
+
const CODING_PASSES_RANGE_37_164_BASE = 37;
|
|
211
|
+
const CODING_PASSES_7_BIT_FIELD_WIDTH = 7;
|
|
205
212
|
function readCodingPasses(reader) {
|
|
206
213
|
if (reader.readBit() === 0) return 1;
|
|
207
214
|
if (reader.readBit() === 0) return 2;
|
|
208
215
|
const twoBit = reader.readBits(2);
|
|
209
|
-
if (twoBit <
|
|
210
|
-
const fiveBit = reader.readBits(
|
|
211
|
-
if (fiveBit <
|
|
212
|
-
return
|
|
216
|
+
if (twoBit < CODING_PASSES_RANGE_3_5_BASE) return CODING_PASSES_RANGE_3_5_BASE + twoBit;
|
|
217
|
+
const fiveBit = reader.readBits(CODING_PASSES_5_BIT_FIELD_WIDTH);
|
|
218
|
+
if (fiveBit < CODING_PASSES_5_BIT_FIELD_ESCAPE) return CODING_PASSES_RANGE_6_36_BASE + fiveBit;
|
|
219
|
+
return CODING_PASSES_RANGE_37_164_BASE + reader.readBits(CODING_PASSES_7_BIT_FIELD_WIDTH);
|
|
213
220
|
}
|
|
214
221
|
function buildPacketSequence(tile, order, layers) {
|
|
215
222
|
const maxResolutions = Math.max(...tile.components.map((component) => component.resolutions.length));
|
|
@@ -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 };
|