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.
Files changed (198) hide show
  1. package/README.md +38 -0
  2. package/dist/afm-widths-BoeTOK2r.cjs +826 -0
  3. package/dist/afm-widths-Dxucrg7D.js +779 -0
  4. package/dist/afm-widths-DyDq56Ph.d.cts +19 -0
  5. package/dist/afm-widths-DyDq56Ph.d.ts +19 -0
  6. package/dist/afm-widths.cjs +4 -0
  7. package/dist/afm-widths.d.cts +2 -0
  8. package/dist/afm-widths.d.ts +2 -0
  9. package/dist/afm-widths.js +2 -0
  10. package/dist/assets/stix-two-math-font.cjs +5 -0
  11. package/dist/assets/stix-two-math-font.d.cts +4 -0
  12. package/dist/assets/stix-two-math-font.d.ts +4 -0
  13. package/dist/assets/stix-two-math-font.js +4 -0
  14. package/dist/bytes/crc32.cjs +21 -0
  15. package/dist/bytes/crc32.d.cts +4 -0
  16. package/dist/bytes/crc32.d.ts +4 -0
  17. package/dist/bytes/crc32.js +20 -0
  18. package/dist/bytes/flate.cjs +53 -0
  19. package/dist/bytes/flate.d.cts +12 -0
  20. package/dist/bytes/flate.d.ts +12 -0
  21. package/dist/bytes/flate.js +49 -0
  22. package/dist/bytes/reader.cjs +60 -0
  23. package/dist/bytes/reader.d.cts +20 -0
  24. package/dist/bytes/reader.d.ts +20 -0
  25. package/dist/bytes/reader.js +58 -0
  26. package/dist/bytes/writer.cjs +37 -0
  27. package/dist/bytes/writer.d.cts +13 -0
  28. package/dist/bytes/writer.d.ts +13 -0
  29. package/dist/bytes/writer.js +35 -0
  30. package/dist/cmap.cjs +110 -0
  31. package/dist/cmap.d.cts +8 -0
  32. package/dist/cmap.d.ts +8 -0
  33. package/dist/cmap.js +109 -0
  34. package/dist/codec.cjs +34 -0
  35. package/dist/codec.d.cts +167 -0
  36. package/dist/codec.d.ts +167 -0
  37. package/dist/codec.js +32 -0
  38. package/dist/content-read.cjs +126 -0
  39. package/dist/content-read.d.cts +21 -0
  40. package/dist/content-read.d.ts +21 -0
  41. package/dist/content-read.js +125 -0
  42. package/dist/content-write.cjs +138 -0
  43. package/dist/content-write.d.cts +24 -0
  44. package/dist/content-write.d.ts +24 -0
  45. package/dist/content-write.js +137 -0
  46. package/dist/diagnostics.cjs +21 -0
  47. package/dist/diagnostics.d.cts +19 -0
  48. package/dist/diagnostics.d.ts +19 -0
  49. package/dist/diagnostics.js +18 -0
  50. package/dist/document.cjs +162 -0
  51. package/dist/document.d.cts +12 -0
  52. package/dist/document.d.ts +12 -0
  53. package/dist/document.js +161 -0
  54. package/dist/encoding.cjs +5 -0
  55. package/dist/encoding.d.cts +6 -0
  56. package/dist/encoding.d.ts +6 -0
  57. package/dist/encoding.js +2 -0
  58. package/dist/filters.cjs +223 -0
  59. package/dist/filters.d.cts +14 -0
  60. package/dist/filters.d.ts +14 -0
  61. package/dist/filters.js +218 -0
  62. package/dist/font-read.cjs +199 -0
  63. package/dist/font-read.d.cts +23 -0
  64. package/dist/font-read.d.ts +23 -0
  65. package/dist/font-read.js +198 -0
  66. package/dist/font-style.cjs +35 -0
  67. package/dist/font-style.d.cts +14 -0
  68. package/dist/font-style.d.ts +14 -0
  69. package/dist/font-style.js +34 -0
  70. package/dist/fonts.cjs +124 -0
  71. package/dist/fonts.d.cts +15 -0
  72. package/dist/fonts.d.ts +15 -0
  73. package/dist/fonts.js +122 -0
  74. package/dist/formula.cjs +0 -0
  75. package/dist/formula.d.cts +10 -0
  76. package/dist/formula.d.ts +10 -0
  77. package/dist/formula.js +0 -0
  78. package/dist/image/jpeg-info.cjs +71 -0
  79. package/dist/image/jpeg-info.d.cts +12 -0
  80. package/dist/image/jpeg-info.d.ts +12 -0
  81. package/dist/image/jpeg-info.js +70 -0
  82. package/dist/image/png-decode.cjs +181 -0
  83. package/dist/image/png-decode.d.cts +14 -0
  84. package/dist/image/png-decode.d.ts +14 -0
  85. package/dist/image/png-decode.js +180 -0
  86. package/dist/image/png-encode.cjs +64 -0
  87. package/dist/image/png-encode.d.cts +8 -0
  88. package/dist/image/png-encode.d.ts +8 -0
  89. package/dist/image/png-encode.js +63 -0
  90. package/dist/image/png-filter.cjs +95 -0
  91. package/dist/image/png-filter.d.cts +6 -0
  92. package/dist/image/png-filter.d.ts +6 -0
  93. package/dist/image/png-filter.js +93 -0
  94. package/dist/images-read.cjs +250 -0
  95. package/dist/images-read.d.cts +13 -0
  96. package/dist/images-read.d.ts +13 -0
  97. package/dist/images-read.js +249 -0
  98. package/dist/index.cjs +45 -5912
  99. package/dist/index.d.cts +21 -483
  100. package/dist/index.d.ts +21 -483
  101. package/dist/index.js +18 -5885
  102. package/dist/interpret.cjs +587 -0
  103. package/dist/interpret.d.cts +84 -0
  104. package/dist/interpret.d.ts +84 -0
  105. package/dist/interpret.js +586 -0
  106. package/dist/lexer.cjs +180 -0
  107. package/dist/lexer.d.cts +29 -0
  108. package/dist/lexer.d.ts +29 -0
  109. package/dist/lexer.js +179 -0
  110. package/dist/math-cmap.cjs +81 -0
  111. package/dist/math-cmap.d.cts +6 -0
  112. package/dist/math-cmap.d.ts +6 -0
  113. package/dist/math-cmap.js +80 -0
  114. package/dist/math-content-write.cjs +83 -0
  115. package/dist/math-content-write.d.cts +11 -0
  116. package/dist/math-content-write.d.ts +11 -0
  117. package/dist/math-content-write.js +81 -0
  118. package/dist/math-font-write.cjs +100 -0
  119. package/dist/math-font-write.d.cts +19 -0
  120. package/dist/math-font-write.d.ts +19 -0
  121. package/dist/math-font-write.js +99 -0
  122. package/dist/math-font.cjs +103 -0
  123. package/dist/math-font.d.cts +25 -0
  124. package/dist/math-font.d.ts +25 -0
  125. package/dist/math-font.js +102 -0
  126. package/dist/math-hmtx.cjs +17 -0
  127. package/dist/math-hmtx.d.cts +8 -0
  128. package/dist/math-hmtx.d.ts +8 -0
  129. package/dist/math-hmtx.js +16 -0
  130. package/dist/math-table.cjs +117 -0
  131. package/dist/math-table.d.cts +45 -0
  132. package/dist/math-table.d.ts +45 -0
  133. package/dist/math-table.js +116 -0
  134. package/dist/math-types-Ba8qAf1p.d.cts +82 -0
  135. package/dist/math-types-Ba8qAf1p.d.ts +82 -0
  136. package/dist/math-types.cjs +0 -0
  137. package/dist/math-types.d.cts +2 -0
  138. package/dist/math-types.d.ts +2 -0
  139. package/dist/math-types.js +0 -0
  140. package/dist/matrix-B3c2_a2f.d.cts +18 -0
  141. package/dist/matrix-B3c2_a2f.d.ts +18 -0
  142. package/dist/matrix.cjs +93 -0
  143. package/dist/matrix.d.cts +2 -0
  144. package/dist/matrix.d.ts +2 -0
  145. package/dist/matrix.js +83 -0
  146. package/dist/measure.cjs +54 -0
  147. package/dist/measure.d.cts +20 -0
  148. package/dist/measure.d.ts +20 -0
  149. package/dist/measure.js +53 -0
  150. package/dist/objects.cjs +100 -0
  151. package/dist/objects.d.cts +58 -0
  152. package/dist/objects.d.ts +58 -0
  153. package/dist/objects.js +84 -0
  154. package/dist/parse.cjs +230 -0
  155. package/dist/parse.d.cts +13 -0
  156. package/dist/parse.d.ts +13 -0
  157. package/dist/parse.js +228 -0
  158. package/dist/predictors.cjs +64 -0
  159. package/dist/predictors.d.cts +13 -0
  160. package/dist/predictors.d.ts +13 -0
  161. package/dist/predictors.js +62 -0
  162. package/dist/read.cjs +418 -0
  163. package/dist/read.d.cts +21 -0
  164. package/dist/read.d.ts +21 -0
  165. package/dist/read.js +413 -0
  166. package/dist/serialize.cjs +69 -0
  167. package/dist/serialize.d.cts +8 -0
  168. package/dist/serialize.d.ts +8 -0
  169. package/dist/serialize.js +66 -0
  170. package/dist/sfnt.cjs +52 -0
  171. package/dist/sfnt.d.cts +17 -0
  172. package/dist/sfnt.d.ts +17 -0
  173. package/dist/sfnt.js +46 -0
  174. package/dist/text-layout.cjs +224 -0
  175. package/dist/text-layout.d.cts +37 -0
  176. package/dist/text-layout.d.ts +37 -0
  177. package/dist/text-layout.js +222 -0
  178. package/dist/util/abort.cjs +7 -0
  179. package/dist/util/abort.d.cts +4 -0
  180. package/dist/util/abort.d.ts +4 -0
  181. package/dist/util/abort.js +6 -0
  182. package/dist/util/base64.cjs +48 -0
  183. package/dist/util/base64.d.cts +5 -0
  184. package/dist/util/base64.d.ts +5 -0
  185. package/dist/util/base64.js +46 -0
  186. package/dist/winansi.cjs +5 -0
  187. package/dist/winansi.d.cts +20 -0
  188. package/dist/winansi.d.ts +20 -0
  189. package/dist/winansi.js +2 -0
  190. package/dist/write.cjs +421 -0
  191. package/dist/write.d.cts +16 -0
  192. package/dist/write.d.ts +16 -0
  193. package/dist/write.js +419 -0
  194. package/dist/xref.cjs +325 -0
  195. package/dist/xref.d.cts +21 -0
  196. package/dist/xref.d.ts +21 -0
  197. package/dist/xref.js +324 -0
  198. package/package.json +9 -1
