@vaadin-component-factory/vcf-pdf-viewer 0.9.0 → 0.9.4

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 (174) hide show
  1. package/README.md +1 -1
  2. package/package.json +33 -18
  3. package/{src/display → pdfjs/dist}/display_utils.js +344 -139
  4. package/{src/display → pdfjs/dist}/fetch_stream.js +115 -97
  5. package/pdfjs/dist/get.js +1857 -0
  6. package/pdfjs/dist/index.js +767 -0
  7. package/pdfjs/dist/l10n_utils.js +140 -0
  8. package/{src/shared → pdfjs/dist}/message_handler.js +243 -259
  9. package/{src/display → pdfjs/dist}/network.js +149 -87
  10. package/{src/display/content_disposition.js → pdfjs/dist/network_utils.js} +167 -55
  11. package/{src/display → pdfjs/dist}/node_stream.js +133 -98
  12. package/pdfjs/dist/pdf.js +12778 -0
  13. package/pdfjs/dist/pdf_link_service.js +638 -0
  14. package/pdfjs/dist/pdf_rendering_queue.js +199 -0
  15. package/pdfjs/dist/pdf_thumbnail_viewer.js +819 -0
  16. package/pdfjs/dist/pdf_viewer.js +3598 -0
  17. package/pdfjs/dist/typeof.js +100 -0
  18. package/pdfjs/dist/ui_utils.js +1033 -0
  19. package/{src/shared → pdfjs/dist}/util.js +301 -287
  20. package/pdfjs/dist/worker.js +62813 -0
  21. package/src/vcf-pdf-viewer.js +77 -27
  22. package/theme/lumo/vcf-pdf-viewer-styles.js +1 -1
  23. package/theme/material/vcf-pdf-viewer.js +2 -2
  24. package/src/core/.eslintrc +0 -13
  25. package/src/core/annotation.js +0 -2948
  26. package/src/core/arithmetic_decoder.js +0 -182
  27. package/src/core/ascii_85_stream.js +0 -98
  28. package/src/core/ascii_hex_stream.js +0 -79
  29. package/src/core/base_stream.js +0 -110
  30. package/src/core/bidi.js +0 -438
  31. package/src/core/calibri_factors.js +0 -308
  32. package/src/core/catalog.js +0 -1459
  33. package/src/core/ccitt.js +0 -1062
  34. package/src/core/ccitt_stream.js +0 -60
  35. package/src/core/cff_font.js +0 -116
  36. package/src/core/cff_parser.js +0 -1949
  37. package/src/core/charsets.js +0 -119
  38. package/src/core/chunked_stream.js +0 -557
  39. package/src/core/cmap.js +0 -1039
  40. package/src/core/colorspace.js +0 -1533
  41. package/src/core/core_utils.js +0 -464
  42. package/src/core/crypto.js +0 -1900
  43. package/src/core/decode_stream.js +0 -170
  44. package/src/core/decrypt_stream.js +0 -59
  45. package/src/core/default_appearance.js +0 -99
  46. package/src/core/document.js +0 -1456
  47. package/src/core/encodings.js +0 -301
  48. package/src/core/evaluator.js +0 -4601
  49. package/src/core/file_spec.js +0 -108
  50. package/src/core/flate_stream.js +0 -402
  51. package/src/core/font_renderer.js +0 -882
  52. package/src/core/fonts.js +0 -3260
  53. package/src/core/fonts_utils.js +0 -221
  54. package/src/core/function.js +0 -1257
  55. package/src/core/glyf.js +0 -706
  56. package/src/core/glyphlist.js +0 -4558
  57. package/src/core/helvetica_factors.js +0 -353
  58. package/src/core/image.js +0 -802
  59. package/src/core/image_utils.js +0 -291
  60. package/src/core/jbig2.js +0 -2572
  61. package/src/core/jbig2_stream.js +0 -73
  62. package/src/core/jpeg_stream.js +0 -105
  63. package/src/core/jpg.js +0 -1416
  64. package/src/core/jpx.js +0 -2343
  65. package/src/core/jpx_stream.js +0 -87
  66. package/src/core/liberationsans_widths.js +0 -221
  67. package/src/core/lzw_stream.js +0 -150
  68. package/src/core/metadata_parser.js +0 -146
  69. package/src/core/metrics.js +0 -2970
  70. package/src/core/murmurhash3.js +0 -139
  71. package/src/core/myriadpro_factors.js +0 -290
  72. package/src/core/name_number_tree.js +0 -153
  73. package/src/core/object_loader.js +0 -149
  74. package/src/core/opentype_file_builder.js +0 -154
  75. package/src/core/operator_list.js +0 -734
  76. package/src/core/parser.js +0 -1416
  77. package/src/core/pattern.js +0 -985
  78. package/src/core/pdf_manager.js +0 -217
  79. package/src/core/predictor_stream.js +0 -238
  80. package/src/core/primitives.js +0 -402
  81. package/src/core/ps_parser.js +0 -272
  82. package/src/core/run_length_stream.js +0 -61
  83. package/src/core/segoeui_factors.js +0 -308
  84. package/src/core/standard_fonts.js +0 -817
  85. package/src/core/stream.js +0 -103
  86. package/src/core/struct_tree.js +0 -335
  87. package/src/core/to_unicode_map.js +0 -103
  88. package/src/core/type1_font.js +0 -421
  89. package/src/core/type1_parser.js +0 -776
  90. package/src/core/unicode.js +0 -1649
  91. package/src/core/worker.js +0 -848
  92. package/src/core/worker_stream.js +0 -135
  93. package/src/core/writer.js +0 -278
  94. package/src/core/xfa/bind.js +0 -652
  95. package/src/core/xfa/builder.js +0 -207
  96. package/src/core/xfa/config.js +0 -1926
  97. package/src/core/xfa/connection_set.js +0 -202
  98. package/src/core/xfa/data.js +0 -82
  99. package/src/core/xfa/datasets.js +0 -76
  100. package/src/core/xfa/factory.js +0 -111
  101. package/src/core/xfa/fonts.js +0 -181
  102. package/src/core/xfa/formcalc_lexer.js +0 -385
  103. package/src/core/xfa/formcalc_parser.js +0 -1340
  104. package/src/core/xfa/html_utils.js +0 -639
  105. package/src/core/xfa/layout.js +0 -383
  106. package/src/core/xfa/locale_set.js +0 -345
  107. package/src/core/xfa/namespaces.js +0 -81
  108. package/src/core/xfa/parser.js +0 -184
  109. package/src/core/xfa/setup.js +0 -38
  110. package/src/core/xfa/signature.js +0 -40
  111. package/src/core/xfa/som.js +0 -338
  112. package/src/core/xfa/stylesheet.js +0 -40
  113. package/src/core/xfa/template.js +0 -6260
  114. package/src/core/xfa/text.js +0 -290
  115. package/src/core/xfa/unknown.js +0 -29
  116. package/src/core/xfa/utils.js +0 -217
  117. package/src/core/xfa/xdp.js +0 -59
  118. package/src/core/xfa/xfa_object.js +0 -1130
  119. package/src/core/xfa/xhtml.js +0 -543
  120. package/src/core/xfa_fonts.js +0 -208
  121. package/src/core/xml_parser.js +0 -507
  122. package/src/core/xref.js +0 -899
  123. package/src/display/annotation_layer.js +0 -2107
  124. package/src/display/annotation_storage.js +0 -113
  125. package/src/display/api.js +0 -3292
  126. package/src/display/base_factory.js +0 -180
  127. package/src/display/canvas.js +0 -2828
  128. package/src/display/font_loader.js +0 -484
  129. package/src/display/metadata.js +0 -41
  130. package/src/display/network_utils.js +0 -100
  131. package/src/display/node_utils.js +0 -83
  132. package/src/display/optional_content_config.js +0 -189
  133. package/src/display/pattern_helper.js +0 -659
  134. package/src/display/svg.js +0 -1709
  135. package/src/display/text_layer.js +0 -847
  136. package/src/display/transport_stream.js +0 -303
  137. package/src/display/worker_options.js +0 -40
  138. package/src/display/xfa_layer.js +0 -204
  139. package/src/doc_helper.js +0 -25
  140. package/src/images/logo.svg +0 -41
  141. package/src/interfaces.js +0 -169
  142. package/src/license_header.js +0 -14
  143. package/src/license_header_libre.js +0 -21
  144. package/src/pdf.image_decoders.js +0 -46
  145. package/src/pdf.js +0 -146
  146. package/src/pdf.sandbox.external.js +0 -181
  147. package/src/pdf.sandbox.js +0 -151
  148. package/src/pdf.scripting.js +0 -25
  149. package/src/pdf.worker.entry.js +0 -19
  150. package/src/pdf.worker.js +0 -23
  151. package/src/scripting_api/aform.js +0 -608
  152. package/src/scripting_api/app.js +0 -621
  153. package/src/scripting_api/color.js +0 -129
  154. package/src/scripting_api/common.js +0 -58
  155. package/src/scripting_api/console.js +0 -38
  156. package/src/scripting_api/constants.js +0 -208
  157. package/src/scripting_api/doc.js +0 -1195
  158. package/src/scripting_api/error.js +0 -23
  159. package/src/scripting_api/event.js +0 -232
  160. package/src/scripting_api/field.js +0 -620
  161. package/src/scripting_api/fullscreen.js +0 -145
  162. package/src/scripting_api/initialization.js +0 -223
  163. package/src/scripting_api/pdf_object.js +0 -24
  164. package/src/scripting_api/print_params.js +0 -146
  165. package/src/scripting_api/proxy.js +0 -139
  166. package/src/scripting_api/thermometer.js +0 -69
  167. package/src/scripting_api/util.js +0 -581
  168. package/src/shared/.eslintrc +0 -13
  169. package/src/shared/cffStandardStrings.js +0 -311
  170. package/src/shared/compatibility.js +0 -114
  171. package/src/shared/fonts_utils.js +0 -429
  172. package/src/shared/is_node.js +0 -27
  173. package/src/shared/scripting_utils.js +0 -85
  174. package/src/worker_loader.js +0 -32
