document.js 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817
  1. /**
  2. * @licstart The following is the entire license notice for the
  3. * Javascript code in this page
  4. *
  5. * Copyright 2020 Mozilla Foundation
  6. *
  7. * Licensed under the Apache License, Version 2.0 (the "License");
  8. * you may not use this file except in compliance with the License.
  9. * You may obtain a copy of the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing, software
  14. * distributed under the License is distributed on an "AS IS" BASIS,
  15. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16. * See the License for the specific language governing permissions and
  17. * limitations under the License.
  18. *
  19. * @licend The above is the entire license notice for the
  20. * Javascript code in this page
  21. */
  22. "use strict";
  23. Object.defineProperty(exports, "__esModule", {
  24. value: true
  25. });
  26. exports.PDFDocument = exports.Page = void 0;
  27. var _util = require("../shared/util.js");
  28. var _obj = require("./obj.js");
  29. var _primitives = require("./primitives.js");
  30. var _core_utils = require("./core_utils.js");
  31. var _stream = require("./stream.js");
  32. var _annotation = require("./annotation.js");
  33. var _crypto = require("./crypto.js");
  34. var _parser = require("./parser.js");
  35. var _operator_list = require("./operator_list.js");
  36. var _evaluator = require("./evaluator.js");
  37. const DEFAULT_USER_UNIT = 1.0;
  38. const LETTER_SIZE_MEDIABOX = [0, 0, 612, 792];
  39. function isAnnotationRenderable(annotation, intent) {
  40. return intent === "display" && annotation.viewable || intent === "print" && annotation.printable;
  41. }
  42. class Page {
  43. constructor({
  44. pdfManager,
  45. xref,
  46. pageIndex,
  47. pageDict,
  48. ref,
  49. globalIdFactory,
  50. fontCache,
  51. builtInCMapCache,
  52. globalImageCache
  53. }) {
  54. this.pdfManager = pdfManager;
  55. this.pageIndex = pageIndex;
  56. this.pageDict = pageDict;
  57. this.xref = xref;
  58. this.ref = ref;
  59. this.fontCache = fontCache;
  60. this.builtInCMapCache = builtInCMapCache;
  61. this.globalImageCache = globalImageCache;
  62. this.evaluatorOptions = pdfManager.evaluatorOptions;
  63. this.resourcesPromise = null;
  64. const idCounters = {
  65. obj: 0
  66. };
  67. this._localIdFactory = class extends globalIdFactory {
  68. static createObjId() {
  69. return `p${pageIndex}_${++idCounters.obj}`;
  70. }
  71. };
  72. }
  73. _getInheritableProperty(key, getArray = false) {
  74. const value = (0, _core_utils.getInheritableProperty)({
  75. dict: this.pageDict,
  76. key,
  77. getArray,
  78. stopWhenFound: false
  79. });
  80. if (!Array.isArray(value)) {
  81. return value;
  82. }
  83. if (value.length === 1 || !(0, _primitives.isDict)(value[0])) {
  84. return value[0];
  85. }
  86. return _primitives.Dict.merge({
  87. xref: this.xref,
  88. dictArray: value
  89. });
  90. }
  91. get content() {
  92. return this.pageDict.get("Contents");
  93. }
  94. get resources() {
  95. return (0, _util.shadow)(this, "resources", this._getInheritableProperty("Resources") || _primitives.Dict.empty);
  96. }
  97. _getBoundingBox(name) {
  98. const box = this._getInheritableProperty(name, true);
  99. if (Array.isArray(box) && box.length === 4) {
  100. if (box[2] - box[0] !== 0 && box[3] - box[1] !== 0) {
  101. return box;
  102. }
  103. (0, _util.warn)(`Empty /${name} entry.`);
  104. }
  105. return null;
  106. }
  107. get mediaBox() {
  108. return (0, _util.shadow)(this, "mediaBox", this._getBoundingBox("MediaBox") || LETTER_SIZE_MEDIABOX);
  109. }
  110. get cropBox() {
  111. return (0, _util.shadow)(this, "cropBox", this._getBoundingBox("CropBox") || this.mediaBox);
  112. }
  113. get userUnit() {
  114. let obj = this.pageDict.get("UserUnit");
  115. if (!(0, _util.isNum)(obj) || obj <= 0) {
  116. obj = DEFAULT_USER_UNIT;
  117. }
  118. return (0, _util.shadow)(this, "userUnit", obj);
  119. }
  120. get view() {
  121. const {
  122. cropBox,
  123. mediaBox
  124. } = this;
  125. let view;
  126. if (cropBox === mediaBox || (0, _util.isArrayEqual)(cropBox, mediaBox)) {
  127. view = mediaBox;
  128. } else {
  129. const box = _util.Util.intersect(cropBox, mediaBox);
  130. if (box && box[2] - box[0] !== 0 && box[3] - box[1] !== 0) {
  131. view = box;
  132. } else {
  133. (0, _util.warn)("Empty /CropBox and /MediaBox intersection.");
  134. }
  135. }
  136. return (0, _util.shadow)(this, "view", view || mediaBox);
  137. }
  138. get rotate() {
  139. let rotate = this._getInheritableProperty("Rotate") || 0;
  140. if (rotate % 90 !== 0) {
  141. rotate = 0;
  142. } else if (rotate >= 360) {
  143. rotate = rotate % 360;
  144. } else if (rotate < 0) {
  145. rotate = (rotate % 360 + 360) % 360;
  146. }
  147. return (0, _util.shadow)(this, "rotate", rotate);
  148. }
  149. getContentStream() {
  150. const content = this.content;
  151. let stream;
  152. if (Array.isArray(content)) {
  153. const xref = this.xref;
  154. const streams = [];
  155. for (const subStream of content) {
  156. streams.push(xref.fetchIfRef(subStream));
  157. }
  158. stream = new _stream.StreamsSequenceStream(streams);
  159. } else if ((0, _primitives.isStream)(content)) {
  160. stream = content;
  161. } else {
  162. stream = new _stream.NullStream();
  163. }
  164. return stream;
  165. }
  166. save(handler, task, annotationStorage) {
  167. const partialEvaluator = new _evaluator.PartialEvaluator({
  168. xref: this.xref,
  169. handler,
  170. pageIndex: this.pageIndex,
  171. idFactory: this._localIdFactory,
  172. fontCache: this.fontCache,
  173. builtInCMapCache: this.builtInCMapCache,
  174. globalImageCache: this.globalImageCache,
  175. options: this.evaluatorOptions
  176. });
  177. return this._parsedAnnotations.then(function (annotations) {
  178. const newRefsPromises = [];
  179. for (const annotation of annotations) {
  180. if (!isAnnotationRenderable(annotation, "print")) {
  181. continue;
  182. }
  183. newRefsPromises.push(annotation.save(partialEvaluator, task, annotationStorage).catch(function (reason) {
  184. (0, _util.warn)("save - ignoring annotation data during " + `"${task.name}" task: "${reason}".`);
  185. return null;
  186. }));
  187. }
  188. return Promise.all(newRefsPromises);
  189. });
  190. }
  191. loadResources(keys) {
  192. if (!this.resourcesPromise) {
  193. this.resourcesPromise = this.pdfManager.ensure(this, "resources");
  194. }
  195. return this.resourcesPromise.then(() => {
  196. const objectLoader = new _obj.ObjectLoader(this.resources, keys, this.xref);
  197. return objectLoader.load();
  198. });
  199. }
  200. getOperatorList({
  201. handler,
  202. sink,
  203. task,
  204. intent,
  205. renderInteractiveForms,
  206. annotationStorage
  207. }) {
  208. const contentStreamPromise = this.pdfManager.ensure(this, "getContentStream");
  209. const resourcesPromise = this.loadResources(["ExtGState", "ColorSpace", "Pattern", "Shading", "XObject", "Font"]);
  210. const partialEvaluator = new _evaluator.PartialEvaluator({
  211. xref: this.xref,
  212. handler,
  213. pageIndex: this.pageIndex,
  214. idFactory: this._localIdFactory,
  215. fontCache: this.fontCache,
  216. builtInCMapCache: this.builtInCMapCache,
  217. globalImageCache: this.globalImageCache,
  218. options: this.evaluatorOptions
  219. });
  220. const dataPromises = Promise.all([contentStreamPromise, resourcesPromise]);
  221. const pageListPromise = dataPromises.then(([contentStream]) => {
  222. const opList = new _operator_list.OperatorList(intent, sink);
  223. handler.send("StartRenderPage", {
  224. transparency: partialEvaluator.hasBlendModes(this.resources),
  225. pageIndex: this.pageIndex,
  226. intent
  227. });
  228. return partialEvaluator.getOperatorList({
  229. stream: contentStream,
  230. task,
  231. resources: this.resources,
  232. operatorList: opList
  233. }).then(function () {
  234. return opList;
  235. });
  236. });
  237. return Promise.all([pageListPromise, this._parsedAnnotations]).then(function ([pageOpList, annotations]) {
  238. if (annotations.length === 0) {
  239. pageOpList.flush(true);
  240. return {
  241. length: pageOpList.totalLength
  242. };
  243. }
  244. const opListPromises = [];
  245. for (const annotation of annotations) {
  246. if (isAnnotationRenderable(annotation, intent)) {
  247. opListPromises.push(annotation.getOperatorList(partialEvaluator, task, renderInteractiveForms, annotationStorage).catch(function (reason) {
  248. (0, _util.warn)("getOperatorList - ignoring annotation data during " + `"${task.name}" task: "${reason}".`);
  249. return null;
  250. }));
  251. }
  252. }
  253. return Promise.all(opListPromises).then(function (opLists) {
  254. pageOpList.addOp(_util.OPS.beginAnnotations, []);
  255. for (const opList of opLists) {
  256. pageOpList.addOpList(opList);
  257. }
  258. pageOpList.addOp(_util.OPS.endAnnotations, []);
  259. pageOpList.flush(true);
  260. return {
  261. length: pageOpList.totalLength
  262. };
  263. });
  264. });
  265. }
  266. extractTextContent({
  267. handler,
  268. task,
  269. normalizeWhitespace,
  270. sink,
  271. combineTextItems
  272. }) {
  273. const contentStreamPromise = this.pdfManager.ensure(this, "getContentStream");
  274. const resourcesPromise = this.loadResources(["ExtGState", "XObject", "Font"]);
  275. const dataPromises = Promise.all([contentStreamPromise, resourcesPromise]);
  276. return dataPromises.then(([contentStream]) => {
  277. const partialEvaluator = new _evaluator.PartialEvaluator({
  278. xref: this.xref,
  279. handler,
  280. pageIndex: this.pageIndex,
  281. idFactory: this._localIdFactory,
  282. fontCache: this.fontCache,
  283. builtInCMapCache: this.builtInCMapCache,
  284. globalImageCache: this.globalImageCache,
  285. options: this.evaluatorOptions
  286. });
  287. return partialEvaluator.getTextContent({
  288. stream: contentStream,
  289. task,
  290. resources: this.resources,
  291. normalizeWhitespace,
  292. combineTextItems,
  293. sink
  294. });
  295. });
  296. }
  297. getAnnotationsData(intent) {
  298. return this._parsedAnnotations.then(function (annotations) {
  299. const annotationsData = [];
  300. for (let i = 0, ii = annotations.length; i < ii; i++) {
  301. if (!intent || isAnnotationRenderable(annotations[i], intent)) {
  302. annotationsData.push(annotations[i].data);
  303. }
  304. }
  305. return annotationsData;
  306. });
  307. }
  308. get annotations() {
  309. return (0, _util.shadow)(this, "annotations", this._getInheritableProperty("Annots") || []);
  310. }
  311. get _parsedAnnotations() {
  312. const parsedAnnotations = this.pdfManager.ensure(this, "annotations").then(() => {
  313. const annotationPromises = [];
  314. for (const annotationRef of this.annotations) {
  315. annotationPromises.push(_annotation.AnnotationFactory.create(this.xref, annotationRef, this.pdfManager, this._localIdFactory).catch(function (reason) {
  316. (0, _util.warn)(`_parsedAnnotations: "${reason}".`);
  317. return null;
  318. }));
  319. }
  320. return Promise.all(annotationPromises).then(function (annotations) {
  321. return annotations.filter(annotation => !!annotation);
  322. });
  323. });
  324. return (0, _util.shadow)(this, "_parsedAnnotations", parsedAnnotations);
  325. }
  326. }
  327. exports.Page = Page;
  328. const PDF_HEADER_SIGNATURE = new Uint8Array([0x25, 0x50, 0x44, 0x46, 0x2d]);
  329. const STARTXREF_SIGNATURE = new Uint8Array([0x73, 0x74, 0x61, 0x72, 0x74, 0x78, 0x72, 0x65, 0x66]);
  330. const ENDOBJ_SIGNATURE = new Uint8Array([0x65, 0x6e, 0x64, 0x6f, 0x62, 0x6a]);
  331. const FINGERPRINT_FIRST_BYTES = 1024;
  332. const EMPTY_FINGERPRINT = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
  333. const PDF_HEADER_VERSION_REGEXP = /^[1-9]\.[0-9]$/;
  334. function find(stream, signature, limit = 1024, backwards = false) {
  335. const signatureLength = signature.length;
  336. const scanBytes = stream.peekBytes(limit);
  337. const scanLength = scanBytes.length - signatureLength;
  338. if (scanLength <= 0) {
  339. return false;
  340. }
  341. if (backwards) {
  342. const signatureEnd = signatureLength - 1;
  343. let pos = scanBytes.length - 1;
  344. while (pos >= signatureEnd) {
  345. let j = 0;
  346. while (j < signatureLength && scanBytes[pos - j] === signature[signatureEnd - j]) {
  347. j++;
  348. }
  349. if (j >= signatureLength) {
  350. stream.pos += pos - signatureEnd;
  351. return true;
  352. }
  353. pos--;
  354. }
  355. } else {
  356. let pos = 0;
  357. while (pos <= scanLength) {
  358. let j = 0;
  359. while (j < signatureLength && scanBytes[pos + j] === signature[j]) {
  360. j++;
  361. }
  362. if (j >= signatureLength) {
  363. stream.pos += pos;
  364. return true;
  365. }
  366. pos++;
  367. }
  368. }
  369. return false;
  370. }
  371. class PDFDocument {
  372. constructor(pdfManager, arg) {
  373. let stream;
  374. if ((0, _primitives.isStream)(arg)) {
  375. stream = arg;
  376. } else if ((0, _util.isArrayBuffer)(arg)) {
  377. stream = new _stream.Stream(arg);
  378. } else {
  379. throw new Error("PDFDocument: Unknown argument type");
  380. }
  381. if (stream.length <= 0) {
  382. throw new _util.InvalidPDFException("The PDF file is empty, i.e. its size is zero bytes.");
  383. }
  384. this.pdfManager = pdfManager;
  385. this.stream = stream;
  386. this.xref = new _obj.XRef(stream, pdfManager);
  387. this._pagePromises = [];
  388. this._version = null;
  389. const idCounters = {
  390. font: 0
  391. };
  392. this._globalIdFactory = class {
  393. static getDocId() {
  394. return `g_${pdfManager.docId}`;
  395. }
  396. static createFontId() {
  397. return `f${++idCounters.font}`;
  398. }
  399. static createObjId() {
  400. (0, _util.unreachable)("Abstract method `createObjId` called.");
  401. }
  402. };
  403. }
  404. parse(recoveryMode) {
  405. this.xref.parse(recoveryMode);
  406. this.catalog = new _obj.Catalog(this.pdfManager, this.xref);
  407. if (this.catalog.version) {
  408. this._version = this.catalog.version;
  409. }
  410. }
  411. get linearization() {
  412. let linearization = null;
  413. try {
  414. linearization = _parser.Linearization.create(this.stream);
  415. } catch (err) {
  416. if (err instanceof _core_utils.MissingDataException) {
  417. throw err;
  418. }
  419. (0, _util.info)(err);
  420. }
  421. return (0, _util.shadow)(this, "linearization", linearization);
  422. }
  423. get startXRef() {
  424. const stream = this.stream;
  425. let startXRef = 0;
  426. if (this.linearization) {
  427. stream.reset();
  428. if (find(stream, ENDOBJ_SIGNATURE)) {
  429. startXRef = stream.pos + 6 - stream.start;
  430. }
  431. } else {
  432. const step = 1024;
  433. const startXRefLength = STARTXREF_SIGNATURE.length;
  434. let found = false,
  435. pos = stream.end;
  436. while (!found && pos > 0) {
  437. pos -= step - startXRefLength;
  438. if (pos < 0) {
  439. pos = 0;
  440. }
  441. stream.pos = pos;
  442. found = find(stream, STARTXREF_SIGNATURE, step, true);
  443. }
  444. if (found) {
  445. stream.skip(9);
  446. let ch;
  447. do {
  448. ch = stream.getByte();
  449. } while ((0, _core_utils.isWhiteSpace)(ch));
  450. let str = "";
  451. while (ch >= 0x20 && ch <= 0x39) {
  452. str += String.fromCharCode(ch);
  453. ch = stream.getByte();
  454. }
  455. startXRef = parseInt(str, 10);
  456. if (isNaN(startXRef)) {
  457. startXRef = 0;
  458. }
  459. }
  460. }
  461. return (0, _util.shadow)(this, "startXRef", startXRef);
  462. }
  463. checkHeader() {
  464. const stream = this.stream;
  465. stream.reset();
  466. if (!find(stream, PDF_HEADER_SIGNATURE)) {
  467. return;
  468. }
  469. stream.moveStart();
  470. const MAX_PDF_VERSION_LENGTH = 12;
  471. let version = "",
  472. ch;
  473. while ((ch = stream.getByte()) > 0x20) {
  474. if (version.length >= MAX_PDF_VERSION_LENGTH) {
  475. break;
  476. }
  477. version += String.fromCharCode(ch);
  478. }
  479. if (!this._version) {
  480. this._version = version.substring(5);
  481. }
  482. }
  483. parseStartXRef() {
  484. this.xref.setStartXRef(this.startXRef);
  485. }
  486. get numPages() {
  487. const linearization = this.linearization;
  488. const num = linearization ? linearization.numPages : this.catalog.numPages;
  489. return (0, _util.shadow)(this, "numPages", num);
  490. }
  491. _hasOnlyDocumentSignatures(fields, recursionDepth = 0) {
  492. const RECURSION_LIMIT = 10;
  493. return fields.every(field => {
  494. field = this.xref.fetchIfRef(field);
  495. if (field.has("Kids")) {
  496. if (++recursionDepth > RECURSION_LIMIT) {
  497. (0, _util.warn)("_hasOnlyDocumentSignatures: maximum recursion depth reached");
  498. return false;
  499. }
  500. return this._hasOnlyDocumentSignatures(field.get("Kids"), recursionDepth);
  501. }
  502. const isSignature = (0, _primitives.isName)(field.get("FT"), "Sig");
  503. const rectangle = field.get("Rect");
  504. const isInvisible = Array.isArray(rectangle) && rectangle.every(value => value === 0);
  505. return isSignature && isInvisible;
  506. });
  507. }
  508. get formInfo() {
  509. const formInfo = {
  510. hasAcroForm: false,
  511. hasXfa: false
  512. };
  513. const acroForm = this.catalog.acroForm;
  514. if (!acroForm) {
  515. return (0, _util.shadow)(this, "formInfo", formInfo);
  516. }
  517. try {
  518. const xfa = acroForm.get("XFA");
  519. const hasXfa = Array.isArray(xfa) && xfa.length > 0 || (0, _primitives.isStream)(xfa) && !xfa.isEmpty;
  520. formInfo.hasXfa = hasXfa;
  521. const fields = acroForm.get("Fields");
  522. const hasFields = Array.isArray(fields) && fields.length > 0;
  523. const sigFlags = acroForm.get("SigFlags");
  524. const hasOnlyDocumentSignatures = !!(sigFlags & 0x1) && this._hasOnlyDocumentSignatures(fields);
  525. formInfo.hasAcroForm = hasFields && !hasOnlyDocumentSignatures;
  526. } catch (ex) {
  527. if (ex instanceof _core_utils.MissingDataException) {
  528. throw ex;
  529. }
  530. (0, _util.info)("Cannot fetch form information.");
  531. }
  532. return (0, _util.shadow)(this, "formInfo", formInfo);
  533. }
  534. get documentInfo() {
  535. const DocumentInfoValidators = {
  536. Title: _util.isString,
  537. Author: _util.isString,
  538. Subject: _util.isString,
  539. Keywords: _util.isString,
  540. Creator: _util.isString,
  541. Producer: _util.isString,
  542. CreationDate: _util.isString,
  543. ModDate: _util.isString,
  544. Trapped: _primitives.isName
  545. };
  546. let version = this._version;
  547. if (typeof version !== "string" || !PDF_HEADER_VERSION_REGEXP.test(version)) {
  548. (0, _util.warn)(`Invalid PDF header version number: ${version}`);
  549. version = null;
  550. }
  551. const docInfo = {
  552. PDFFormatVersion: version,
  553. IsLinearized: !!this.linearization,
  554. IsAcroFormPresent: this.formInfo.hasAcroForm,
  555. IsXFAPresent: this.formInfo.hasXfa,
  556. IsCollectionPresent: !!this.catalog.collection
  557. };
  558. let infoDict;
  559. try {
  560. infoDict = this.xref.trailer.get("Info");
  561. } catch (err) {
  562. if (err instanceof _core_utils.MissingDataException) {
  563. throw err;
  564. }
  565. (0, _util.info)("The document information dictionary is invalid.");
  566. }
  567. if ((0, _primitives.isDict)(infoDict)) {
  568. for (const key of infoDict.getKeys()) {
  569. const value = infoDict.get(key);
  570. if (DocumentInfoValidators[key]) {
  571. if (DocumentInfoValidators[key](value)) {
  572. docInfo[key] = typeof value !== "string" ? value : (0, _util.stringToPDFString)(value);
  573. } else {
  574. (0, _util.info)(`Bad value in document info for "${key}".`);
  575. }
  576. } else if (typeof key === "string") {
  577. let customValue;
  578. if ((0, _util.isString)(value)) {
  579. customValue = (0, _util.stringToPDFString)(value);
  580. } else if ((0, _primitives.isName)(value) || (0, _util.isNum)(value) || (0, _util.isBool)(value)) {
  581. customValue = value;
  582. } else {
  583. (0, _util.info)(`Unsupported value in document info for (custom) "${key}".`);
  584. continue;
  585. }
  586. if (!docInfo.Custom) {
  587. docInfo.Custom = Object.create(null);
  588. }
  589. docInfo.Custom[key] = customValue;
  590. }
  591. }
  592. }
  593. return (0, _util.shadow)(this, "documentInfo", docInfo);
  594. }
  595. get fingerprint() {
  596. let hash;
  597. const idArray = this.xref.trailer.get("ID");
  598. if (Array.isArray(idArray) && idArray[0] && (0, _util.isString)(idArray[0]) && idArray[0] !== EMPTY_FINGERPRINT) {
  599. hash = (0, _util.stringToBytes)(idArray[0]);
  600. } else {
  601. hash = (0, _crypto.calculateMD5)(this.stream.getByteRange(0, FINGERPRINT_FIRST_BYTES), 0, FINGERPRINT_FIRST_BYTES);
  602. }
  603. const fingerprintBuf = [];
  604. for (let i = 0, ii = hash.length; i < ii; i++) {
  605. const hex = hash[i].toString(16);
  606. fingerprintBuf.push(hex.padStart(2, "0"));
  607. }
  608. return (0, _util.shadow)(this, "fingerprint", fingerprintBuf.join(""));
  609. }
  610. _getLinearizationPage(pageIndex) {
  611. const {
  612. catalog,
  613. linearization
  614. } = this;
  615. const ref = _primitives.Ref.get(linearization.objectNumberFirst, 0);
  616. return this.xref.fetchAsync(ref).then(obj => {
  617. if ((0, _primitives.isDict)(obj, "Page") || (0, _primitives.isDict)(obj) && !obj.has("Type") && obj.has("Contents")) {
  618. if (ref && !catalog.pageKidsCountCache.has(ref)) {
  619. catalog.pageKidsCountCache.put(ref, 1);
  620. }
  621. return [obj, ref];
  622. }
  623. throw new _util.FormatError("The Linearization dictionary doesn't point " + "to a valid Page dictionary.");
  624. }).catch(reason => {
  625. (0, _util.info)(reason);
  626. return catalog.getPageDict(pageIndex);
  627. });
  628. }
  629. getPage(pageIndex) {
  630. if (this._pagePromises[pageIndex] !== undefined) {
  631. return this._pagePromises[pageIndex];
  632. }
  633. const {
  634. catalog,
  635. linearization
  636. } = this;
  637. const promise = linearization && linearization.pageFirst === pageIndex ? this._getLinearizationPage(pageIndex) : catalog.getPageDict(pageIndex);
  638. return this._pagePromises[pageIndex] = promise.then(([pageDict, ref]) => {
  639. return new Page({
  640. pdfManager: this.pdfManager,
  641. xref: this.xref,
  642. pageIndex,
  643. pageDict,
  644. ref,
  645. globalIdFactory: this._globalIdFactory,
  646. fontCache: catalog.fontCache,
  647. builtInCMapCache: catalog.builtInCMapCache,
  648. globalImageCache: catalog.globalImageCache
  649. });
  650. });
  651. }
  652. checkFirstPage() {
  653. return this.getPage(0).catch(async reason => {
  654. if (reason instanceof _core_utils.XRefEntryException) {
  655. this._pagePromises.length = 0;
  656. await this.cleanup();
  657. throw new _core_utils.XRefParseException();
  658. }
  659. });
  660. }
  661. fontFallback(id, handler) {
  662. return this.catalog.fontFallback(id, handler);
  663. }
  664. async cleanup(manuallyTriggered = false) {
  665. return this.catalog ? this.catalog.cleanup(manuallyTriggered) : (0, _primitives.clearPrimitiveCaches)();
  666. }
  667. }
  668. exports.PDFDocument = PDFDocument;