@@ -0,0 +1,161 @@
1
+ import { ByteReader } from "./bytes/reader.js";
2
+ import { nextToken } from "./lexer.js";
3
+ import { PdfEncryptedError, PdfParseError } from "./diagnostics.js";
4
+ import { asArray, asDict, asNumber, dictGet, isName, pdfNull } from "./objects.js";
5
+ import { decodeStream } from "./filters.js";
6
+ import { parseIndirectObject, parseValue } from "./parse.js";
7
+ import { readXref } from "./xref.js";
8
+ //#region src/document.ts
9
+ const MAX_RESOLVE_DEPTH = 64;
10
+ const INHERITABLE_PAGE_KEYS = [
11
+ "Resources",
12
+ "MediaBox",
13
+ "CropBox",
14
+ "Rotate"
15
+ ];
16
+ function openPdfDocument(bytes, sink) {
17
+ const xref = readXref(bytes, sink);
18
+ if (dictGet(xref.trailer, "Encrypt") !== void 0) throw new PdfEncryptedError();
19
+ const objectCache = /* @__PURE__ */ new Map();
20
+ const objStmCache = /* @__PURE__ */ new Map();
21
+ function fetchDirect(num, entry) {
22
+ const reader = new ByteReader(bytes);
23
+ reader.seek(entry.offset);
24
+ const indirect = parseIndirectObject(reader, sink);
25
+ if (indirect === void 0) {
26
+ sink({
27
+ code: "pdf/object-missing-value",
28
+ severity: "warning",
29
+ message: `object ${String(num)} could not be parsed at its recorded offset`
30
+ });
31
+ return pdfNull();
32
+ }
33
+ return indirect.value;
34
+ }
35
+ function decodeObjectStream(streamObjNum) {
36
+ const cached = objStmCache.get(streamObjNum);
37
+ if (cached !== void 0) return cached;
38
+ const streamEntry = xref.entries.get(streamObjNum);
39
+ const streamObj = streamEntry?.type === "offset" ? fetchDirect(streamObjNum, streamEntry) : void 0;
40
+ if (streamObj?.kind !== "stream") {
41
+ sink({
42
+ code: "pdf/object-missing-value",
43
+ severity: "warning",
44
+ message: `object ${String(streamObjNum)} referenced as an object stream is not directly-located, or is not actually a stream`
45
+ });
46
+ objStmCache.set(streamObjNum, []);
47
+ return [];
48
+ }
49
+ const decoded = decodeStream(streamObj.raw, streamObj.dict, sink);
50
+ const n = asNumber(dictGet(streamObj.dict, "N")) ?? 0;
51
+ const first = asNumber(dictGet(streamObj.dict, "First")) ?? 0;
52
+ const headerReader = new ByteReader(decoded.bytes);
53
+ const relativeOffsets = [];
54
+ for (let i = 0; i < n; i++) {
55
+ const numTok = nextToken(headerReader);
56
+ const offTok = nextToken(headerReader);
57
+ if (numTok?.kind !== "number" || offTok?.kind !== "number") {
58
+ sink({
59
+ code: "pdf/object-missing-value",
60
+ severity: "warning",
61
+ message: `object stream ${String(streamObjNum)} header is truncated at entry ${String(i)}`
62
+ });
63
+ break;
64
+ }
65
+ relativeOffsets.push(offTok.value);
66
+ }
67
+ const values = relativeOffsets.map((relativeOffset) => {
68
+ const valueReader = new ByteReader(decoded.bytes);
69
+ valueReader.seek(first + relativeOffset);
70
+ return parseValue(valueReader, sink) ?? pdfNull();
71
+ });
72
+ objStmCache.set(streamObjNum, values);
73
+ return values;
74
+ }
75
+ function fetch(num) {
76
+ const cached = objectCache.get(num);
77
+ if (cached !== void 0) return cached;
78
+ const entry = xref.entries.get(num);
79
+ if (entry === void 0) {
80
+ sink({
81
+ code: "pdf/object-missing-value",
82
+ severity: "warning",
83
+ message: `object ${String(num)} is referenced but not present in the cross-reference table`
84
+ });
85
+ return pdfNull();
86
+ }
87
+ const value = entry.type === "offset" ? fetchDirect(num, entry) : decodeObjectStream(entry.streamObjNum)[entry.indexInStream] ?? pdfNull();
88
+ objectCache.set(num, value);
89
+ return value;
90
+ }
91
+ function resolve(obj) {
92
+ let current = obj;
93
+ let depth = 0;
94
+ while (current?.kind === "ref" && depth < MAX_RESOLVE_DEPTH) {
95
+ current = fetch(current.num);
96
+ depth++;
97
+ }
98
+ if (depth >= MAX_RESOLVE_DEPTH) {
99
+ sink({
100
+ code: "pdf/reference-cycle",
101
+ severity: "warning",
102
+ message: "a chain of indirect references did not resolve within the depth limit; treating it as null"
103
+ });
104
+ return pdfNull();
105
+ }
106
+ return current;
107
+ }
108
+ function resolveDict(obj) {
109
+ return asDict(resolve(obj));
110
+ }
111
+ function requireCatalog(dict) {
112
+ if (dict === void 0 || !isName(dictGet(dict, "Type"), "Catalog")) throw new PdfParseError("pdf/no-root", "no resolvable /Root catalog was found, even after cross-reference recovery");
113
+ return dict;
114
+ }
115
+ const catalog = requireCatalog(resolveDict(dictGet(xref.trailer, "Root")));
116
+ function pages() {
117
+ const pagesRoot = resolveDict(dictGet(catalog, "Pages"));
118
+ if (pagesRoot === void 0) return [];
119
+ const result = [];
120
+ walkPageTree(pagesRoot, {}, /* @__PURE__ */ new Set(), result);
121
+ return result;
122
+ }
123
+ function walkPageTree(node, inherited, visited, result) {
124
+ if (visited.has(node)) {
125
+ sink({
126
+ code: "pdf/page-tree-cycle",
127
+ severity: "warning",
128
+ message: "the page tree contains a cycle; stopping descent at the repeated node"
129
+ });
130
+ return;
131
+ }
132
+ visited.add(node);
133
+ const merged = { ...inherited };
134
+ for (const key of INHERITABLE_PAGE_KEYS) {
135
+ const own = dictGet(node, key);
136
+ if (own !== void 0) merged[key] = own;
137
+ }
138
+ const kids = asArray(dictGet(node, "Kids"));
139
+ if (kids === void 0) {
140
+ const entries = new Map(node.entries);
141
+ for (const key of INHERITABLE_PAGE_KEYS) if (!entries.has(key) && merged[key] !== void 0) entries.set(key, merged[key]);
142
+ result.push({
143
+ kind: "dict",
144
+ entries
145
+ });
146
+ return;
147
+ }
148
+ for (const kid of kids) {
149
+ const kidDict = resolveDict(kid);
150
+ if (kidDict !== void 0) walkPageTree(kidDict, merged, visited, result);
151
+ }
152
+ }
153
+ return {
154
+ trailer: xref.trailer,
155
+ resolve,
156
+ resolveDict,
157
+ pages
158
+ };
159
+ }
160
+ //#endregion
161
+ export { openPdfDocument };
@@ -0,0 +1,5 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_afm_widths = require("./afm-widths-BoeTOK2r.cjs");
3
+ exports.WINANSI_GLYPH_NAMES = require_afm_widths.WINANSI_GLYPH_NAMES;
4
+ exports.glyphNameToUnicode = require_afm_widths.glyphNameToUnicode;
5
+ exports.winAnsiGlyphName = require_afm_widths.winAnsiGlyphName;
@@ -0,0 +1,6 @@
1
+ //#region src/encoding.d.ts
2
+ declare const WINANSI_GLYPH_NAMES: readonly string[];
3
+ declare function winAnsiGlyphName(code: number): string | undefined;
4
+ declare function glyphNameToUnicode(name: string): number | undefined;
5
+ //#endregion
6
+ export { WINANSI_GLYPH_NAMES, glyphNameToUnicode, winAnsiGlyphName };
@@ -0,0 +1,6 @@
1
+ //#region src/encoding.d.ts
2
+ declare const WINANSI_GLYPH_NAMES: readonly string[];
3
+ declare function winAnsiGlyphName(code: number): string | undefined;
4
+ declare function glyphNameToUnicode(name: string): number | undefined;
5
+ //#endregion
6
+ export { WINANSI_GLYPH_NAMES, glyphNameToUnicode, winAnsiGlyphName };
@@ -0,0 +1,2 @@
1
+ import { a as winAnsiGlyphName, i as glyphNameToUnicode, r as WINANSI_GLYPH_NAMES } from "./afm-widths-Dxucrg7D.js";
2
+ export { WINANSI_GLYPH_NAMES, glyphNameToUnicode, winAnsiGlyphName };
@@ -0,0 +1,223 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_bytes_reader = require("./bytes/reader.cjs");
3
+ const require_bytes_flate = require("./bytes/flate.cjs");
4
+ const require_objects = require("./objects.cjs");
5
+ const require_predictors = require("./predictors.cjs");
6
+ //#region src/filters.ts
7
+ function decodeStream(raw, dict, sink) {
8
+ const filters = filterNames(dict);
9
+ const parms = decodeParmsList(dict, filters.length);
10
+ let bytes = raw;
11
+ for (let i = 0; i < filters.length; i++) {
12
+ const filter = filters[i];
13
+ const parm = parms[i];
14
+ if (filter === "FlateDecode" || filter === "Fl") bytes = applyPredictorIfPresent(require_bytes_flate.inflateTolerant(bytes).bytes, parm, sink);
15
+ else if (filter === "LZWDecode" || filter === "LZW") {
16
+ const earlyChange = (require_objects.asNumber(parm ? require_objects.dictGet(parm, "EarlyChange") : void 0) ?? 1) !== 0;
17
+ bytes = applyPredictorIfPresent(lzwDecode(bytes, earlyChange, sink), parm, sink);
18
+ } else if (filter === "ASCII85Decode" || filter === "A85") bytes = ascii85Decode(bytes);
19
+ else if (filter === "ASCIIHexDecode" || filter === "AHx") bytes = asciiHexDecode(bytes);
20
+ else if (filter === "RunLengthDecode" || filter === "RL") bytes = runLengthDecode(bytes);
21
+ else if (filter === "DCTDecode" || filter === "DCT") return {
22
+ bytes,
23
+ remainingFilter: "DCTDecode"
24
+ };
25
+ else {
26
+ sink({
27
+ code: "pdf/unsupported-filter",
28
+ severity: "warning",
29
+ message: `unsupported stream filter "${filter}"; leaving remaining bytes undecoded`
30
+ });
31
+ return {
32
+ bytes,
33
+ remainingFilter: filter
34
+ };
35
+ }
36
+ }
37
+ return { bytes };
38
+ }
39
+ function applyPredictorIfPresent(data, parm, sink) {
40
+ return require_predictors.applyPredictor(data, require_predictors.readPredictorParams(parm), sink);
41
+ }
42
+ function filterNames(dict) {
43
+ const filterObj = require_objects.dictGet(dict, "Filter") ?? require_objects.dictGet(dict, "F");
44
+ if (filterObj === void 0) return [];
45
+ const single = require_objects.asName(filterObj);
46
+ if (single !== void 0) return [single];
47
+ const arr = require_objects.asArray(filterObj);
48
+ if (arr === void 0) return [];
49
+ const names = [];
50
+ for (const item of arr) {
51
+ const name = require_objects.asName(item);
52
+ if (name !== void 0) names.push(name);
53
+ }
54
+ return names;
55
+ }
56
+ function decodeParmsList(dict, count) {
57
+ const parmsObj = require_objects.dictGet(dict, "DecodeParms") ?? require_objects.dictGet(dict, "DP");
58
+ const empty = () => Array.from({ length: count }, () => void 0);
59
+ if (parmsObj === void 0) return empty();
60
+ const single = require_objects.asDict(parmsObj);
61
+ if (single !== void 0) {
62
+ const list = empty();
63
+ list[0] = single;
64
+ return list;
65
+ }
66
+ const arr = require_objects.asArray(parmsObj);
67
+ if (arr === void 0) return empty();
68
+ return Array.from({ length: count }, (_, i) => require_objects.asDict(arr[i]));
69
+ }
70
+ const LZW_CLEAR_TABLE = 256;
71
+ const LZW_EOD = 257;
72
+ const LZW_INITIAL_CODE_WIDTH = 9;
73
+ const LZW_FIRST_NEW_CODE = 258;
74
+ function initialLzwDictionary() {
75
+ return Array.from({ length: 256 }, (_, i) => new Uint8Array([i]));
76
+ }
77
+ function concatTwo(a, b) {
78
+ const out = new Uint8Array(a.length + b.length);
79
+ out.set(a, 0);
80
+ out.set(b, a.length);
81
+ return out;
82
+ }
83
+ function lzwDecode(data, earlyChange, sink) {
84
+ const out = [];
85
+ let dict = initialLzwDictionary();
86
+ let nextCode = LZW_FIRST_NEW_CODE;
87
+ let codeWidth = LZW_INITIAL_CODE_WIDTH;
88
+ let prevEntry;
89
+ const bias = earlyChange ? 1 : 0;
90
+ let bitBuffer = 0;
91
+ let bitCount = 0;
92
+ let pos = 0;
93
+ const readCode = () => {
94
+ while (bitCount < codeWidth) {
95
+ if (pos >= data.length) return;
96
+ bitBuffer = bitBuffer << 8 | data[pos];
97
+ pos++;
98
+ bitCount += 8;
99
+ }
100
+ const value = bitBuffer >>> bitCount - codeWidth & (1 << codeWidth) - 1;
101
+ bitCount -= codeWidth;
102
+ return value;
103
+ };
104
+ for (;;) {
105
+ const code = readCode();
106
+ if (code === void 0 || code === LZW_EOD) break;
107
+ if (code === LZW_CLEAR_TABLE) {
108
+ dict = initialLzwDictionary();
109
+ nextCode = LZW_FIRST_NEW_CODE;
110
+ codeWidth = LZW_INITIAL_CODE_WIDTH;
111
+ prevEntry = void 0;
112
+ continue;
113
+ }
114
+ let entry;
115
+ const existing = dict[code];
116
+ if (existing !== void 0) entry = existing;
117
+ else if (code === nextCode && prevEntry !== void 0) entry = concatTwo(prevEntry, new Uint8Array([prevEntry[0] ?? 0]));
118
+ else {
119
+ sink({
120
+ code: "pdf/lzw-corrupt",
121
+ severity: "warning",
122
+ message: `LZW stream referenced code ${String(code)} with no valid dictionary entry; stopping decode with what was recovered so far`
123
+ });
124
+ break;
125
+ }
126
+ for (const byte of entry) out.push(byte);
127
+ if (prevEntry !== void 0) {
128
+ dict[nextCode] = concatTwo(prevEntry, new Uint8Array([entry[0] ?? 0]));
129
+ nextCode++;
130
+ if (nextCode + bias === 2 ** 9) codeWidth = 10;
131
+ else if (nextCode + bias === 2 ** 10) codeWidth = 11;
132
+ else if (nextCode + bias === 2 ** 11) codeWidth = 12;
133
+ }
134
+ prevEntry = entry;
135
+ }
136
+ return Uint8Array.from(out);
137
+ }
138
+ const ASCII85_ZERO_GROUP_MARKER = 122;
139
+ const ASCII85_END_MARKER = 126;
140
+ const ASCII85_MIN_DIGIT = 33;
141
+ const ASCII85_MAX_DIGIT = 117;
142
+ const ASCII85_MAX_DIGIT_VALUE = 84;
143
+ function pushAscii85Group(out, digits, byteCount) {
144
+ let value = 0;
145
+ for (const digit of digits) value = value * 85 + digit;
146
+ const bytes = [
147
+ value >>> 24 & 255,
148
+ value >>> 16 & 255,
149
+ value >>> 8 & 255,
150
+ value & 255
151
+ ];
152
+ for (let i = 0; i < byteCount; i++) out.push(bytes[i]);
153
+ }
154
+ function ascii85Decode(data) {
155
+ const out = [];
156
+ let tuple = [];
157
+ let i = 0;
158
+ if (data.length >= 2 && data[0] === 60 && data[1] === 126) i = 2;
159
+ for (; i < data.length; i++) {
160
+ const byte = data[i];
161
+ if (byte === ASCII85_END_MARKER) break;
162
+ if (require_bytes_reader.isAsciiWhitespace(byte)) continue;
163
+ if (byte === ASCII85_ZERO_GROUP_MARKER && tuple.length === 0) {
164
+ out.push(0, 0, 0, 0);
165
+ continue;
166
+ }
167
+ if (byte < ASCII85_MIN_DIGIT || byte > ASCII85_MAX_DIGIT) continue;
168
+ tuple.push(byte - ASCII85_MIN_DIGIT);
169
+ if (tuple.length === 5) {
170
+ pushAscii85Group(out, tuple, 4);
171
+ tuple = [];
172
+ }
173
+ }
174
+ if (tuple.length > 1) {
175
+ const padded = tuple.slice();
176
+ while (padded.length < 5) padded.push(ASCII85_MAX_DIGIT_VALUE);
177
+ pushAscii85Group(out, padded, tuple.length - 1);
178
+ }
179
+ return Uint8Array.from(out);
180
+ }
181
+ function hexDigitValue(byte) {
182
+ if (byte >= 48 && byte <= 57) return byte - 48;
183
+ if (byte >= 65 && byte <= 70) return byte - 65 + 10;
184
+ if (byte >= 97 && byte <= 102) return byte - 97 + 10;
185
+ }
186
+ function asciiHexDecode(data) {
187
+ const digits = [];
188
+ for (const byte of data) {
189
+ if (byte === 62) break;
190
+ const value = hexDigitValue(byte);
191
+ if (value !== void 0) digits.push(value);
192
+ }
193
+ if (digits.length % 2 === 1) digits.push(0);
194
+ const out = new Uint8Array(digits.length / 2);
195
+ for (let i = 0; i < out.length; i++) out[i] = digits[i * 2] << 4 | digits[i * 2 + 1];
196
+ return out;
197
+ }
198
+ const RUN_LENGTH_EOD = 128;
199
+ function runLengthDecode(data) {
200
+ const out = [];
201
+ let i = 0;
202
+ while (i < data.length) {
203
+ const length = data[i];
204
+ i++;
205
+ if (length === RUN_LENGTH_EOD) break;
206
+ if (length < RUN_LENGTH_EOD) {
207
+ const count = length + 1;
208
+ for (let j = 0; j < count && i < data.length; j++, i++) out.push(data[i]);
209
+ } else {
210
+ const count = 257 - length;
211
+ const byte = data[i] ?? 0;
212
+ i++;
213
+ for (let j = 0; j < count; j++) out.push(byte);
214
+ }
215
+ }
216
+ return Uint8Array.from(out);
217
+ }
218
+ //#endregion
219
+ exports.ascii85Decode = ascii85Decode;
220
+ exports.asciiHexDecode = asciiHexDecode;
221
+ exports.decodeStream = decodeStream;
222
+ exports.lzwDecode = lzwDecode;
223
+ exports.runLengthDecode = runLengthDecode;
@@ -0,0 +1,14 @@
1
+ import { PdfDiagnosticSink } from "./diagnostics.cjs";
2
+ import { PdfDict } from "./objects.cjs";
3
+ //#region src/filters.d.ts
4
+ interface DecodedStream {
5
+ readonly bytes: Uint8Array<ArrayBuffer>;
6
+ readonly remainingFilter?: string;
7
+ }
8
+ declare function decodeStream(raw: Uint8Array<ArrayBuffer>, dict: PdfDict, sink: PdfDiagnosticSink): DecodedStream;
9
+ declare function lzwDecode(data: Uint8Array<ArrayBuffer>, earlyChange: boolean, sink: PdfDiagnosticSink): Uint8Array<ArrayBuffer>;
10
+ declare function ascii85Decode(data: Uint8Array<ArrayBuffer>): Uint8Array<ArrayBuffer>;
11
+ declare function asciiHexDecode(data: Uint8Array<ArrayBuffer>): Uint8Array<ArrayBuffer>;
12
+ declare function runLengthDecode(data: Uint8Array<ArrayBuffer>): Uint8Array<ArrayBuffer>;
13
+ //#endregion
14
+ export { DecodedStream, ascii85Decode, asciiHexDecode, decodeStream, lzwDecode, runLengthDecode };
@@ -0,0 +1,14 @@
1
+ import { PdfDiagnosticSink } from "./diagnostics.js";
2
+ import { PdfDict } from "./objects.js";
3
+ //#region src/filters.d.ts
4
+ interface DecodedStream {
5
+ readonly bytes: Uint8Array<ArrayBuffer>;
6
+ readonly remainingFilter?: string;
7
+ }
8
+ declare function decodeStream(raw: Uint8Array<ArrayBuffer>, dict: PdfDict, sink: PdfDiagnosticSink): DecodedStream;
9
+ declare function lzwDecode(data: Uint8Array<ArrayBuffer>, earlyChange: boolean, sink: PdfDiagnosticSink): Uint8Array<ArrayBuffer>;
10
+ declare function ascii85Decode(data: Uint8Array<ArrayBuffer>): Uint8Array<ArrayBuffer>;
11
+ declare function asciiHexDecode(data: Uint8Array<ArrayBuffer>): Uint8Array<ArrayBuffer>;
12
+ declare function runLengthDecode(data: Uint8Array<ArrayBuffer>): Uint8Array<ArrayBuffer>;
13
+ //#endregion
14
+ export { DecodedStream, ascii85Decode, asciiHexDecode, decodeStream, lzwDecode, runLengthDecode };
@@ -0,0 +1,218 @@
1
+ import { isAsciiWhitespace } from "./bytes/reader.js";
2
+ import { inflateTolerant } from "./bytes/flate.js";
3
+ import { asArray, asDict, asName, asNumber, dictGet } from "./objects.js";
4
+ import { applyPredictor, readPredictorParams } from "./predictors.js";
5
+ //#region src/filters.ts
6
+ function decodeStream(raw, dict, sink) {
7
+ const filters = filterNames(dict);
8
+ const parms = decodeParmsList(dict, filters.length);
9
+ let bytes = raw;
10
+ for (let i = 0; i < filters.length; i++) {
11
+ const filter = filters[i];
12
+ const parm = parms[i];
13
+ if (filter === "FlateDecode" || filter === "Fl") bytes = applyPredictorIfPresent(inflateTolerant(bytes).bytes, parm, sink);
14
+ else if (filter === "LZWDecode" || filter === "LZW") {
15
+ const earlyChange = (asNumber(parm ? dictGet(parm, "EarlyChange") : void 0) ?? 1) !== 0;
16
+ bytes = applyPredictorIfPresent(lzwDecode(bytes, earlyChange, sink), parm, sink);
17
+ } else if (filter === "ASCII85Decode" || filter === "A85") bytes = ascii85Decode(bytes);
18
+ else if (filter === "ASCIIHexDecode" || filter === "AHx") bytes = asciiHexDecode(bytes);
19
+ else if (filter === "RunLengthDecode" || filter === "RL") bytes = runLengthDecode(bytes);
20
+ else if (filter === "DCTDecode" || filter === "DCT") return {
21
+ bytes,
22
+ remainingFilter: "DCTDecode"
23
+ };
24
+ else {
25
+ sink({
26
+ code: "pdf/unsupported-filter",
27
+ severity: "warning",
28
+ message: `unsupported stream filter "${filter}"; leaving remaining bytes undecoded`
29
+ });
30
+ return {
31
+ bytes,
32
+ remainingFilter: filter
33
+ };
34
+ }
35
+ }
36
+ return { bytes };
37
+ }
38
+ function applyPredictorIfPresent(data, parm, sink) {
39
+ return applyPredictor(data, readPredictorParams(parm), sink);
40
+ }
41
+ function filterNames(dict) {
42
+ const filterObj = dictGet(dict, "Filter") ?? dictGet(dict, "F");
43
+ if (filterObj === void 0) return [];
44
+ const single = asName(filterObj);
45
+ if (single !== void 0) return [single];
46
+ const arr = asArray(filterObj);
47
+ if (arr === void 0) return [];
48
+ const names = [];
49
+ for (const item of arr) {
50
+ const name = asName(item);
51
+ if (name !== void 0) names.push(name);
52
+ }
53
+ return names;
54
+ }
55
+ function decodeParmsList(dict, count) {
56
+ const parmsObj = dictGet(dict, "DecodeParms") ?? dictGet(dict, "DP");
57
+ const empty = () => Array.from({ length: count }, () => void 0);
58
+ if (parmsObj === void 0) return empty();
59
+ const single = asDict(parmsObj);
60
+ if (single !== void 0) {
61
+ const list = empty();
62
+ list[0] = single;
63
+ return list;
64
+ }
65
+ const arr = asArray(parmsObj);
66
+ if (arr === void 0) return empty();
67
+ return Array.from({ length: count }, (_, i) => asDict(arr[i]));
68
+ }
69
+ const LZW_CLEAR_TABLE = 256;
70
+ const LZW_EOD = 257;
71
+ const LZW_INITIAL_CODE_WIDTH = 9;
72
+ const LZW_FIRST_NEW_CODE = 258;
73
+ function initialLzwDictionary() {
74
+ return Array.from({ length: 256 }, (_, i) => new Uint8Array([i]));
75
+ }
76
+ function concatTwo(a, b) {
77
+ const out = new Uint8Array(a.length + b.length);
78
+ out.set(a, 0);
79
+ out.set(b, a.length);
80
+ return out;
81
+ }
82
+ function lzwDecode(data, earlyChange, sink) {
83
+ const out = [];
84
+ let dict = initialLzwDictionary();
85
+ let nextCode = LZW_FIRST_NEW_CODE;
86
+ let codeWidth = LZW_INITIAL_CODE_WIDTH;
87
+ let prevEntry;
88
+ const bias = earlyChange ? 1 : 0;
89
+ let bitBuffer = 0;
90
+ let bitCount = 0;
91
+ let pos = 0;
92
+ const readCode = () => {
93
+ while (bitCount < codeWidth) {
94
+ if (pos >= data.length) return;
95
+ bitBuffer = bitBuffer << 8 | data[pos];
96
+ pos++;
97
+ bitCount += 8;
98
+ }
99
+ const value = bitBuffer >>> bitCount - codeWidth & (1 << codeWidth) - 1;
100
+ bitCount -= codeWidth;
101
+ return value;
102
+ };
103
+ for (;;) {
104
+ const code = readCode();
105
+ if (code === void 0 || code === LZW_EOD) break;
106
+ if (code === LZW_CLEAR_TABLE) {
107
+ dict = initialLzwDictionary();
108
+ nextCode = LZW_FIRST_NEW_CODE;
109
+ codeWidth = LZW_INITIAL_CODE_WIDTH;
110
+ prevEntry = void 0;
111
+ continue;
112
+ }
113
+ let entry;
114
+ const existing = dict[code];
115
+ if (existing !== void 0) entry = existing;
116
+ else if (code === nextCode && prevEntry !== void 0) entry = concatTwo(prevEntry, new Uint8Array([prevEntry[0] ?? 0]));
117
+ else {
118
+ sink({
119
+ code: "pdf/lzw-corrupt",
120
+ severity: "warning",
121
+ message: `LZW stream referenced code ${String(code)} with no valid dictionary entry; stopping decode with what was recovered so far`
122
+ });
123
+ break;
124
+ }
125
+ for (const byte of entry) out.push(byte);
126
+ if (prevEntry !== void 0) {
127
+ dict[nextCode] = concatTwo(prevEntry, new Uint8Array([entry[0] ?? 0]));
128
+ nextCode++;
129
+ if (nextCode + bias === 2 ** 9) codeWidth = 10;
130
+ else if (nextCode + bias === 2 ** 10) codeWidth = 11;
131
+ else if (nextCode + bias === 2 ** 11) codeWidth = 12;
132
+ }
133
+ prevEntry = entry;
134
+ }
135
+ return Uint8Array.from(out);
136
+ }
137
+ const ASCII85_ZERO_GROUP_MARKER = 122;
138
+ const ASCII85_END_MARKER = 126;
139
+ const ASCII85_MIN_DIGIT = 33;
140
+ const ASCII85_MAX_DIGIT = 117;
141
+ const ASCII85_MAX_DIGIT_VALUE = 84;
142
+ function pushAscii85Group(out, digits, byteCount) {
143
+ let value = 0;
144
+ for (const digit of digits) value = value * 85 + digit;
145
+ const bytes = [
146
+ value >>> 24 & 255,
147
+ value >>> 16 & 255,
148
+ value >>> 8 & 255,
149
+ value & 255
150
+ ];
151
+ for (let i = 0; i < byteCount; i++) out.push(bytes[i]);
152
+ }
153
+ function ascii85Decode(data) {
154
+ const out = [];
155
+ let tuple = [];
156
+ let i = 0;
157
+ if (data.length >= 2 && data[0] === 60 && data[1] === 126) i = 2;
158
+ for (; i < data.length; i++) {
159
+ const byte = data[i];
160
+ if (byte === ASCII85_END_MARKER) break;
161
+ if (isAsciiWhitespace(byte)) continue;
162
+ if (byte === ASCII85_ZERO_GROUP_MARKER && tuple.length === 0) {
163
+ out.push(0, 0, 0, 0);
164
+ continue;
165
+ }
166
+ if (byte < ASCII85_MIN_DIGIT || byte > ASCII85_MAX_DIGIT) continue;
167
+ tuple.push(byte - ASCII85_MIN_DIGIT);
168
+ if (tuple.length === 5) {
169
+ pushAscii85Group(out, tuple, 4);
170
+ tuple = [];
171
+ }
172
+ }
173
+ if (tuple.length > 1) {
174
+ const padded = tuple.slice();
175
+ while (padded.length < 5) padded.push(ASCII85_MAX_DIGIT_VALUE);
176
+ pushAscii85Group(out, padded, tuple.length - 1);
177
+ }
178
+ return Uint8Array.from(out);
179
+ }
180
+ function hexDigitValue(byte) {
181
+ if (byte >= 48 && byte <= 57) return byte - 48;
182
+ if (byte >= 65 && byte <= 70) return byte - 65 + 10;
183
+ if (byte >= 97 && byte <= 102) return byte - 97 + 10;
184
+ }
185
+ function asciiHexDecode(data) {
186
+ const digits = [];
187
+ for (const byte of data) {
188
+ if (byte === 62) break;
189
+ const value = hexDigitValue(byte);
190
+ if (value !== void 0) digits.push(value);
191
+ }
192
+ if (digits.length % 2 === 1) digits.push(0);
193
+ const out = new Uint8Array(digits.length / 2);
194
+ for (let i = 0; i < out.length; i++) out[i] = digits[i * 2] << 4 | digits[i * 2 + 1];
195
+ return out;
196
+ }
197
+ const RUN_LENGTH_EOD = 128;
198
+ function runLengthDecode(data) {
199
+ const out = [];
200
+ let i = 0;
201
+ while (i < data.length) {
202
+ const length = data[i];
203
+ i++;
204
+ if (length === RUN_LENGTH_EOD) break;
205
+ if (length < RUN_LENGTH_EOD) {
206
+ const count = length + 1;
207
+ for (let j = 0; j < count && i < data.length; j++, i++) out.push(data[i]);
208
+ } else {
209
+ const count = 257 - length;
210
+ const byte = data[i] ?? 0;
211
+ i++;
212
+ for (let j = 0; j < count; j++) out.push(byte);
213
+ }
214
+ }
215
+ return Uint8Array.from(out);
216
+ }
217
+ //#endregion
218
+ export { ascii85Decode, asciiHexDecode, decodeStream, lzwDecode, runLengthDecode };