@@ -1,1456 +0,0 @@
1
- /* Copyright 2012 Mozilla Foundation
2
- *
3
- * Licensed under the Apache License, Version 2.0 (the "License");
4
- * you may not use this file except in compliance with the License.
5
- * You may obtain a copy of the License at
6
- *
7
- * http://www.apache.org/licenses/LICENSE-2.0
8
- *
9
- * Unless required by applicable law or agreed to in writing, software
10
- * distributed under the License is distributed on an "AS IS" BASIS,
11
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- * See the License for the specific language governing permissions and
13
- * limitations under the License.
14
- */
15
-
16
- import {
17
- assert,
18
- FormatError,
19
- info,
20
- InvalidPDFException,
21
- isArrayBuffer,
22
- isArrayEqual,
23
- isBool,
24
- isNum,
25
- isString,
26
- OPS,
27
- PageActionEventType,
28
- shadow,
29
- stringToBytes,
30
- stringToPDFString,
31
- stringToUTF8String,
32
- unreachable,
33
- Util,
34
- warn,
35
- } from "../shared/util.js";
36
- import {
37
- clearPrimitiveCaches,
38
- Dict,
39
- isDict,
40
- isName,
41
- isRef,
42
- isStream,
43
- Name,
44
- Ref,
45
- } from "./primitives.js";
46
- import {
47
- collectActions,
48
- getInheritableProperty,
49
- isWhiteSpace,
50
- MissingDataException,
51
- validateCSSFont,
52
- XRefEntryException,
53
- XRefParseException,
54
- } from "./core_utils.js";
55
- import { NullStream, Stream } from "./stream.js";
56
- import { AnnotationFactory } from "./annotation.js";
57
- import { BaseStream } from "./base_stream.js";
58
- import { calculateMD5 } from "./crypto.js";
59
- import { Catalog } from "./catalog.js";
60
- import { getXfaFontWidths } from "./xfa_fonts.js";
61
- import { Linearization } from "./parser.js";
62
- import { ObjectLoader } from "./object_loader.js";
63
- import { OperatorList } from "./operator_list.js";
64
- import { PartialEvaluator } from "./evaluator.js";
65
- import { StreamsSequenceStream } from "./decode_stream.js";
66
- import { StructTreePage } from "./struct_tree.js";
67
- import { XFAFactory } from "./xfa/factory.js";
68
- import { XRef } from "./xref.js";
69
-
70
- const DEFAULT_USER_UNIT = 1.0;
71
- const LETTER_SIZE_MEDIABOX = [0, 0, 612, 792];
72
-
73
- class Page {
74
- constructor({
75
- pdfManager,
76
- xref,
77
- pageIndex,
78
- pageDict,
79
- ref,
80
- globalIdFactory,
81
- fontCache,
82
- builtInCMapCache,
83
- standardFontDataCache,
84
- globalImageCache,
85
- nonBlendModesSet,
86
- xfaFactory,
87
- }) {
88
- this.pdfManager = pdfManager;
89
- this.pageIndex = pageIndex;
90
- this.pageDict = pageDict;
91
- this.xref = xref;
92
- this.ref = ref;
93
- this.fontCache = fontCache;
94
- this.builtInCMapCache = builtInCMapCache;
95
- this.standardFontDataCache = standardFontDataCache;
96
- this.globalImageCache = globalImageCache;
97
- this.nonBlendModesSet = nonBlendModesSet;
98
- this.evaluatorOptions = pdfManager.evaluatorOptions;
99
- this.resourcesPromise = null;
100
- this.xfaFactory = xfaFactory;
101
-
102
- const idCounters = {
103
- obj: 0,
104
- };
105
- this._localIdFactory = class extends globalIdFactory {
106
- static createObjId() {
107
- return `p${pageIndex}_${++idCounters.obj}`;
108
- }
109
-
110
- static getPageObjId() {
111
- return `page${ref.toString()}`;
112
- }
113
- };
114
- }
115
-
116
- /**
117
- * @private
118
- */
119
- _getInheritableProperty(key, getArray = false) {
120
- const value = getInheritableProperty({
121
- dict: this.pageDict,
122
- key,
123
- getArray,
124
- stopWhenFound: false,
125
- });
126
- if (!Array.isArray(value)) {
127
- return value;
128
- }
129
- if (value.length === 1 || !isDict(value[0])) {
130
- return value[0];
131
- }
132
- return Dict.merge({ xref: this.xref, dictArray: value });
133
- }
134
-
135
- get content() {
136
- return this.pageDict.getArray("Contents");
137
- }
138
-
139
- get resources() {
140
- // For robustness: The spec states that a \Resources entry has to be
141
- // present, but can be empty. Some documents still omit it; in this case
142
- // we return an empty dictionary.
143
- return shadow(
144
- this,
145
- "resources",
146
- this._getInheritableProperty("Resources") || Dict.empty
147
- );
148
- }
149
-
150
- _getBoundingBox(name) {
151
- if (this.xfaData) {
152
- return this.xfaData.bbox;
153
- }
154
-
155
- const box = this._getInheritableProperty(name, /* getArray = */ true);
156
-
157
- if (Array.isArray(box) && box.length === 4) {
158
- if (box[2] - box[0] !== 0 && box[3] - box[1] !== 0) {
159
- return box;
160
- }
161
- warn(`Empty /${name} entry.`);
162
- }
163
- return null;
164
- }
165
-
166
- get mediaBox() {
167
- // Reset invalid media box to letter size.
168
- return shadow(
169
- this,
170
- "mediaBox",
171
- this._getBoundingBox("MediaBox") || LETTER_SIZE_MEDIABOX
172
- );
173
- }
174
-
175
- get cropBox() {
176
- // Reset invalid crop box to media box.
177
- return shadow(
178
- this,
179
- "cropBox",
180
- this._getBoundingBox("CropBox") || this.mediaBox
181
- );
182
- }
183
-
184
- get userUnit() {
185
- let obj = this.pageDict.get("UserUnit");
186
- if (!isNum(obj) || obj <= 0) {
187
- obj = DEFAULT_USER_UNIT;
188
- }
189
- return shadow(this, "userUnit", obj);
190
- }
191
-
192
- get view() {
193
- // From the spec, 6th ed., p.963:
194
- // "The crop, bleed, trim, and art boxes should not ordinarily
195
- // extend beyond the boundaries of the media box. If they do, they are
196
- // effectively reduced to their intersection with the media box."
197
- const { cropBox, mediaBox } = this;
198
- let view;
199
- if (cropBox === mediaBox || isArrayEqual(cropBox, mediaBox)) {
200
- view = mediaBox;
201
- } else {
202
- const box = Util.intersect(cropBox, mediaBox);
203
- if (box && box[2] - box[0] !== 0 && box[3] - box[1] !== 0) {
204
- view = box;
205
- } else {
206
- warn("Empty /CropBox and /MediaBox intersection.");
207
- }
208
- }
209
- return shadow(this, "view", view || mediaBox);
210
- }
211
-
212
- get rotate() {
213
- let rotate = this._getInheritableProperty("Rotate") || 0;
214
-
215
- // Normalize rotation so it's a multiple of 90 and between 0 and 270.
216
- if (rotate % 90 !== 0) {
217
- rotate = 0;
218
- } else if (rotate >= 360) {
219
- rotate %= 360;
220
- } else if (rotate < 0) {
221
- // The spec doesn't cover negatives. Assume it's counterclockwise
222
- // rotation. The following is the other implementation of modulo.
223
- rotate = ((rotate % 360) + 360) % 360;
224
- }
225
- return shadow(this, "rotate", rotate);
226
- }
227
-
228
- /**
229
- * @returns {Promise<BaseStream>}
230
- */
231
- getContentStream() {
232
- return this.pdfManager.ensure(this, "content").then(content => {
233
- if (content instanceof BaseStream) {
234
- return content;
235
- }
236
- if (Array.isArray(content)) {
237
- return new StreamsSequenceStream(content);
238
- }
239
- // Replace non-existent page content with empty content.
240
- return new NullStream();
241
- });
242
- }
243
-
244
- get xfaData() {
245
- if (this.xfaFactory) {
246
- return shadow(this, "xfaData", {
247
- bbox: this.xfaFactory.getBoundingBox(this.pageIndex),
248
- });
249
- }
250
- return shadow(this, "xfaData", null);
251
- }
252
-
253
- save(handler, task, annotationStorage) {
254
- const partialEvaluator = new PartialEvaluator({
255
- xref: this.xref,
256
- handler,
257
- pageIndex: this.pageIndex,
258
- idFactory: this._localIdFactory,
259
- fontCache: this.fontCache,
260
- builtInCMapCache: this.builtInCMapCache,
261
- standardFontDataCache: this.standardFontDataCache,
262
- globalImageCache: this.globalImageCache,
263
- options: this.evaluatorOptions,
264
- });
265
-
266
- // Fetch the page's annotations and save the content
267
- // in case of interactive form fields.
268
- return this._parsedAnnotations.then(function (annotations) {
269
- const newRefsPromises = [];
270
- for (const annotation of annotations) {
271
- if (!annotation.mustBePrinted(annotationStorage)) {
272
- continue;
273
- }
274
- newRefsPromises.push(
275
- annotation
276
- .save(partialEvaluator, task, annotationStorage)
277
- .catch(function (reason) {
278
- warn(
279
- "save - ignoring annotation data during " +
280
- `"${task.name}" task: "${reason}".`
281
- );
282
- return null;
283
- })
284
- );
285
- }
286
-
287
- return Promise.all(newRefsPromises);
288
- });
289
- }
290
-
291
- loadResources(keys) {
292
- if (!this.resourcesPromise) {
293
- // TODO: add async `_getInheritableProperty` and remove this.
294
- this.resourcesPromise = this.pdfManager.ensure(this, "resources");
295
- }
296
- return this.resourcesPromise.then(() => {
297
- const objectLoader = new ObjectLoader(this.resources, keys, this.xref);
298
- return objectLoader.load();
299
- });
300
- }
301
-
302
- getOperatorList({
303
- handler,
304
- sink,
305
- task,
306
- intent,
307
- renderInteractiveForms,
308
- annotationStorage,
309
- }) {
310
- const contentStreamPromise = this.getContentStream();
311
- const resourcesPromise = this.loadResources([
312
- "ColorSpace",
313
- "ExtGState",
314
- "Font",
315
- "Pattern",
316
- "Properties",
317
- "Shading",
318
- "XObject",
319
- ]);
320
-
321
- const partialEvaluator = new PartialEvaluator({
322
- xref: this.xref,
323
- handler,
324
- pageIndex: this.pageIndex,
325
- idFactory: this._localIdFactory,
326
- fontCache: this.fontCache,
327
- builtInCMapCache: this.builtInCMapCache,
328
- standardFontDataCache: this.standardFontDataCache,
329
- globalImageCache: this.globalImageCache,
330
- options: this.evaluatorOptions,
331
- });
332
-
333
- const dataPromises = Promise.all([contentStreamPromise, resourcesPromise]);
334
- const pageListPromise = dataPromises.then(([contentStream]) => {
335
- const opList = new OperatorList(intent, sink);
336
-
337
- handler.send("StartRenderPage", {
338
- transparency: partialEvaluator.hasBlendModes(
339
- this.resources,
340
- this.nonBlendModesSet
341
- ),
342
- pageIndex: this.pageIndex,
343
- intent,
344
- });
345
-
346
- return partialEvaluator
347
- .getOperatorList({
348
- stream: contentStream,
349
- task,
350
- resources: this.resources,
351
- operatorList: opList,
352
- })
353
- .then(function () {
354
- return opList;
355
- });
356
- });
357
-
358
- // Fetch the page's annotations and add their operator lists to the
359
- // page's operator list to render them.
360
- return Promise.all([pageListPromise, this._parsedAnnotations]).then(
361
- function ([pageOpList, annotations]) {
362
- if (annotations.length === 0) {
363
- pageOpList.flush(true);
364
- return { length: pageOpList.totalLength };
365
- }
366
-
367
- // Collect the operator list promises for the annotations. Each promise
368
- // is resolved with the complete operator list for a single annotation.
369
- const annotationIntent = intent.startsWith("oplist-")
370
- ? intent.split("-")[1]
371
- : intent;
372
- const opListPromises = [];
373
- for (const annotation of annotations) {
374
- if (
375
- (annotationIntent === "display" &&
376
- annotation.mustBeViewed(annotationStorage)) ||
377
- (annotationIntent === "print" &&
378
- annotation.mustBePrinted(annotationStorage))
379
- ) {
380
- opListPromises.push(
381
- annotation
382
- .getOperatorList(
383
- partialEvaluator,
384
- task,
385
- renderInteractiveForms,
386
- annotationStorage
387
- )
388
- .catch(function (reason) {
389
- warn(
390
- "getOperatorList - ignoring annotation data during " +
391
- `"${task.name}" task: "${reason}".`
392
- );
393
- return null;
394
- })
395
- );
396
- }
397
- }
398
-
399
- return Promise.all(opListPromises).then(function (opLists) {
400
- pageOpList.addOp(OPS.beginAnnotations, []);
401
- for (const opList of opLists) {
402
- pageOpList.addOpList(opList);
403
- }
404
- pageOpList.addOp(OPS.endAnnotations, []);
405
- pageOpList.flush(true);
406
- return { length: pageOpList.totalLength };
407
- });
408
- }
409
- );
410
- }
411
-
412
- extractTextContent({
413
- handler,
414
- task,
415
- normalizeWhitespace,
416
- includeMarkedContent,
417
- sink,
418
- combineTextItems,
419
- }) {
420
- const contentStreamPromise = this.getContentStream();
421
- const resourcesPromise = this.loadResources([
422
- "ExtGState",
423
- "Font",
424
- "Properties",
425
- "XObject",
426
- ]);
427
-
428
- const dataPromises = Promise.all([contentStreamPromise, resourcesPromise]);
429
- return dataPromises.then(([contentStream]) => {
430
- const partialEvaluator = new PartialEvaluator({
431
- xref: this.xref,
432
- handler,
433
- pageIndex: this.pageIndex,
434
- idFactory: this._localIdFactory,
435
- fontCache: this.fontCache,
436
- builtInCMapCache: this.builtInCMapCache,
437
- standardFontDataCache: this.standardFontDataCache,
438
- globalImageCache: this.globalImageCache,
439
- options: this.evaluatorOptions,
440
- });
441
-
442
- return partialEvaluator.getTextContent({
443
- stream: contentStream,
444
- task,
445
- resources: this.resources,
446
- normalizeWhitespace,
447
- includeMarkedContent,
448
- combineTextItems,
449
- sink,
450
- });
451
- });
452
- }
453
-
454
- async getStructTree() {
455
- const structTreeRoot = await this.pdfManager.ensureCatalog(
456
- "structTreeRoot"
457
- );
458
- if (!structTreeRoot) {
459
- return null;
460
- }
461
- const structTree = await this.pdfManager.ensure(this, "_parseStructTree", [
462
- structTreeRoot,
463
- ]);
464
- return structTree.serializable;
465
- }
466
-
467
- /**
468
- * @private
469
- */
470
- _parseStructTree(structTreeRoot) {
471
- const tree = new StructTreePage(structTreeRoot, this.pageDict);
472
- tree.parse();
473
- return tree;
474
- }
475
-
476
- getAnnotationsData(intent) {
477
- return this._parsedAnnotations.then(function (annotations) {
478
- const annotationsData = [];
479
- for (let i = 0, ii = annotations.length; i < ii; i++) {
480
- // Get the annotation even if it's hidden because
481
- // JS can change its display.
482
- if (
483
- !intent ||
484
- (intent === "display" && annotations[i].viewable) ||
485
- (intent === "print" && annotations[i].printable)
486
- ) {
487
- annotationsData.push(annotations[i].data);
488
- }
489
- }
490
- return annotationsData;
491
- });
492
- }
493
-
494
- get annotations() {
495
- const annots = this._getInheritableProperty("Annots");
496
- return shadow(this, "annotations", Array.isArray(annots) ? annots : []);
497
- }
498
-
499
- get _parsedAnnotations() {
500
- const parsedAnnotations = this.pdfManager
501
- .ensure(this, "annotations")
502
- .then(() => {
503
- const annotationPromises = [];
504
- for (const annotationRef of this.annotations) {
505
- annotationPromises.push(
506
- AnnotationFactory.create(
507
- this.xref,
508
- annotationRef,
509
- this.pdfManager,
510
- this._localIdFactory,
511
- /* collectFields */ false
512
- ).catch(function (reason) {
513
- warn(`_parsedAnnotations: "${reason}".`);
514
- return null;
515
- })
516
- );
517
- }
518
-
519
- return Promise.all(annotationPromises).then(function (annotations) {
520
- return annotations.filter(annotation => !!annotation);
521
- });
522
- });
523
-
524
- return shadow(this, "_parsedAnnotations", parsedAnnotations);
525
- }
526
-
527
- get jsActions() {
528
- const actions = collectActions(
529
- this.xref,
530
- this.pageDict,
531
- PageActionEventType
532
- );
533
- return shadow(this, "jsActions", actions);
534
- }
535
- }
536
-
537
- const PDF_HEADER_SIGNATURE = new Uint8Array([0x25, 0x50, 0x44, 0x46, 0x2d]);
538
- const STARTXREF_SIGNATURE = new Uint8Array([
539
- 0x73, 0x74, 0x61, 0x72, 0x74, 0x78, 0x72, 0x65, 0x66,
540
- ]);
541
- const ENDOBJ_SIGNATURE = new Uint8Array([0x65, 0x6e, 0x64, 0x6f, 0x62, 0x6a]);
542
-
543
- const FINGERPRINT_FIRST_BYTES = 1024;
544
- const EMPTY_FINGERPRINT =
545
- "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
546
-
547
- const PDF_HEADER_VERSION_REGEXP = /^[1-9]\.[0-9]$/;
548
-
549
- function find(stream, signature, limit = 1024, backwards = false) {
550
- if (
551
- typeof PDFJSDev === "undefined" ||
552
- PDFJSDev.test("!PRODUCTION || TESTING")
553
- ) {
554
- assert(limit > 0, 'The "limit" must be a positive integer.');
555
- }
556
- const signatureLength = signature.length;
557
-
558
- const scanBytes = stream.peekBytes(limit);
559
- const scanLength = scanBytes.length - signatureLength;
560
-
561
- if (scanLength <= 0) {
562
- return false;
563
- }
564
- if (backwards) {
565
- const signatureEnd = signatureLength - 1;
566
-
567
- let pos = scanBytes.length - 1;
568
- while (pos >= signatureEnd) {
569
- let j = 0;
570
- while (
571
- j < signatureLength &&
572
- scanBytes[pos - j] === signature[signatureEnd - j]
573
- ) {
574
- j++;
575
- }
576
- if (j >= signatureLength) {
577
- // `signature` found.
578
- stream.pos += pos - signatureEnd;
579
- return true;
580
- }
581
- pos--;
582
- }
583
- } else {
584
- // forwards
585
- let pos = 0;
586
- while (pos <= scanLength) {
587
- let j = 0;
588
- while (j < signatureLength && scanBytes[pos + j] === signature[j]) {
589
- j++;
590
- }
591
- if (j >= signatureLength) {
592
- // `signature` found.
593
- stream.pos += pos;
594
- return true;
595
- }
596
- pos++;
597
- }
598
- }
599
- return false;
600
- }
601
-
602
- /**
603
- * The `PDFDocument` class holds all the (worker-thread) data of the PDF file.
604
- */
605
- class PDFDocument {
606
- constructor(pdfManager, arg) {
607
- let stream;
608
- if (isStream(arg)) {
609
- stream = arg;
610
- } else if (isArrayBuffer(arg)) {
611
- stream = new Stream(arg);
612
- } else {
613
- throw new Error("PDFDocument: Unknown argument type");
614
- }
615
- if (stream.length <= 0) {
616
- throw new InvalidPDFException(
617
- "The PDF file is empty, i.e. its size is zero bytes."
618
- );
619
- }
620
-
621
- this.pdfManager = pdfManager;
622
- this.stream = stream;
623
- this.xref = new XRef(stream, pdfManager);
624
- this._pagePromises = [];
625
- this._version = null;
626
-
627
- const idCounters = {
628
- font: 0,
629
- };
630
- this._globalIdFactory = class {
631
- static getDocId() {
632
- return `g_${pdfManager.docId}`;
633
- }
634
-
635
- static createFontId() {
636
- return `f${++idCounters.font}`;
637
- }
638
-
639
- static createObjId() {
640
- unreachable("Abstract method `createObjId` called.");
641
- }
642
-
643
- static getPageObjId() {
644
- unreachable("Abstract method `getPageObjId` called.");
645
- }
646
- };
647
- }
648
-
649
- parse(recoveryMode) {
650
- this.xref.parse(recoveryMode);
651
- this.catalog = new Catalog(this.pdfManager, this.xref);
652
-
653
- // The `checkHeader` method is called before this method and parses the
654
- // version from the header. The specification states in section 7.5.2
655
- // that the version from the catalog, if present, should overwrite the
656
- // version from the header.
657
- if (this.catalog.version) {
658
- this._version = this.catalog.version;
659
- }
660
- }
661
-
662
- get linearization() {
663
- let linearization = null;
664
- try {
665
- linearization = Linearization.create(this.stream);
666
- } catch (err) {
667
- if (err instanceof MissingDataException) {
668
- throw err;
669
- }
670
- info(err);
671
- }
672
- return shadow(this, "linearization", linearization);
673
- }
674
-
675
- get startXRef() {
676
- const stream = this.stream;
677
- let startXRef = 0;
678
-
679
- if (this.linearization) {
680
- // Find the end of the first object.
681
- stream.reset();
682
- if (find(stream, ENDOBJ_SIGNATURE)) {
683
- startXRef = stream.pos + 6 - stream.start;
684
- }
685
- } else {
686
- // Find `startxref` by checking backwards from the end of the file.
687
- const step = 1024;
688
- const startXRefLength = STARTXREF_SIGNATURE.length;
689
- let found = false,
690
- pos = stream.end;
691
-
692
- while (!found && pos > 0) {
693
- pos -= step - startXRefLength;
694
- if (pos < 0) {
695
- pos = 0;
696
- }
697
- stream.pos = pos;
698
- found = find(stream, STARTXREF_SIGNATURE, step, true);
699
- }
700
-
701
- if (found) {
702
- stream.skip(9);
703
- let ch;
704
- do {
705
- ch = stream.getByte();
706
- } while (isWhiteSpace(ch));
707
- let str = "";
708
- while (ch >= /* Space = */ 0x20 && ch <= /* '9' = */ 0x39) {
709
- str += String.fromCharCode(ch);
710
- ch = stream.getByte();
711
- }
712
- startXRef = parseInt(str, 10);
713
- if (isNaN(startXRef)) {
714
- startXRef = 0;
715
- }
716
- }
717
- }
718
- return shadow(this, "startXRef", startXRef);
719
- }
720
-
721
- // Find the header, get the PDF format version and setup the
722
- // stream to start from the header.
723
- checkHeader() {
724
- const stream = this.stream;
725
- stream.reset();
726
-
727
- if (!find(stream, PDF_HEADER_SIGNATURE)) {
728
- // May not be a PDF file, but don't throw an error and let
729
- // parsing continue.
730
- return;
731
- }
732
- stream.moveStart();
733
-
734
- // Read the PDF format version.
735
- const MAX_PDF_VERSION_LENGTH = 12;
736
- let version = "",
737
- ch;
738
- while ((ch = stream.getByte()) > /* Space = */ 0x20) {
739
- if (version.length >= MAX_PDF_VERSION_LENGTH) {
740
- break;
741
- }
742
- version += String.fromCharCode(ch);
743
- }
744
- if (!this._version) {
745
- // Remove the "%PDF-" prefix.
746
- this._version = version.substring(5);
747
- }
748
- }
749
-
750
- parseStartXRef() {
751
- this.xref.setStartXRef(this.startXRef);
752
- }
753
-
754
- get numPages() {
755
- if (this.xfaFactory) {
756
- return shadow(this, "numPages", this.xfaFactory.numberPages);
757
- }
758
- const linearization = this.linearization;
759
- const num = linearization ? linearization.numPages : this.catalog.numPages;
760
- return shadow(this, "numPages", num);
761
- }
762
-
763
- /**
764
- * @private
765
- */
766
- _hasOnlyDocumentSignatures(fields, recursionDepth = 0) {
767
- const RECURSION_LIMIT = 10;
768
-
769
- if (!Array.isArray(fields)) {
770
- return false;
771
- }
772
- return fields.every(field => {
773
- field = this.xref.fetchIfRef(field);
774
- if (!(field instanceof Dict)) {
775
- return false;
776
- }
777
- if (field.has("Kids")) {
778
- if (++recursionDepth > RECURSION_LIMIT) {
779
- warn("_hasOnlyDocumentSignatures: maximum recursion depth reached");
780
- return false;
781
- }
782
- return this._hasOnlyDocumentSignatures(
783
- field.get("Kids"),
784
- recursionDepth
785
- );
786
- }
787
- const isSignature = isName(field.get("FT"), "Sig");
788
- const rectangle = field.get("Rect");
789
- const isInvisible =
790
- Array.isArray(rectangle) && rectangle.every(value => value === 0);
791
- return isSignature && isInvisible;
792
- });
793
- }
794
-
795
- get xfaData() {
796
- const acroForm = this.catalog.acroForm;
797
- if (!acroForm) {
798
- return null;
799
- }
800
-
801
- const xfa = acroForm.get("XFA");
802
- const entries = {
803
- "xdp:xdp": "",
804
- template: "",
805
- datasets: "",
806
- config: "",
807
- connectionSet: "",
808
- localeSet: "",
809
- stylesheet: "",
810
- "/xdp:xdp": "",
811
- };
812
- if (isStream(xfa) && !xfa.isEmpty) {
813
- try {
814
- entries["xdp:xdp"] = stringToUTF8String(xfa.getString());
815
- return entries;
816
- } catch (_) {
817
- warn("XFA - Invalid utf-8 string.");
818
- return null;
819
- }
820
- }
821
-
822
- if (!Array.isArray(xfa) || xfa.length === 0) {
823
- return null;
824
- }
825
-
826
- for (let i = 0, ii = xfa.length; i < ii; i += 2) {
827
- let name;
828
- if (i === 0) {
829
- name = "xdp:xdp";
830
- } else if (i === ii - 2) {
831
- name = "/xdp:xdp";
832
- } else {
833
- name = xfa[i];
834
- }
835
-
836
- if (!entries.hasOwnProperty(name)) {
837
- continue;
838
- }
839
- const data = this.xref.fetchIfRef(xfa[i + 1]);
840
- if (!isStream(data) || data.isEmpty) {
841
- continue;
842
- }
843
- try {
844
- entries[name] = stringToUTF8String(data.getString());
845
- } catch (_) {
846
- warn("XFA - Invalid utf-8 string.");
847
- return null;
848
- }
849
- }
850
- return entries;
851
- }
852
-
853
- get xfaFactory() {
854
- if (
855
- this.pdfManager.enableXfa &&
856
- this.formInfo.hasXfa &&
857
- !this.formInfo.hasAcroForm
858
- ) {
859
- const data = this.xfaData;
860
- return shadow(this, "xfaFactory", data ? new XFAFactory(data) : null);
861
- }
862
- return shadow(this, "xfaFaxtory", null);
863
- }
864
-
865
- get isPureXfa() {
866
- return this.xfaFactory && this.xfaFactory.isValid();
867
- }
868
-
869
- get htmlForXfa() {
870
- if (this.xfaFactory) {
871
- return this.xfaFactory.getPages();
872
- }
873
- return null;
874
- }
875
-
876
- async loadXfaImages() {
877
- const xfaImagesDict = await this.pdfManager.ensureCatalog("xfaImages");
878
- if (!xfaImagesDict) {
879
- return;
880
- }
881
-
882
- const keys = xfaImagesDict.getKeys();
883
- const objectLoader = new ObjectLoader(xfaImagesDict, keys, this.xref);
884
- await objectLoader.load();
885
-
886
- const xfaImages = new Map();
887
- for (const key of keys) {
888
- const stream = xfaImagesDict.get(key);
889
- if (!isStream(stream)) {
890
- continue;
891
- }
892
- xfaImages.set(key, stream.getBytes());
893
- }
894
-
895
- this.xfaFactory.setImages(xfaImages);
896
- }
897
-
898
- async loadXfaFonts(handler, task) {
899
- const acroForm = await this.pdfManager.ensureCatalog("acroForm");
900
- if (!acroForm) {
901
- return;
902
- }
903
- const resources = await acroForm.getAsync("DR");
904
- if (!(resources instanceof Dict)) {
905
- return;
906
- }
907
- const objectLoader = new ObjectLoader(resources, ["Font"], this.xref);
908
- await objectLoader.load();
909
-
910
- const fontRes = resources.get("Font");
911
- if (!(fontRes instanceof Dict)) {
912
- return;
913
- }
914
-
915
- const options = Object.assign(
916
- Object.create(null),
917
- this.pdfManager.evaluatorOptions
918
- );
919
- options.useSystemFonts = false;
920
-
921
- const partialEvaluator = new PartialEvaluator({
922
- xref: this.xref,
923
- handler,
924
- pageIndex: -1,
925
- idFactory: this._globalIdFactory,
926
- fontCache: this.catalog.fontCache,
927
- builtInCMapCache: this.catalog.builtInCMapCache,
928
- standardFontDataCache: this.catalog.standardFontDataCache,
929
- options,
930
- });
931
- const operatorList = new OperatorList();
932
- const pdfFonts = [];
933
- const initialState = {
934
- get font() {
935
- return pdfFonts[pdfFonts.length - 1];
936
- },
937
- set font(font) {
938
- pdfFonts.push(font);
939
- },
940
- clone() {
941
- return this;
942
- },
943
- };
944
-
945
- const fonts = new Map();
946
- fontRes.forEach((fontName, font) => {
947
- fonts.set(fontName, font);
948
- });
949
- const promises = [];
950
-
951
- for (const [fontName, font] of fonts) {
952
- const descriptor = font.get("FontDescriptor");
953
- if (!(descriptor instanceof Dict)) {
954
- continue;
955
- }
956
- let fontFamily = descriptor.get("FontFamily");
957
- // For example, "Wingdings 3" is not a valid font name in the css specs.
958
- fontFamily = fontFamily.replace(/[ ]+([0-9])/g, "$1");
959
- const fontWeight = descriptor.get("FontWeight");
960
-
961
- // Angle is expressed in degrees counterclockwise in PDF
962
- // when it's clockwise in CSS
963
- // (see https://drafts.csswg.org/css-fonts-4/#valdef-font-style-oblique-angle)
964
- const italicAngle = -descriptor.get("ItalicAngle");
965
- const cssFontInfo = { fontFamily, fontWeight, italicAngle };
966
-
967
- if (!validateCSSFont(cssFontInfo)) {
968
- continue;
969
- }
970
- promises.push(
971
- partialEvaluator
972
- .handleSetFont(
973
- resources,
974
- [Name.get(fontName), 1],
975
- /* fontRef = */ null,
976
- operatorList,
977
- task,
978
- initialState,
979
- /* fallbackFontDict = */ null,
980
- /* cssFontInfo = */ cssFontInfo
981
- )
982
- .catch(function (reason) {
983
- warn(`loadXfaFonts: "${reason}".`);
984
- return null;
985
- })
986
- );
987
- }
988
-
989
- await Promise.all(promises);
990
- const missingFonts = this.xfaFactory.setFonts(pdfFonts);
991
-
992
- if (!missingFonts) {
993
- return;
994
- }
995
-
996
- options.ignoreErrors = true;
997
- promises.length = 0;
998
- pdfFonts.length = 0;
999
-
1000
- const reallyMissingFonts = new Set();
1001
- for (const missing of missingFonts) {
1002
- if (!getXfaFontWidths(`${missing}-Regular`)) {
1003
- // No substitution available: we'll fallback on Myriad.
1004
- reallyMissingFonts.add(missing);
1005
- }
1006
- }
1007
-
1008
- if (reallyMissingFonts.size) {
1009
- missingFonts.push("PdfJS-Fallback");
1010
- }
1011
-
1012
- for (const missing of missingFonts) {
1013
- if (reallyMissingFonts.has(missing)) {
1014
- continue;
1015
- }
1016
- for (const fontInfo of [
1017
- { name: "Regular", fontWeight: 400, italicAngle: 0 },
1018
- { name: "Bold", fontWeight: 700, italicAngle: 0 },
1019
- { name: "Italic", fontWeight: 400, italicAngle: 12 },
1020
- { name: "BoldItalic", fontWeight: 700, italicAngle: 12 },
1021
- ]) {
1022
- const name = `${missing}-${fontInfo.name}`;
1023
- const widths = getXfaFontWidths(name);
1024
- const dict = new Dict(null);
1025
- dict.set("BaseFont", Name.get(name));
1026
- dict.set("Type", Name.get("Font"));
1027
- dict.set("Subtype", Name.get("TrueType"));
1028
- dict.set("Encoding", Name.get("WinAnsiEncoding"));
1029
- const descriptor = new Dict(null);
1030
- descriptor.set("Widths", widths);
1031
- dict.set("FontDescriptor", descriptor);
1032
-
1033
- promises.push(
1034
- partialEvaluator
1035
- .handleSetFont(
1036
- resources,
1037
- [Name.get(name), 1],
1038
- /* fontRef = */ null,
1039
- operatorList,
1040
- task,
1041
- initialState,
1042
- /* fallbackFontDict = */ dict,
1043
- /* cssFontInfo = */ {
1044
- fontFamily: missing,
1045
- fontWeight: fontInfo.fontWeight,
1046
- italicAngle: fontInfo.italicAngle,
1047
- }
1048
- )
1049
- .catch(function (reason) {
1050
- warn(`loadXfaFonts: "${reason}".`);
1051
- return null;
1052
- })
1053
- );
1054
- }
1055
- }
1056
-
1057
- await Promise.all(promises);
1058
- this.xfaFactory.appendFonts(pdfFonts, reallyMissingFonts);
1059
- }
1060
-
1061
- async serializeXfaData(annotationStorage) {
1062
- if (this.xfaFactory) {
1063
- return this.xfaFactory.serializeData(annotationStorage);
1064
- }
1065
- return null;
1066
- }
1067
-
1068
- get formInfo() {
1069
- const formInfo = {
1070
- hasFields: false,
1071
- hasAcroForm: false,
1072
- hasXfa: false,
1073
- hasSignatures: false,
1074
- };
1075
- const acroForm = this.catalog.acroForm;
1076
- if (!acroForm) {
1077
- return shadow(this, "formInfo", formInfo);
1078
- }
1079
-
1080
- try {
1081
- const fields = acroForm.get("Fields");
1082
- const hasFields = Array.isArray(fields) && fields.length > 0;
1083
- formInfo.hasFields = hasFields; // Used by the `fieldObjects` getter.
1084
-
1085
- // The document contains XFA data if the `XFA` entry is a non-empty
1086
- // array or stream.
1087
- const xfa = acroForm.get("XFA");
1088
- formInfo.hasXfa =
1089
- (Array.isArray(xfa) && xfa.length > 0) ||
1090
- (isStream(xfa) && !xfa.isEmpty);
1091
-
1092
- // The document contains AcroForm data if the `Fields` entry is a
1093
- // non-empty array and it doesn't consist of only document signatures.
1094
- // This second check is required for files that don't actually contain
1095
- // AcroForm data (only XFA data), but that use the `Fields` entry to
1096
- // store (invisible) document signatures. This can be detected using
1097
- // the first bit of the `SigFlags` integer (see Table 219 in the
1098
- // specification).
1099
- const sigFlags = acroForm.get("SigFlags");
1100
- const hasSignatures = !!(sigFlags & 0x1);
1101
- const hasOnlyDocumentSignatures =
1102
- hasSignatures && this._hasOnlyDocumentSignatures(fields);
1103
- formInfo.hasAcroForm = hasFields && !hasOnlyDocumentSignatures;
1104
- formInfo.hasSignatures = hasSignatures;
1105
- } catch (ex) {
1106
- if (ex instanceof MissingDataException) {
1107
- throw ex;
1108
- }
1109
- warn(`Cannot fetch form information: "${ex}".`);
1110
- }
1111
- return shadow(this, "formInfo", formInfo);
1112
- }
1113
-
1114
- get documentInfo() {
1115
- const DocumentInfoValidators = {
1116
- Title: isString,
1117
- Author: isString,
1118
- Subject: isString,
1119
- Keywords: isString,
1120
- Creator: isString,
1121
- Producer: isString,
1122
- CreationDate: isString,
1123
- ModDate: isString,
1124
- Trapped: isName,
1125
- };
1126
-
1127
- let version = this._version;
1128
- if (
1129
- typeof version !== "string" ||
1130
- !PDF_HEADER_VERSION_REGEXP.test(version)
1131
- ) {
1132
- warn(`Invalid PDF header version number: ${version}`);
1133
- version = null;
1134
- }
1135
-
1136
- const docInfo = {
1137
- PDFFormatVersion: version,
1138
- IsLinearized: !!this.linearization,
1139
- IsAcroFormPresent: this.formInfo.hasAcroForm,
1140
- IsXFAPresent: this.formInfo.hasXfa,
1141
- IsCollectionPresent: !!this.catalog.collection,
1142
- IsSignaturesPresent: this.formInfo.hasSignatures,
1143
- };
1144
-
1145
- let infoDict;
1146
- try {
1147
- infoDict = this.xref.trailer.get("Info");
1148
- } catch (err) {
1149
- if (err instanceof MissingDataException) {
1150
- throw err;
1151
- }
1152
- info("The document information dictionary is invalid.");
1153
- }
1154
-
1155
- if (isDict(infoDict)) {
1156
- // Fill the document info with valid entries from the specification,
1157
- // as well as any existing well-formed custom entries.
1158
- for (const key of infoDict.getKeys()) {
1159
- const value = infoDict.get(key);
1160
-
1161
- if (DocumentInfoValidators[key]) {
1162
- // Make sure the (standard) value conforms to the specification.
1163
- if (DocumentInfoValidators[key](value)) {
1164
- docInfo[key] =
1165
- typeof value !== "string" ? value : stringToPDFString(value);
1166
- } else {
1167
- info(`Bad value in document info for "${key}".`);
1168
- }
1169
- } else if (typeof key === "string") {
1170
- // For custom values, only accept white-listed types to prevent
1171
- // errors that would occur when trying to send non-serializable
1172
- // objects to the main-thread (for example `Dict` or `Stream`).
1173
- let customValue;
1174
- if (isString(value)) {
1175
- customValue = stringToPDFString(value);
1176
- } else if (isName(value) || isNum(value) || isBool(value)) {
1177
- customValue = value;
1178
- } else {
1179
- info(`Unsupported value in document info for (custom) "${key}".`);
1180
- continue;
1181
- }
1182
-
1183
- if (!docInfo.Custom) {
1184
- docInfo.Custom = Object.create(null);
1185
- }
1186
- docInfo.Custom[key] = customValue;
1187
- }
1188
- }
1189
- }
1190
- return shadow(this, "documentInfo", docInfo);
1191
- }
1192
-
1193
- get fingerprints() {
1194
- function validate(data) {
1195
- return (
1196
- typeof data === "string" &&
1197
- data.length > 0 &&
1198
- data !== EMPTY_FINGERPRINT
1199
- );
1200
- }
1201
-
1202
- function hexString(hash) {
1203
- const buf = [];
1204
- for (let i = 0, ii = hash.length; i < ii; i++) {
1205
- const hex = hash[i].toString(16);
1206
- buf.push(hex.padStart(2, "0"));
1207
- }
1208
- return buf.join("");
1209
- }
1210
-
1211
- const idArray = this.xref.trailer.get("ID");
1212
- let hashOriginal, hashModified;
1213
- if (Array.isArray(idArray) && validate(idArray[0])) {
1214
- hashOriginal = stringToBytes(idArray[0]);
1215
-
1216
- if (idArray[1] !== idArray[0] && validate(idArray[1])) {
1217
- hashModified = stringToBytes(idArray[1]);
1218
- }
1219
- } else {
1220
- hashOriginal = calculateMD5(
1221
- this.stream.getByteRange(0, FINGERPRINT_FIRST_BYTES),
1222
- 0,
1223
- FINGERPRINT_FIRST_BYTES
1224
- );
1225
- }
1226
-
1227
- return shadow(this, "fingerprints", [
1228
- hexString(hashOriginal),
1229
- hashModified ? hexString(hashModified) : null,
1230
- ]);
1231
- }
1232
-
1233
- _getLinearizationPage(pageIndex) {
1234
- const { catalog, linearization } = this;
1235
- if (
1236
- typeof PDFJSDev === "undefined" ||
1237
- PDFJSDev.test("!PRODUCTION || TESTING")
1238
- ) {
1239
- assert(
1240
- linearization && linearization.pageFirst === pageIndex,
1241
- "_getLinearizationPage - invalid pageIndex argument."
1242
- );
1243
- }
1244
-
1245
- const ref = Ref.get(linearization.objectNumberFirst, 0);
1246
- return this.xref
1247
- .fetchAsync(ref)
1248
- .then(obj => {
1249
- // Ensure that the object that was found is actually a Page dictionary.
1250
- if (
1251
- isDict(obj, "Page") ||
1252
- (isDict(obj) && !obj.has("Type") && obj.has("Contents"))
1253
- ) {
1254
- if (ref && !catalog.pageKidsCountCache.has(ref)) {
1255
- catalog.pageKidsCountCache.put(ref, 1); // Cache the Page reference.
1256
- }
1257
- return [obj, ref];
1258
- }
1259
- throw new FormatError(
1260
- "The Linearization dictionary doesn't point " +
1261
- "to a valid Page dictionary."
1262
- );
1263
- })
1264
- .catch(reason => {
1265
- info(reason);
1266
- return catalog.getPageDict(pageIndex);
1267
- });
1268
- }
1269
-
1270
- getPage(pageIndex) {
1271
- if (this._pagePromises[pageIndex] !== undefined) {
1272
- return this._pagePromises[pageIndex];
1273
- }
1274
- const { catalog, linearization } = this;
1275
-
1276
- if (this.xfaFactory) {
1277
- return Promise.resolve(
1278
- new Page({
1279
- pdfManager: this.pdfManager,
1280
- xref: this.xref,
1281
- pageIndex,
1282
- pageDict: Dict.empty,
1283
- ref: null,
1284
- globalIdFactory: this._globalIdFactory,
1285
- fontCache: catalog.fontCache,
1286
- builtInCMapCache: catalog.builtInCMapCache,
1287
- standardFontDataCache: catalog.standardFontDataCache,
1288
- globalImageCache: catalog.globalImageCache,
1289
- nonBlendModesSet: catalog.nonBlendModesSet,
1290
- xfaFactory: this.xfaFactory,
1291
- })
1292
- );
1293
- }
1294
-
1295
- const promise =
1296
- linearization && linearization.pageFirst === pageIndex
1297
- ? this._getLinearizationPage(pageIndex)
1298
- : catalog.getPageDict(pageIndex);
1299
-
1300
- return (this._pagePromises[pageIndex] = promise.then(([pageDict, ref]) => {
1301
- return new Page({
1302
- pdfManager: this.pdfManager,
1303
- xref: this.xref,
1304
- pageIndex,
1305
- pageDict,
1306
- ref,
1307
- globalIdFactory: this._globalIdFactory,
1308
- fontCache: catalog.fontCache,
1309
- builtInCMapCache: catalog.builtInCMapCache,
1310
- standardFontDataCache: catalog.standardFontDataCache,
1311
- globalImageCache: catalog.globalImageCache,
1312
- nonBlendModesSet: catalog.nonBlendModesSet,
1313
- xfaFactory: null,
1314
- });
1315
- }));
1316
- }
1317
-
1318
- checkFirstPage() {
1319
- return this.getPage(0).catch(async reason => {
1320
- if (reason instanceof XRefEntryException) {
1321
- // Clear out the various caches to ensure that we haven't stored any
1322
- // inconsistent and/or incorrect state, since that could easily break
1323
- // subsequent `this.getPage` calls.
1324
- this._pagePromises.length = 0;
1325
- await this.cleanup();
1326
-
1327
- throw new XRefParseException();
1328
- }
1329
- });
1330
- }
1331
-
1332
- fontFallback(id, handler) {
1333
- return this.catalog.fontFallback(id, handler);
1334
- }
1335
-
1336
- async cleanup(manuallyTriggered = false) {
1337
- return this.catalog
1338
- ? this.catalog.cleanup(manuallyTriggered)
1339
- : clearPrimitiveCaches();
1340
- }
1341
-
1342
- /**
1343
- * @private
1344
- */
1345
- _collectFieldObjects(name, fieldRef, promises) {
1346
- const field = this.xref.fetchIfRef(fieldRef);
1347
- if (field.has("T")) {
1348
- const partName = stringToPDFString(field.get("T"));
1349
- if (name === "") {
1350
- name = partName;
1351
- } else {
1352
- name = `${name}.${partName}`;
1353
- }
1354
- }
1355
-
1356
- if (!promises.has(name)) {
1357
- promises.set(name, []);
1358
- }
1359
- promises.get(name).push(
1360
- AnnotationFactory.create(
1361
- this.xref,
1362
- fieldRef,
1363
- this.pdfManager,
1364
- this._localIdFactory,
1365
- /* collectFields */ true
1366
- )
1367
- .then(annotation => annotation && annotation.getFieldObject())
1368
- .catch(function (reason) {
1369
- warn(`_collectFieldObjects: "${reason}".`);
1370
- return null;
1371
- })
1372
- );
1373
-
1374
- if (field.has("Kids")) {
1375
- const kids = field.get("Kids");
1376
- for (const kid of kids) {
1377
- this._collectFieldObjects(name, kid, promises);
1378
- }
1379
- }
1380
- }
1381
-
1382
- get fieldObjects() {
1383
- if (!this.formInfo.hasFields) {
1384
- return shadow(this, "fieldObjects", Promise.resolve(null));
1385
- }
1386
-
1387
- const allFields = Object.create(null);
1388
- const fieldPromises = new Map();
1389
- for (const fieldRef of this.catalog.acroForm.get("Fields")) {
1390
- this._collectFieldObjects("", fieldRef, fieldPromises);
1391
- }
1392
-
1393
- const allPromises = [];
1394
- for (const [name, promises] of fieldPromises) {
1395
- allPromises.push(
1396
- Promise.all(promises).then(fields => {
1397
- fields = fields.filter(field => !!field);
1398
- if (fields.length > 0) {
1399
- allFields[name] = fields;
1400
- }
1401
- })
1402
- );
1403
- }
1404
-
1405
- return shadow(
1406
- this,
1407
- "fieldObjects",
1408
- Promise.all(allPromises).then(() => allFields)
1409
- );
1410
- }
1411
-
1412
- get hasJSActions() {
1413
- const promise = this.pdfManager.ensureDoc("_parseHasJSActions");
1414
- return shadow(this, "hasJSActions", promise);
1415
- }
1416
-
1417
- /**
1418
- * @private
1419
- */
1420
- async _parseHasJSActions() {
1421
- const [catalogJsActions, fieldObjects] = await Promise.all([
1422
- this.pdfManager.ensureCatalog("jsActions"),
1423
- this.pdfManager.ensureDoc("fieldObjects"),
1424
- ]);
1425
-
1426
- if (catalogJsActions) {
1427
- return true;
1428
- }
1429
- if (fieldObjects) {
1430
- return Object.values(fieldObjects).some(fieldObject =>
1431
- fieldObject.some(object => object.actions !== null)
1432
- );
1433
- }
1434
- return false;
1435
- }
1436
-
1437
- get calculationOrderIds() {
1438
- const acroForm = this.catalog.acroForm;
1439
- if (!acroForm || !acroForm.has("CO")) {
1440
- return shadow(this, "calculationOrderIds", null);
1441
- }
1442
-
1443
- const calculationOrder = acroForm.get("CO");
1444
- if (!Array.isArray(calculationOrder) || calculationOrder.length === 0) {
1445
- return shadow(this, "calculationOrderIds", null);
1446
- }
1447
-
1448
- const ids = calculationOrder.filter(isRef).map(ref => ref.toString());
1449
- if (ids.length === 0) {
1450
- return shadow(this, "calculationOrderIds", null);
1451
- }
1452
- return shadow(this, "calculationOrderIds", ids);
1453
- }
1454
- }
1455
-
1456
- export { Page, PDFDocument };