pdf-codec 1.3.0 → 1.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/README.md +38 -0
- package/dist/afm-widths-BoeTOK2r.cjs +826 -0
- package/dist/afm-widths-Dxucrg7D.js +779 -0
- package/dist/afm-widths-DyDq56Ph.d.cts +19 -0
- package/dist/afm-widths-DyDq56Ph.d.ts +19 -0
- package/dist/afm-widths.cjs +4 -0
- package/dist/afm-widths.d.cts +2 -0
- package/dist/afm-widths.d.ts +2 -0
- package/dist/afm-widths.js +2 -0
- package/dist/assets/stix-two-math-font.cjs +5 -0
- package/dist/assets/stix-two-math-font.d.cts +4 -0
- package/dist/assets/stix-two-math-font.d.ts +4 -0
- package/dist/assets/stix-two-math-font.js +4 -0
- package/dist/bytes/crc32.cjs +21 -0
- package/dist/bytes/crc32.d.cts +4 -0
- package/dist/bytes/crc32.d.ts +4 -0
- package/dist/bytes/crc32.js +20 -0
- package/dist/bytes/flate.cjs +53 -0
- package/dist/bytes/flate.d.cts +12 -0
- package/dist/bytes/flate.d.ts +12 -0
- package/dist/bytes/flate.js +49 -0
- package/dist/bytes/reader.cjs +60 -0
- package/dist/bytes/reader.d.cts +20 -0
- package/dist/bytes/reader.d.ts +20 -0
- package/dist/bytes/reader.js +58 -0
- package/dist/bytes/writer.cjs +37 -0
- package/dist/bytes/writer.d.cts +13 -0
- package/dist/bytes/writer.d.ts +13 -0
- package/dist/bytes/writer.js +35 -0
- package/dist/cmap.cjs +110 -0
- package/dist/cmap.d.cts +8 -0
- package/dist/cmap.d.ts +8 -0
- package/dist/cmap.js +109 -0
- package/dist/codec.cjs +34 -0
- package/dist/codec.d.cts +167 -0
- package/dist/codec.d.ts +167 -0
- package/dist/codec.js +32 -0
- package/dist/content-read.cjs +126 -0
- package/dist/content-read.d.cts +21 -0
- package/dist/content-read.d.ts +21 -0
- package/dist/content-read.js +125 -0
- package/dist/content-write.cjs +138 -0
- package/dist/content-write.d.cts +24 -0
- package/dist/content-write.d.ts +24 -0
- package/dist/content-write.js +137 -0
- package/dist/diagnostics.cjs +21 -0
- package/dist/diagnostics.d.cts +19 -0
- package/dist/diagnostics.d.ts +19 -0
- package/dist/diagnostics.js +18 -0
- package/dist/document.cjs +162 -0
- package/dist/document.d.cts +12 -0
- package/dist/document.d.ts +12 -0
- package/dist/document.js +161 -0
- package/dist/encoding.cjs +5 -0
- package/dist/encoding.d.cts +6 -0
- package/dist/encoding.d.ts +6 -0
- package/dist/encoding.js +2 -0
- package/dist/filters.cjs +223 -0
- package/dist/filters.d.cts +14 -0
- package/dist/filters.d.ts +14 -0
- package/dist/filters.js +218 -0
- package/dist/font-read.cjs +199 -0
- package/dist/font-read.d.cts +23 -0
- package/dist/font-read.d.ts +23 -0
- package/dist/font-read.js +198 -0
- package/dist/font-style.cjs +35 -0
- package/dist/font-style.d.cts +14 -0
- package/dist/font-style.d.ts +14 -0
- package/dist/font-style.js +34 -0
- package/dist/fonts.cjs +124 -0
- package/dist/fonts.d.cts +15 -0
- package/dist/fonts.d.ts +15 -0
- package/dist/fonts.js +122 -0
- package/dist/formula.cjs +0 -0
- package/dist/formula.d.cts +10 -0
- package/dist/formula.d.ts +10 -0
- package/dist/formula.js +0 -0
- package/dist/image/jpeg-info.cjs +71 -0
- package/dist/image/jpeg-info.d.cts +12 -0
- package/dist/image/jpeg-info.d.ts +12 -0
- package/dist/image/jpeg-info.js +70 -0
- package/dist/image/png-decode.cjs +181 -0
- package/dist/image/png-decode.d.cts +14 -0
- package/dist/image/png-decode.d.ts +14 -0
- package/dist/image/png-decode.js +180 -0
- package/dist/image/png-encode.cjs +64 -0
- package/dist/image/png-encode.d.cts +8 -0
- package/dist/image/png-encode.d.ts +8 -0
- package/dist/image/png-encode.js +63 -0
- package/dist/image/png-filter.cjs +95 -0
- package/dist/image/png-filter.d.cts +6 -0
- package/dist/image/png-filter.d.ts +6 -0
- package/dist/image/png-filter.js +93 -0
- package/dist/images-read.cjs +250 -0
- package/dist/images-read.d.cts +13 -0
- package/dist/images-read.d.ts +13 -0
- package/dist/images-read.js +249 -0
- package/dist/index.cjs +45 -5912
- package/dist/index.d.cts +21 -483
- package/dist/index.d.ts +21 -483
- package/dist/index.js +18 -5885
- package/dist/interpret.cjs +587 -0
- package/dist/interpret.d.cts +84 -0
- package/dist/interpret.d.ts +84 -0
- package/dist/interpret.js +586 -0
- package/dist/lexer.cjs +180 -0
- package/dist/lexer.d.cts +29 -0
- package/dist/lexer.d.ts +29 -0
- package/dist/lexer.js +179 -0
- package/dist/math-cmap.cjs +81 -0
- package/dist/math-cmap.d.cts +6 -0
- package/dist/math-cmap.d.ts +6 -0
- package/dist/math-cmap.js +80 -0
- package/dist/math-content-write.cjs +83 -0
- package/dist/math-content-write.d.cts +11 -0
- package/dist/math-content-write.d.ts +11 -0
- package/dist/math-content-write.js +81 -0
- package/dist/math-font-write.cjs +100 -0
- package/dist/math-font-write.d.cts +19 -0
- package/dist/math-font-write.d.ts +19 -0
- package/dist/math-font-write.js +99 -0
- package/dist/math-font.cjs +103 -0
- package/dist/math-font.d.cts +25 -0
- package/dist/math-font.d.ts +25 -0
- package/dist/math-font.js +102 -0
- package/dist/math-hmtx.cjs +17 -0
- package/dist/math-hmtx.d.cts +8 -0
- package/dist/math-hmtx.d.ts +8 -0
- package/dist/math-hmtx.js +16 -0
- package/dist/math-table.cjs +117 -0
- package/dist/math-table.d.cts +45 -0
- package/dist/math-table.d.ts +45 -0
- package/dist/math-table.js +116 -0
- package/dist/math-types-Ba8qAf1p.d.cts +82 -0
- package/dist/math-types-Ba8qAf1p.d.ts +82 -0
- package/dist/math-types.cjs +0 -0
- package/dist/math-types.d.cts +2 -0
- package/dist/math-types.d.ts +2 -0
- package/dist/math-types.js +0 -0
- package/dist/matrix-B3c2_a2f.d.cts +18 -0
- package/dist/matrix-B3c2_a2f.d.ts +18 -0
- package/dist/matrix.cjs +93 -0
- package/dist/matrix.d.cts +2 -0
- package/dist/matrix.d.ts +2 -0
- package/dist/matrix.js +83 -0
- package/dist/measure.cjs +54 -0
- package/dist/measure.d.cts +20 -0
- package/dist/measure.d.ts +20 -0
- package/dist/measure.js +53 -0
- package/dist/objects.cjs +100 -0
- package/dist/objects.d.cts +58 -0
- package/dist/objects.d.ts +58 -0
- package/dist/objects.js +84 -0
- package/dist/parse.cjs +230 -0
- package/dist/parse.d.cts +13 -0
- package/dist/parse.d.ts +13 -0
- package/dist/parse.js +228 -0
- package/dist/predictors.cjs +64 -0
- package/dist/predictors.d.cts +13 -0
- package/dist/predictors.d.ts +13 -0
- package/dist/predictors.js +62 -0
- package/dist/read.cjs +418 -0
- package/dist/read.d.cts +21 -0
- package/dist/read.d.ts +21 -0
- package/dist/read.js +413 -0
- package/dist/serialize.cjs +69 -0
- package/dist/serialize.d.cts +8 -0
- package/dist/serialize.d.ts +8 -0
- package/dist/serialize.js +66 -0
- package/dist/sfnt.cjs +52 -0
- package/dist/sfnt.d.cts +17 -0
- package/dist/sfnt.d.ts +17 -0
- package/dist/sfnt.js +46 -0
- package/dist/text-layout.cjs +224 -0
- package/dist/text-layout.d.cts +37 -0
- package/dist/text-layout.d.ts +37 -0
- package/dist/text-layout.js +222 -0
- package/dist/util/abort.cjs +7 -0
- package/dist/util/abort.d.cts +4 -0
- package/dist/util/abort.d.ts +4 -0
- package/dist/util/abort.js +6 -0
- package/dist/util/base64.cjs +48 -0
- package/dist/util/base64.d.cts +5 -0
- package/dist/util/base64.d.ts +5 -0
- package/dist/util/base64.js +46 -0
- package/dist/winansi.cjs +5 -0
- package/dist/winansi.d.cts +20 -0
- package/dist/winansi.d.ts +20 -0
- package/dist/winansi.js +2 -0
- package/dist/write.cjs +421 -0
- package/dist/write.d.cts +16 -0
- package/dist/write.d.ts +16 -0
- package/dist/write.js +419 -0
- package/dist/xref.cjs +325 -0
- package/dist/xref.d.cts +21 -0
- package/dist/xref.d.ts +21 -0
- package/dist/xref.js +324 -0
- package/package.json +9 -1
package/dist/parse.cjs
ADDED
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_lexer = require("./lexer.cjs");
|
|
3
|
+
const require_objects = require("./objects.cjs");
|
|
4
|
+
//#region src/parse.ts
|
|
5
|
+
function parseValue(reader, sink) {
|
|
6
|
+
const token = require_lexer.nextToken(reader);
|
|
7
|
+
if (token === void 0) return;
|
|
8
|
+
switch (token.kind) {
|
|
9
|
+
case "number": return parseNumberOrReference(reader, token.value);
|
|
10
|
+
case "name": return require_objects.pdfName(token.value);
|
|
11
|
+
case "literalString": return require_objects.pdfLiteralString(token.value);
|
|
12
|
+
case "hexString": return require_objects.pdfHexString(token.value);
|
|
13
|
+
case "arrayStart": return parseArrayBody(reader, sink);
|
|
14
|
+
case "dictStart": return parseDictOrStreamBody(reader, sink);
|
|
15
|
+
case "keyword": return parseKeywordValue(token.value, sink);
|
|
16
|
+
case "arrayEnd":
|
|
17
|
+
case "dictEnd":
|
|
18
|
+
sink({
|
|
19
|
+
code: "pdf/unexpected-delimiter",
|
|
20
|
+
severity: "warning",
|
|
21
|
+
message: `unexpected "${token.kind === "arrayEnd" ? "]" : ">>"}" where a value was expected`
|
|
22
|
+
});
|
|
23
|
+
return require_objects.pdfNull();
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function parseKeywordValue(keyword, sink) {
|
|
27
|
+
if (keyword === "true") return require_objects.pdfBool(true);
|
|
28
|
+
if (keyword === "false") return require_objects.pdfBool(false);
|
|
29
|
+
if (keyword === "null") return require_objects.pdfNull();
|
|
30
|
+
sink({
|
|
31
|
+
code: "pdf/unexpected-keyword",
|
|
32
|
+
severity: "warning",
|
|
33
|
+
message: `unexpected keyword "${keyword}" where a value was expected`
|
|
34
|
+
});
|
|
35
|
+
return require_objects.pdfNull();
|
|
36
|
+
}
|
|
37
|
+
function parseNumberOrReference(reader, first) {
|
|
38
|
+
if (!Number.isInteger(first) || first < 0) return require_objects.pdfNum(first);
|
|
39
|
+
const mark = reader.mark();
|
|
40
|
+
const second = require_lexer.nextToken(reader);
|
|
41
|
+
if (second?.kind === "number" && Number.isInteger(second.value) && second.value >= 0) {
|
|
42
|
+
const third = require_lexer.nextToken(reader);
|
|
43
|
+
if (third?.kind === "keyword" && third.value === "R") return require_objects.pdfRef(first, second.value);
|
|
44
|
+
}
|
|
45
|
+
reader.reset(mark);
|
|
46
|
+
return require_objects.pdfNum(first);
|
|
47
|
+
}
|
|
48
|
+
function parseArrayBody(reader, sink) {
|
|
49
|
+
const items = [];
|
|
50
|
+
for (;;) {
|
|
51
|
+
const mark = reader.mark();
|
|
52
|
+
const token = require_lexer.nextToken(reader);
|
|
53
|
+
if (token === void 0) {
|
|
54
|
+
sink({
|
|
55
|
+
code: "pdf/unterminated-array",
|
|
56
|
+
severity: "warning",
|
|
57
|
+
message: "array not closed before end of input"
|
|
58
|
+
});
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
if (token.kind === "arrayEnd") break;
|
|
62
|
+
reader.reset(mark);
|
|
63
|
+
const beforeOffset = reader.offset;
|
|
64
|
+
const value = parseValue(reader, sink);
|
|
65
|
+
if (value === void 0 || reader.offset === beforeOffset) break;
|
|
66
|
+
items.push(value);
|
|
67
|
+
}
|
|
68
|
+
return require_objects.pdfArray(items);
|
|
69
|
+
}
|
|
70
|
+
function parseDictOrStreamBody(reader, sink) {
|
|
71
|
+
const entries = /* @__PURE__ */ new Map();
|
|
72
|
+
for (;;) {
|
|
73
|
+
const token = require_lexer.nextToken(reader);
|
|
74
|
+
if (token === void 0) {
|
|
75
|
+
sink({
|
|
76
|
+
code: "pdf/unterminated-dict",
|
|
77
|
+
severity: "warning",
|
|
78
|
+
message: "dictionary not closed before end of input"
|
|
79
|
+
});
|
|
80
|
+
break;
|
|
81
|
+
}
|
|
82
|
+
if (token.kind === "dictEnd") break;
|
|
83
|
+
if (token.kind !== "name") {
|
|
84
|
+
sink({
|
|
85
|
+
code: "pdf/dict-key-not-name",
|
|
86
|
+
severity: "warning",
|
|
87
|
+
message: `expected a /Name dictionary key, found "${token.kind}"`
|
|
88
|
+
});
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
const value = parseValue(reader, sink);
|
|
92
|
+
if (value === void 0) {
|
|
93
|
+
sink({
|
|
94
|
+
code: "pdf/dict-missing-value",
|
|
95
|
+
severity: "warning",
|
|
96
|
+
message: `dictionary key "/${token.value}" has no value before end of input`
|
|
97
|
+
});
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
entries.set(token.value, value);
|
|
101
|
+
}
|
|
102
|
+
const dict = require_objects.pdfDict(entries);
|
|
103
|
+
const afterDictMark = reader.mark();
|
|
104
|
+
const maybeStream = require_lexer.nextToken(reader);
|
|
105
|
+
if (maybeStream?.kind === "keyword" && maybeStream.value === "stream") return parseStreamBody(reader, sink, dict);
|
|
106
|
+
reader.reset(afterDictMark);
|
|
107
|
+
return dict;
|
|
108
|
+
}
|
|
109
|
+
function skipStreamDataStart(reader, sink) {
|
|
110
|
+
if (reader.peek() === 13) {
|
|
111
|
+
reader.next();
|
|
112
|
+
if (reader.peek() === 10) reader.next();
|
|
113
|
+
else sink({
|
|
114
|
+
code: "pdf/stream-bad-eol",
|
|
115
|
+
severity: "warning",
|
|
116
|
+
message: "stream keyword followed by a bare CR, not CRLF or LF as required"
|
|
117
|
+
});
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
if (reader.peek() === 10) {
|
|
121
|
+
reader.next();
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
sink({
|
|
125
|
+
code: "pdf/stream-bad-eol",
|
|
126
|
+
severity: "warning",
|
|
127
|
+
message: "stream keyword not followed by an end-of-line marker"
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
const ENDSTREAM_BYTES = new TextEncoder().encode("endstream");
|
|
131
|
+
function parseStreamBody(reader, sink, dict) {
|
|
132
|
+
skipStreamDataStart(reader, sink);
|
|
133
|
+
const dataStart = reader.offset;
|
|
134
|
+
const lengthObj = require_objects.dictGet(dict, "Length");
|
|
135
|
+
let dataEnd = resolveDirectLength(reader, dataStart, lengthObj);
|
|
136
|
+
if (dataEnd === void 0) {
|
|
137
|
+
if (lengthObj !== void 0) sink({
|
|
138
|
+
code: "pdf/stream-length-invalid",
|
|
139
|
+
severity: "warning",
|
|
140
|
+
message: "stream /Length was missing, indirect, or did not land on \"endstream\"; falling back to a scan for \"endstream\""
|
|
141
|
+
});
|
|
142
|
+
const found = findEndstreamOffset(reader, dataStart);
|
|
143
|
+
if (found === void 0) {
|
|
144
|
+
sink({
|
|
145
|
+
code: "pdf/stream-unterminated",
|
|
146
|
+
severity: "warning",
|
|
147
|
+
message: "no \"endstream\" found before end of input; treating the remainder of the file as stream data"
|
|
148
|
+
});
|
|
149
|
+
dataEnd = reader.length;
|
|
150
|
+
} else dataEnd = trimTrailingStreamEol(reader, dataStart, found);
|
|
151
|
+
}
|
|
152
|
+
const raw = reader.slice(dataStart, dataEnd);
|
|
153
|
+
reader.seek(dataEnd);
|
|
154
|
+
reader.skipWhitespace();
|
|
155
|
+
const endTok = require_lexer.nextToken(reader);
|
|
156
|
+
if (endTok?.kind !== "keyword" || endTok.value !== "endstream") sink({
|
|
157
|
+
code: "pdf/missing-endstream",
|
|
158
|
+
severity: "warning",
|
|
159
|
+
message: "stream data was not followed by \"endstream\""
|
|
160
|
+
});
|
|
161
|
+
return require_objects.pdfStream(dict, raw);
|
|
162
|
+
}
|
|
163
|
+
function resolveDirectLength(reader, dataStart, lengthObj) {
|
|
164
|
+
if (lengthObj?.kind !== "number" || !Number.isInteger(lengthObj.value) || lengthObj.value < 0) return;
|
|
165
|
+
const candidateEnd = dataStart + lengthObj.value;
|
|
166
|
+
if (candidateEnd > reader.length || !looksLikeEndstreamAt(reader, candidateEnd)) return;
|
|
167
|
+
return candidateEnd;
|
|
168
|
+
}
|
|
169
|
+
function looksLikeEndstreamAt(reader, offset) {
|
|
170
|
+
const mark = reader.mark();
|
|
171
|
+
reader.seek(offset);
|
|
172
|
+
reader.skipWhitespace();
|
|
173
|
+
const matches = reader.matchKeyword("endstream");
|
|
174
|
+
reader.reset(mark);
|
|
175
|
+
return matches;
|
|
176
|
+
}
|
|
177
|
+
function findEndstreamOffset(reader, fromOffset) {
|
|
178
|
+
const haystack = reader.slice(fromOffset, reader.length);
|
|
179
|
+
outer: for (let i = 0; i <= haystack.length - ENDSTREAM_BYTES.length; i++) {
|
|
180
|
+
for (let j = 0; j < ENDSTREAM_BYTES.length; j++) if (haystack[i + j] !== ENDSTREAM_BYTES[j]) continue outer;
|
|
181
|
+
return fromOffset + i;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
function trimTrailingStreamEol(reader, dataStart, endstreamOffset) {
|
|
185
|
+
const precedingTwo = reader.slice(Math.max(dataStart, endstreamOffset - 2), endstreamOffset);
|
|
186
|
+
if (precedingTwo.length >= 2 && precedingTwo[precedingTwo.length - 2] === 13 && precedingTwo[precedingTwo.length - 1] === 10) return endstreamOffset - 2;
|
|
187
|
+
if (precedingTwo.length >= 1 && (precedingTwo[precedingTwo.length - 1] === 10 || precedingTwo[precedingTwo.length - 1] === 13)) return endstreamOffset - 1;
|
|
188
|
+
return endstreamOffset;
|
|
189
|
+
}
|
|
190
|
+
function parseIndirectObject(reader, sink) {
|
|
191
|
+
const mark = reader.mark();
|
|
192
|
+
const numTok = require_lexer.nextToken(reader);
|
|
193
|
+
const genTok = require_lexer.nextToken(reader);
|
|
194
|
+
const objTok = require_lexer.nextToken(reader);
|
|
195
|
+
if (numTok?.kind !== "number" || genTok?.kind !== "number" || objTok?.kind !== "keyword" || objTok.value !== "obj") {
|
|
196
|
+
reader.reset(mark);
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
const value = parseValue(reader, sink);
|
|
200
|
+
if (value === void 0) {
|
|
201
|
+
sink({
|
|
202
|
+
code: "pdf/object-missing-value",
|
|
203
|
+
severity: "warning",
|
|
204
|
+
message: `object ${String(numTok.value)} ${String(genTok.value)} has no value before end of input`
|
|
205
|
+
});
|
|
206
|
+
return {
|
|
207
|
+
num: numTok.value,
|
|
208
|
+
gen: genTok.value,
|
|
209
|
+
value: require_objects.pdfNull()
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
const endMark = reader.mark();
|
|
213
|
+
const endTok = require_lexer.nextToken(reader);
|
|
214
|
+
if (endTok?.kind !== "keyword" || endTok.value !== "endobj") {
|
|
215
|
+
sink({
|
|
216
|
+
code: "pdf/missing-endobj",
|
|
217
|
+
severity: "warning",
|
|
218
|
+
message: `object ${String(numTok.value)} ${String(genTok.value)} is missing its "endobj" keyword`
|
|
219
|
+
});
|
|
220
|
+
reader.reset(endMark);
|
|
221
|
+
}
|
|
222
|
+
return {
|
|
223
|
+
num: numTok.value,
|
|
224
|
+
gen: genTok.value,
|
|
225
|
+
value
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
//#endregion
|
|
229
|
+
exports.parseIndirectObject = parseIndirectObject;
|
|
230
|
+
exports.parseValue = parseValue;
|
package/dist/parse.d.cts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ByteReader } from "./bytes/reader.cjs";
|
|
2
|
+
import { PdfDiagnosticSink } from "./diagnostics.cjs";
|
|
3
|
+
import { PdfObject } from "./objects.cjs";
|
|
4
|
+
//#region src/parse.d.ts
|
|
5
|
+
declare function parseValue(reader: ByteReader, sink: PdfDiagnosticSink): PdfObject | undefined;
|
|
6
|
+
interface ParsedIndirectObject {
|
|
7
|
+
readonly num: number;
|
|
8
|
+
readonly gen: number;
|
|
9
|
+
readonly value: PdfObject;
|
|
10
|
+
}
|
|
11
|
+
declare function parseIndirectObject(reader: ByteReader, sink: PdfDiagnosticSink): ParsedIndirectObject | undefined;
|
|
12
|
+
//#endregion
|
|
13
|
+
export { ParsedIndirectObject, parseIndirectObject, parseValue };
|
package/dist/parse.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ByteReader } from "./bytes/reader.js";
|
|
2
|
+
import { PdfDiagnosticSink } from "./diagnostics.js";
|
|
3
|
+
import { PdfObject } from "./objects.js";
|
|
4
|
+
//#region src/parse.d.ts
|
|
5
|
+
declare function parseValue(reader: ByteReader, sink: PdfDiagnosticSink): PdfObject | undefined;
|
|
6
|
+
interface ParsedIndirectObject {
|
|
7
|
+
readonly num: number;
|
|
8
|
+
readonly gen: number;
|
|
9
|
+
readonly value: PdfObject;
|
|
10
|
+
}
|
|
11
|
+
declare function parseIndirectObject(reader: ByteReader, sink: PdfDiagnosticSink): ParsedIndirectObject | undefined;
|
|
12
|
+
//#endregion
|
|
13
|
+
export { ParsedIndirectObject, parseIndirectObject, parseValue };
|
package/dist/parse.js
ADDED
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
import { nextToken } from "./lexer.js";
|
|
2
|
+
import { dictGet, pdfArray, pdfBool, pdfDict, pdfHexString, pdfLiteralString, pdfName, pdfNull, pdfNum, pdfRef, pdfStream } from "./objects.js";
|
|
3
|
+
//#region src/parse.ts
|
|
4
|
+
function parseValue(reader, sink) {
|
|
5
|
+
const token = nextToken(reader);
|
|
6
|
+
if (token === void 0) return;
|
|
7
|
+
switch (token.kind) {
|
|
8
|
+
case "number": return parseNumberOrReference(reader, token.value);
|
|
9
|
+
case "name": return pdfName(token.value);
|
|
10
|
+
case "literalString": return pdfLiteralString(token.value);
|
|
11
|
+
case "hexString": return pdfHexString(token.value);
|
|
12
|
+
case "arrayStart": return parseArrayBody(reader, sink);
|
|
13
|
+
case "dictStart": return parseDictOrStreamBody(reader, sink);
|
|
14
|
+
case "keyword": return parseKeywordValue(token.value, sink);
|
|
15
|
+
case "arrayEnd":
|
|
16
|
+
case "dictEnd":
|
|
17
|
+
sink({
|
|
18
|
+
code: "pdf/unexpected-delimiter",
|
|
19
|
+
severity: "warning",
|
|
20
|
+
message: `unexpected "${token.kind === "arrayEnd" ? "]" : ">>"}" where a value was expected`
|
|
21
|
+
});
|
|
22
|
+
return pdfNull();
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
function parseKeywordValue(keyword, sink) {
|
|
26
|
+
if (keyword === "true") return pdfBool(true);
|
|
27
|
+
if (keyword === "false") return pdfBool(false);
|
|
28
|
+
if (keyword === "null") return pdfNull();
|
|
29
|
+
sink({
|
|
30
|
+
code: "pdf/unexpected-keyword",
|
|
31
|
+
severity: "warning",
|
|
32
|
+
message: `unexpected keyword "${keyword}" where a value was expected`
|
|
33
|
+
});
|
|
34
|
+
return pdfNull();
|
|
35
|
+
}
|
|
36
|
+
function parseNumberOrReference(reader, first) {
|
|
37
|
+
if (!Number.isInteger(first) || first < 0) return pdfNum(first);
|
|
38
|
+
const mark = reader.mark();
|
|
39
|
+
const second = nextToken(reader);
|
|
40
|
+
if (second?.kind === "number" && Number.isInteger(second.value) && second.value >= 0) {
|
|
41
|
+
const third = nextToken(reader);
|
|
42
|
+
if (third?.kind === "keyword" && third.value === "R") return pdfRef(first, second.value);
|
|
43
|
+
}
|
|
44
|
+
reader.reset(mark);
|
|
45
|
+
return pdfNum(first);
|
|
46
|
+
}
|
|
47
|
+
function parseArrayBody(reader, sink) {
|
|
48
|
+
const items = [];
|
|
49
|
+
for (;;) {
|
|
50
|
+
const mark = reader.mark();
|
|
51
|
+
const token = nextToken(reader);
|
|
52
|
+
if (token === void 0) {
|
|
53
|
+
sink({
|
|
54
|
+
code: "pdf/unterminated-array",
|
|
55
|
+
severity: "warning",
|
|
56
|
+
message: "array not closed before end of input"
|
|
57
|
+
});
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
if (token.kind === "arrayEnd") break;
|
|
61
|
+
reader.reset(mark);
|
|
62
|
+
const beforeOffset = reader.offset;
|
|
63
|
+
const value = parseValue(reader, sink);
|
|
64
|
+
if (value === void 0 || reader.offset === beforeOffset) break;
|
|
65
|
+
items.push(value);
|
|
66
|
+
}
|
|
67
|
+
return pdfArray(items);
|
|
68
|
+
}
|
|
69
|
+
function parseDictOrStreamBody(reader, sink) {
|
|
70
|
+
const entries = /* @__PURE__ */ new Map();
|
|
71
|
+
for (;;) {
|
|
72
|
+
const token = nextToken(reader);
|
|
73
|
+
if (token === void 0) {
|
|
74
|
+
sink({
|
|
75
|
+
code: "pdf/unterminated-dict",
|
|
76
|
+
severity: "warning",
|
|
77
|
+
message: "dictionary not closed before end of input"
|
|
78
|
+
});
|
|
79
|
+
break;
|
|
80
|
+
}
|
|
81
|
+
if (token.kind === "dictEnd") break;
|
|
82
|
+
if (token.kind !== "name") {
|
|
83
|
+
sink({
|
|
84
|
+
code: "pdf/dict-key-not-name",
|
|
85
|
+
severity: "warning",
|
|
86
|
+
message: `expected a /Name dictionary key, found "${token.kind}"`
|
|
87
|
+
});
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
const value = parseValue(reader, sink);
|
|
91
|
+
if (value === void 0) {
|
|
92
|
+
sink({
|
|
93
|
+
code: "pdf/dict-missing-value",
|
|
94
|
+
severity: "warning",
|
|
95
|
+
message: `dictionary key "/${token.value}" has no value before end of input`
|
|
96
|
+
});
|
|
97
|
+
break;
|
|
98
|
+
}
|
|
99
|
+
entries.set(token.value, value);
|
|
100
|
+
}
|
|
101
|
+
const dict = pdfDict(entries);
|
|
102
|
+
const afterDictMark = reader.mark();
|
|
103
|
+
const maybeStream = nextToken(reader);
|
|
104
|
+
if (maybeStream?.kind === "keyword" && maybeStream.value === "stream") return parseStreamBody(reader, sink, dict);
|
|
105
|
+
reader.reset(afterDictMark);
|
|
106
|
+
return dict;
|
|
107
|
+
}
|
|
108
|
+
function skipStreamDataStart(reader, sink) {
|
|
109
|
+
if (reader.peek() === 13) {
|
|
110
|
+
reader.next();
|
|
111
|
+
if (reader.peek() === 10) reader.next();
|
|
112
|
+
else sink({
|
|
113
|
+
code: "pdf/stream-bad-eol",
|
|
114
|
+
severity: "warning",
|
|
115
|
+
message: "stream keyword followed by a bare CR, not CRLF or LF as required"
|
|
116
|
+
});
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
if (reader.peek() === 10) {
|
|
120
|
+
reader.next();
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
sink({
|
|
124
|
+
code: "pdf/stream-bad-eol",
|
|
125
|
+
severity: "warning",
|
|
126
|
+
message: "stream keyword not followed by an end-of-line marker"
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
const ENDSTREAM_BYTES = new TextEncoder().encode("endstream");
|
|
130
|
+
function parseStreamBody(reader, sink, dict) {
|
|
131
|
+
skipStreamDataStart(reader, sink);
|
|
132
|
+
const dataStart = reader.offset;
|
|
133
|
+
const lengthObj = dictGet(dict, "Length");
|
|
134
|
+
let dataEnd = resolveDirectLength(reader, dataStart, lengthObj);
|
|
135
|
+
if (dataEnd === void 0) {
|
|
136
|
+
if (lengthObj !== void 0) sink({
|
|
137
|
+
code: "pdf/stream-length-invalid",
|
|
138
|
+
severity: "warning",
|
|
139
|
+
message: "stream /Length was missing, indirect, or did not land on \"endstream\"; falling back to a scan for \"endstream\""
|
|
140
|
+
});
|
|
141
|
+
const found = findEndstreamOffset(reader, dataStart);
|
|
142
|
+
if (found === void 0) {
|
|
143
|
+
sink({
|
|
144
|
+
code: "pdf/stream-unterminated",
|
|
145
|
+
severity: "warning",
|
|
146
|
+
message: "no \"endstream\" found before end of input; treating the remainder of the file as stream data"
|
|
147
|
+
});
|
|
148
|
+
dataEnd = reader.length;
|
|
149
|
+
} else dataEnd = trimTrailingStreamEol(reader, dataStart, found);
|
|
150
|
+
}
|
|
151
|
+
const raw = reader.slice(dataStart, dataEnd);
|
|
152
|
+
reader.seek(dataEnd);
|
|
153
|
+
reader.skipWhitespace();
|
|
154
|
+
const endTok = nextToken(reader);
|
|
155
|
+
if (endTok?.kind !== "keyword" || endTok.value !== "endstream") sink({
|
|
156
|
+
code: "pdf/missing-endstream",
|
|
157
|
+
severity: "warning",
|
|
158
|
+
message: "stream data was not followed by \"endstream\""
|
|
159
|
+
});
|
|
160
|
+
return pdfStream(dict, raw);
|
|
161
|
+
}
|
|
162
|
+
function resolveDirectLength(reader, dataStart, lengthObj) {
|
|
163
|
+
if (lengthObj?.kind !== "number" || !Number.isInteger(lengthObj.value) || lengthObj.value < 0) return;
|
|
164
|
+
const candidateEnd = dataStart + lengthObj.value;
|
|
165
|
+
if (candidateEnd > reader.length || !looksLikeEndstreamAt(reader, candidateEnd)) return;
|
|
166
|
+
return candidateEnd;
|
|
167
|
+
}
|
|
168
|
+
function looksLikeEndstreamAt(reader, offset) {
|
|
169
|
+
const mark = reader.mark();
|
|
170
|
+
reader.seek(offset);
|
|
171
|
+
reader.skipWhitespace();
|
|
172
|
+
const matches = reader.matchKeyword("endstream");
|
|
173
|
+
reader.reset(mark);
|
|
174
|
+
return matches;
|
|
175
|
+
}
|
|
176
|
+
function findEndstreamOffset(reader, fromOffset) {
|
|
177
|
+
const haystack = reader.slice(fromOffset, reader.length);
|
|
178
|
+
outer: for (let i = 0; i <= haystack.length - ENDSTREAM_BYTES.length; i++) {
|
|
179
|
+
for (let j = 0; j < ENDSTREAM_BYTES.length; j++) if (haystack[i + j] !== ENDSTREAM_BYTES[j]) continue outer;
|
|
180
|
+
return fromOffset + i;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
function trimTrailingStreamEol(reader, dataStart, endstreamOffset) {
|
|
184
|
+
const precedingTwo = reader.slice(Math.max(dataStart, endstreamOffset - 2), endstreamOffset);
|
|
185
|
+
if (precedingTwo.length >= 2 && precedingTwo[precedingTwo.length - 2] === 13 && precedingTwo[precedingTwo.length - 1] === 10) return endstreamOffset - 2;
|
|
186
|
+
if (precedingTwo.length >= 1 && (precedingTwo[precedingTwo.length - 1] === 10 || precedingTwo[precedingTwo.length - 1] === 13)) return endstreamOffset - 1;
|
|
187
|
+
return endstreamOffset;
|
|
188
|
+
}
|
|
189
|
+
function parseIndirectObject(reader, sink) {
|
|
190
|
+
const mark = reader.mark();
|
|
191
|
+
const numTok = nextToken(reader);
|
|
192
|
+
const genTok = nextToken(reader);
|
|
193
|
+
const objTok = nextToken(reader);
|
|
194
|
+
if (numTok?.kind !== "number" || genTok?.kind !== "number" || objTok?.kind !== "keyword" || objTok.value !== "obj") {
|
|
195
|
+
reader.reset(mark);
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
const value = parseValue(reader, sink);
|
|
199
|
+
if (value === void 0) {
|
|
200
|
+
sink({
|
|
201
|
+
code: "pdf/object-missing-value",
|
|
202
|
+
severity: "warning",
|
|
203
|
+
message: `object ${String(numTok.value)} ${String(genTok.value)} has no value before end of input`
|
|
204
|
+
});
|
|
205
|
+
return {
|
|
206
|
+
num: numTok.value,
|
|
207
|
+
gen: genTok.value,
|
|
208
|
+
value: pdfNull()
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
const endMark = reader.mark();
|
|
212
|
+
const endTok = nextToken(reader);
|
|
213
|
+
if (endTok?.kind !== "keyword" || endTok.value !== "endobj") {
|
|
214
|
+
sink({
|
|
215
|
+
code: "pdf/missing-endobj",
|
|
216
|
+
severity: "warning",
|
|
217
|
+
message: `object ${String(numTok.value)} ${String(genTok.value)} is missing its "endobj" keyword`
|
|
218
|
+
});
|
|
219
|
+
reader.reset(endMark);
|
|
220
|
+
}
|
|
221
|
+
return {
|
|
222
|
+
num: numTok.value,
|
|
223
|
+
gen: genTok.value,
|
|
224
|
+
value
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
//#endregion
|
|
228
|
+
export { parseIndirectObject, parseValue };
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_objects = require("./objects.cjs");
|
|
3
|
+
const require_image_png_filter = require("./image/png-filter.cjs");
|
|
4
|
+
//#region src/predictors.ts
|
|
5
|
+
const DEFAULT_PREDICTOR = 1;
|
|
6
|
+
const DEFAULT_COLORS = 1;
|
|
7
|
+
const DEFAULT_BITS_PER_COMPONENT = 8;
|
|
8
|
+
const DEFAULT_COLUMNS = 1;
|
|
9
|
+
function readPredictorParams(parms) {
|
|
10
|
+
return {
|
|
11
|
+
predictor: require_objects.asNumber(parms ? require_objects.dictGet(parms, "Predictor") : void 0) ?? DEFAULT_PREDICTOR,
|
|
12
|
+
colors: require_objects.asNumber(parms ? require_objects.dictGet(parms, "Colors") : void 0) ?? DEFAULT_COLORS,
|
|
13
|
+
bitsPerComponent: require_objects.asNumber(parms ? require_objects.dictGet(parms, "BitsPerComponent") : void 0) ?? DEFAULT_BITS_PER_COMPONENT,
|
|
14
|
+
columns: require_objects.asNumber(parms ? require_objects.dictGet(parms, "Columns") : void 0) ?? DEFAULT_COLUMNS
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
function applyPredictor(data, params, sink) {
|
|
18
|
+
if (params.predictor <= 1) return data;
|
|
19
|
+
const bpp = Math.max(1, Math.ceil(params.colors * params.bitsPerComponent / 8));
|
|
20
|
+
const bytesPerRow = Math.ceil(params.colors * params.bitsPerComponent * params.columns / 8);
|
|
21
|
+
if (params.predictor === 2) return applyTiffPredictor(data, params, bytesPerRow, sink);
|
|
22
|
+
if (params.predictor >= 10) {
|
|
23
|
+
const height = bytesPerRow > 0 ? Math.floor(data.length / (bytesPerRow + 1)) : 0;
|
|
24
|
+
return require_image_png_filter.unfilterScanlines(data, height, bytesPerRow, bpp);
|
|
25
|
+
}
|
|
26
|
+
sink({
|
|
27
|
+
code: "pdf/unsupported-predictor",
|
|
28
|
+
severity: "warning",
|
|
29
|
+
message: `unsupported /Predictor value ${String(params.predictor)}; leaving data unpredicted`
|
|
30
|
+
});
|
|
31
|
+
return data;
|
|
32
|
+
}
|
|
33
|
+
function applyTiffPredictor(data, params, bytesPerRow, sink) {
|
|
34
|
+
if (params.bitsPerComponent !== 8 && params.bitsPerComponent !== 16) {
|
|
35
|
+
sink({
|
|
36
|
+
code: "pdf/unsupported-predictor",
|
|
37
|
+
severity: "warning",
|
|
38
|
+
message: `TIFF predictor with ${String(params.bitsPerComponent)}-bit components is not supported; leaving data unpredicted`
|
|
39
|
+
});
|
|
40
|
+
return data;
|
|
41
|
+
}
|
|
42
|
+
const out = new Uint8Array(data.length);
|
|
43
|
+
out.set(data);
|
|
44
|
+
const rowCount = bytesPerRow > 0 ? Math.floor(out.length / bytesPerRow) : 0;
|
|
45
|
+
const componentStride = params.bitsPerComponent === 16 ? 2 : 1;
|
|
46
|
+
const componentsPerPixel = params.colors;
|
|
47
|
+
for (let row = 0; row < rowCount; row++) {
|
|
48
|
+
const rowStart = row * bytesPerRow;
|
|
49
|
+
for (let component = componentsPerPixel; component * componentStride < bytesPerRow; component++) {
|
|
50
|
+
const i = rowStart + component * componentStride;
|
|
51
|
+
const prevI = i - componentsPerPixel * componentStride;
|
|
52
|
+
if (componentStride === 1) out[i] = (out[i] ?? 0) + (out[prevI] ?? 0) & 255;
|
|
53
|
+
else {
|
|
54
|
+
const sum = ((out[i] ?? 0) << 8 | (out[i + 1] ?? 0)) + ((out[prevI] ?? 0) << 8 | (out[prevI + 1] ?? 0)) & 65535;
|
|
55
|
+
out[i] = sum >> 8 & 255;
|
|
56
|
+
out[i + 1] = sum & 255;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return out;
|
|
61
|
+
}
|
|
62
|
+
//#endregion
|
|
63
|
+
exports.applyPredictor = applyPredictor;
|
|
64
|
+
exports.readPredictorParams = readPredictorParams;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { PdfDiagnosticSink } from "./diagnostics.cjs";
|
|
2
|
+
import { PdfDict } from "./objects.cjs";
|
|
3
|
+
//#region src/predictors.d.ts
|
|
4
|
+
interface PredictorParams {
|
|
5
|
+
readonly predictor: number;
|
|
6
|
+
readonly colors: number;
|
|
7
|
+
readonly bitsPerComponent: number;
|
|
8
|
+
readonly columns: number;
|
|
9
|
+
}
|
|
10
|
+
declare function readPredictorParams(parms: PdfDict | undefined): PredictorParams;
|
|
11
|
+
declare function applyPredictor(data: Uint8Array<ArrayBuffer>, params: PredictorParams, sink: PdfDiagnosticSink): Uint8Array<ArrayBuffer>;
|
|
12
|
+
//#endregion
|
|
13
|
+
export { PredictorParams, applyPredictor, readPredictorParams };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { PdfDiagnosticSink } from "./diagnostics.js";
|
|
2
|
+
import { PdfDict } from "./objects.js";
|
|
3
|
+
//#region src/predictors.d.ts
|
|
4
|
+
interface PredictorParams {
|
|
5
|
+
readonly predictor: number;
|
|
6
|
+
readonly colors: number;
|
|
7
|
+
readonly bitsPerComponent: number;
|
|
8
|
+
readonly columns: number;
|
|
9
|
+
}
|
|
10
|
+
declare function readPredictorParams(parms: PdfDict | undefined): PredictorParams;
|
|
11
|
+
declare function applyPredictor(data: Uint8Array<ArrayBuffer>, params: PredictorParams, sink: PdfDiagnosticSink): Uint8Array<ArrayBuffer>;
|
|
12
|
+
//#endregion
|
|
13
|
+
export { PredictorParams, applyPredictor, readPredictorParams };
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { asNumber, dictGet } from "./objects.js";
|
|
2
|
+
import { unfilterScanlines } from "./image/png-filter.js";
|
|
3
|
+
//#region src/predictors.ts
|
|
4
|
+
const DEFAULT_PREDICTOR = 1;
|
|
5
|
+
const DEFAULT_COLORS = 1;
|
|
6
|
+
const DEFAULT_BITS_PER_COMPONENT = 8;
|
|
7
|
+
const DEFAULT_COLUMNS = 1;
|
|
8
|
+
function readPredictorParams(parms) {
|
|
9
|
+
return {
|
|
10
|
+
predictor: asNumber(parms ? dictGet(parms, "Predictor") : void 0) ?? DEFAULT_PREDICTOR,
|
|
11
|
+
colors: asNumber(parms ? dictGet(parms, "Colors") : void 0) ?? DEFAULT_COLORS,
|
|
12
|
+
bitsPerComponent: asNumber(parms ? dictGet(parms, "BitsPerComponent") : void 0) ?? DEFAULT_BITS_PER_COMPONENT,
|
|
13
|
+
columns: asNumber(parms ? dictGet(parms, "Columns") : void 0) ?? DEFAULT_COLUMNS
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
function applyPredictor(data, params, sink) {
|
|
17
|
+
if (params.predictor <= 1) return data;
|
|
18
|
+
const bpp = Math.max(1, Math.ceil(params.colors * params.bitsPerComponent / 8));
|
|
19
|
+
const bytesPerRow = Math.ceil(params.colors * params.bitsPerComponent * params.columns / 8);
|
|
20
|
+
if (params.predictor === 2) return applyTiffPredictor(data, params, bytesPerRow, sink);
|
|
21
|
+
if (params.predictor >= 10) {
|
|
22
|
+
const height = bytesPerRow > 0 ? Math.floor(data.length / (bytesPerRow + 1)) : 0;
|
|
23
|
+
return unfilterScanlines(data, height, bytesPerRow, bpp);
|
|
24
|
+
}
|
|
25
|
+
sink({
|
|
26
|
+
code: "pdf/unsupported-predictor",
|
|
27
|
+
severity: "warning",
|
|
28
|
+
message: `unsupported /Predictor value ${String(params.predictor)}; leaving data unpredicted`
|
|
29
|
+
});
|
|
30
|
+
return data;
|
|
31
|
+
}
|
|
32
|
+
function applyTiffPredictor(data, params, bytesPerRow, sink) {
|
|
33
|
+
if (params.bitsPerComponent !== 8 && params.bitsPerComponent !== 16) {
|
|
34
|
+
sink({
|
|
35
|
+
code: "pdf/unsupported-predictor",
|
|
36
|
+
severity: "warning",
|
|
37
|
+
message: `TIFF predictor with ${String(params.bitsPerComponent)}-bit components is not supported; leaving data unpredicted`
|
|
38
|
+
});
|
|
39
|
+
return data;
|
|
40
|
+
}
|
|
41
|
+
const out = new Uint8Array(data.length);
|
|
42
|
+
out.set(data);
|
|
43
|
+
const rowCount = bytesPerRow > 0 ? Math.floor(out.length / bytesPerRow) : 0;
|
|
44
|
+
const componentStride = params.bitsPerComponent === 16 ? 2 : 1;
|
|
45
|
+
const componentsPerPixel = params.colors;
|
|
46
|
+
for (let row = 0; row < rowCount; row++) {
|
|
47
|
+
const rowStart = row * bytesPerRow;
|
|
48
|
+
for (let component = componentsPerPixel; component * componentStride < bytesPerRow; component++) {
|
|
49
|
+
const i = rowStart + component * componentStride;
|
|
50
|
+
const prevI = i - componentsPerPixel * componentStride;
|
|
51
|
+
if (componentStride === 1) out[i] = (out[i] ?? 0) + (out[prevI] ?? 0) & 255;
|
|
52
|
+
else {
|
|
53
|
+
const sum = ((out[i] ?? 0) << 8 | (out[i + 1] ?? 0)) + ((out[prevI] ?? 0) << 8 | (out[prevI + 1] ?? 0)) & 65535;
|
|
54
|
+
out[i] = sum >> 8 & 255;
|
|
55
|
+
out[i + 1] = sum & 255;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return out;
|
|
60
|
+
}
|
|
61
|
+
//#endregion
|
|
62
|
+
export { applyPredictor, readPredictorParams };
|