Merge pull request #10393 from timvandermeij/document
Convert `src/core/document.js` to ES6 syntax
This commit is contained in:
		
						commit
						7c080584b6
					
				| @ -12,6 +12,7 @@ | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
| /* eslint no-var: error */ | ||||
| 
 | ||||
| import { | ||||
|   arrayByteLength, arraysToBytes, createPromiseCapability, isEmptyObj, | ||||
|  | ||||
| @ -12,6 +12,7 @@ | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
| /* eslint no-var: error */ | ||||
| 
 | ||||
| import { | ||||
|   assert, FormatError, getInheritableProperty, info, isArrayBuffer, isBool, | ||||
| @ -28,17 +29,16 @@ import { OperatorList } from './operator_list'; | ||||
| import { PartialEvaluator } from './evaluator'; | ||||
| import { PDFFunctionFactory } from './function'; | ||||
| 
 | ||||
| var Page = (function PageClosure() { | ||||
| 
 | ||||
|   var DEFAULT_USER_UNIT = 1.0; | ||||
|   var LETTER_SIZE_MEDIABOX = [0, 0, 612, 792]; | ||||
| const DEFAULT_USER_UNIT = 1.0; | ||||
| const LETTER_SIZE_MEDIABOX = [0, 0, 612, 792]; | ||||
| 
 | ||||
| function isAnnotationRenderable(annotation, intent) { | ||||
|   return (intent === 'display' && annotation.viewable) || | ||||
|          (intent === 'print' && annotation.printable); | ||||
| } | ||||
| 
 | ||||
|   function Page({ pdfManager, xref, pageIndex, pageDict, ref, fontCache, | ||||
| class Page { | ||||
|   constructor({ pdfManager, xref, pageIndex, pageDict, ref, fontCache, | ||||
|                 builtInCMapCache, pdfFunctionFactory, }) { | ||||
|     this.pdfManager = pdfManager; | ||||
|     this.pageIndex = pageIndex; | ||||
| @ -51,8 +51,8 @@ var Page = (function PageClosure() { | ||||
|     this.evaluatorOptions = pdfManager.evaluatorOptions; | ||||
|     this.resourcesPromise = null; | ||||
| 
 | ||||
|     var uniquePrefix = 'p' + this.pageIndex + '_'; | ||||
|     var idCounters = { | ||||
|     const uniquePrefix = `p${this.pageIndex}_`; | ||||
|     const idCounters = { | ||||
|       obj: 0, | ||||
|     }; | ||||
|     this.idFactory = { | ||||
| @ -62,12 +62,11 @@ var Page = (function PageClosure() { | ||||
|     }; | ||||
|   } | ||||
| 
 | ||||
|   Page.prototype = { | ||||
|   /** | ||||
|    * @private | ||||
|    */ | ||||
|   _getInheritableProperty(key, getArray = false) { | ||||
|       let value = getInheritableProperty({ dict: this.pageDict, key, getArray, | ||||
|     const value = getInheritableProperty({ dict: this.pageDict, key, getArray, | ||||
|                                            stopWhenFound: false, }); | ||||
|     if (!Array.isArray(value)) { | ||||
|       return value; | ||||
| @ -76,124 +75,123 @@ var Page = (function PageClosure() { | ||||
|       return value[0]; | ||||
|     } | ||||
|     return Dict.merge(this.xref, value); | ||||
|     }, | ||||
|   } | ||||
| 
 | ||||
|   get content() { | ||||
|     return this.pageDict.get('Contents'); | ||||
|     }, | ||||
|   } | ||||
| 
 | ||||
|   get resources() { | ||||
|     // For robustness: The spec states that a \Resources entry has to be
 | ||||
|       // present, but can be empty. Some document omit it still, in this case
 | ||||
|     // present, but can be empty. Some documents still omit it; in this case
 | ||||
|     // we return an empty dictionary.
 | ||||
|     return shadow(this, 'resources', | ||||
|                   this._getInheritableProperty('Resources') || Dict.empty); | ||||
|     }, | ||||
|   } | ||||
| 
 | ||||
|   get mediaBox() { | ||||
|       var mediaBox = this._getInheritableProperty('MediaBox', | ||||
|     const mediaBox = this._getInheritableProperty('MediaBox', | ||||
|                                                   /* getArray = */ true); | ||||
|     // Reset invalid media box to letter size.
 | ||||
|     if (!Array.isArray(mediaBox) || mediaBox.length !== 4) { | ||||
|       return shadow(this, 'mediaBox', LETTER_SIZE_MEDIABOX); | ||||
|     } | ||||
|     return shadow(this, 'mediaBox', mediaBox); | ||||
|     }, | ||||
|   } | ||||
| 
 | ||||
|   get cropBox() { | ||||
|       var cropBox = this._getInheritableProperty('CropBox', | ||||
|     const cropBox = this._getInheritableProperty('CropBox', | ||||
|                                                  /* getArray = */ true); | ||||
|     // Reset invalid crop box to media box.
 | ||||
|     if (!Array.isArray(cropBox) || cropBox.length !== 4) { | ||||
|       return shadow(this, 'cropBox', this.mediaBox); | ||||
|     } | ||||
|     return shadow(this, 'cropBox', cropBox); | ||||
|     }, | ||||
|   } | ||||
| 
 | ||||
|   get userUnit() { | ||||
|       var obj = this.pageDict.get('UserUnit'); | ||||
|     let obj = this.pageDict.get('UserUnit'); | ||||
|     if (!isNum(obj) || obj <= 0) { | ||||
|       obj = DEFAULT_USER_UNIT; | ||||
|     } | ||||
|     return shadow(this, 'userUnit', obj); | ||||
|     }, | ||||
|   } | ||||
| 
 | ||||
|   get view() { | ||||
|     // From the spec, 6th ed., p.963:
 | ||||
|     // "The crop, bleed, trim, and art boxes should not ordinarily
 | ||||
|     // extend beyond the boundaries of the media box. If they do, they are
 | ||||
|     // effectively reduced to their intersection with the media box."
 | ||||
|       var mediaBox = this.mediaBox, cropBox = this.cropBox; | ||||
|     const mediaBox = this.mediaBox, cropBox = this.cropBox; | ||||
|     if (mediaBox === cropBox) { | ||||
|       return shadow(this, 'view', mediaBox); | ||||
|     } | ||||
|       var intersection = Util.intersect(cropBox, mediaBox); | ||||
| 
 | ||||
|     const intersection = Util.intersect(cropBox, mediaBox); | ||||
|     return shadow(this, 'view', intersection || mediaBox); | ||||
|     }, | ||||
|   } | ||||
| 
 | ||||
|   get rotate() { | ||||
|       var rotate = this._getInheritableProperty('Rotate') || 0; | ||||
|       // Normalize rotation so it's a multiple of 90 and between 0 and 270
 | ||||
|     let rotate = this._getInheritableProperty('Rotate') || 0; | ||||
| 
 | ||||
|     // Normalize rotation so it's a multiple of 90 and between 0 and 270.
 | ||||
|     if (rotate % 90 !== 0) { | ||||
|       rotate = 0; | ||||
|     } else if (rotate >= 360) { | ||||
|       rotate = rotate % 360; | ||||
|     } else if (rotate < 0) { | ||||
|         // The spec doesn't cover negatives, assume its counterclockwise
 | ||||
|       // The spec doesn't cover negatives. Assume it's counterclockwise
 | ||||
|       // rotation. The following is the other implementation of modulo.
 | ||||
|       rotate = ((rotate % 360) + 360) % 360; | ||||
|     } | ||||
|     return shadow(this, 'rotate', rotate); | ||||
|     }, | ||||
|   } | ||||
| 
 | ||||
|   getContentStream() { | ||||
|     const content = this.content; | ||||
|     let stream; | ||||
| 
 | ||||
|     getContentStream: function Page_getContentStream() { | ||||
|       var content = this.content; | ||||
|       var stream; | ||||
|     if (Array.isArray(content)) { | ||||
|         // fetching items
 | ||||
|         var xref = this.xref; | ||||
|         var i, n = content.length; | ||||
|         var streams = []; | ||||
|         for (i = 0; i < n; ++i) { | ||||
|           streams.push(xref.fetchIfRef(content[i])); | ||||
|       // Fetching the individual streams from the array.
 | ||||
|       const xref = this.xref; | ||||
|       const streams = []; | ||||
|       for (const stream of content) { | ||||
|         streams.push(xref.fetchIfRef(stream)); | ||||
|       } | ||||
|       stream = new StreamsSequenceStream(streams); | ||||
|     } else if (isStream(content)) { | ||||
|       stream = content; | ||||
|     } else { | ||||
|         // replacing non-existent page content with empty one
 | ||||
|       // Replace non-existent page content with empty content.
 | ||||
|       stream = new NullStream(); | ||||
|     } | ||||
|     return stream; | ||||
|     }, | ||||
|   } | ||||
| 
 | ||||
|     loadResources: function Page_loadResources(keys) { | ||||
|   loadResources(keys) { | ||||
|     if (!this.resourcesPromise) { | ||||
|       // TODO: add async `_getInheritableProperty` and remove this.
 | ||||
|       this.resourcesPromise = this.pdfManager.ensure(this, 'resources'); | ||||
|     } | ||||
|     return this.resourcesPromise.then(() => { | ||||
|         let objectLoader = new ObjectLoader(this.resources, keys, this.xref); | ||||
| 
 | ||||
|       const objectLoader = new ObjectLoader(this.resources, keys, this.xref); | ||||
|       return objectLoader.load(); | ||||
|     }); | ||||
|     }, | ||||
|   } | ||||
| 
 | ||||
|   getOperatorList({ handler, task, intent, renderInteractiveForms, }) { | ||||
|       var contentStreamPromise = this.pdfManager.ensure(this, | ||||
|     const contentStreamPromise = this.pdfManager.ensure(this, | ||||
|                                                         'getContentStream'); | ||||
|       var resourcesPromise = this.loadResources([ | ||||
|     const resourcesPromise = this.loadResources([ | ||||
|       'ExtGState', | ||||
|       'ColorSpace', | ||||
|       'Pattern', | ||||
|       'Shading', | ||||
|       'XObject', | ||||
|         'Font' | ||||
|         // ProcSet
 | ||||
|         // Properties
 | ||||
|       'Font', | ||||
|     ]); | ||||
| 
 | ||||
|       var partialEvaluator = new PartialEvaluator({ | ||||
|     const partialEvaluator = new PartialEvaluator({ | ||||
|       pdfManager: this.pdfManager, | ||||
|       xref: this.xref, | ||||
|       handler, | ||||
| @ -205,15 +203,16 @@ var Page = (function PageClosure() { | ||||
|       pdfFunctionFactory: this.pdfFunctionFactory, | ||||
|     }); | ||||
| 
 | ||||
|       var dataPromises = Promise.all([contentStreamPromise, resourcesPromise]); | ||||
|       var pageListPromise = dataPromises.then(([contentStream]) => { | ||||
|         var opList = new OperatorList(intent, handler, this.pageIndex); | ||||
|     const dataPromises = Promise.all([contentStreamPromise, resourcesPromise]); | ||||
|     const pageListPromise = dataPromises.then(([contentStream]) => { | ||||
|       const opList = new OperatorList(intent, handler, this.pageIndex); | ||||
| 
 | ||||
|       handler.send('StartRenderPage', { | ||||
|         transparency: partialEvaluator.hasBlendModes(this.resources), | ||||
|         pageIndex: this.pageIndex, | ||||
|         intent, | ||||
|       }); | ||||
| 
 | ||||
|       return partialEvaluator.getOperatorList({ | ||||
|         stream: contentStream, | ||||
|         task, | ||||
| @ -235,40 +234,39 @@ var Page = (function PageClosure() { | ||||
| 
 | ||||
|       // Collect the operator list promises for the annotations. Each promise
 | ||||
|       // is resolved with the complete operator list for a single annotation.
 | ||||
|         var i, ii, opListPromises = []; | ||||
|         for (i = 0, ii = annotations.length; i < ii; i++) { | ||||
|           if (isAnnotationRenderable(annotations[i], intent)) { | ||||
|             opListPromises.push(annotations[i].getOperatorList( | ||||
|       const opListPromises = []; | ||||
|       for (const annotation of annotations) { | ||||
|         if (isAnnotationRenderable(annotation, intent)) { | ||||
|           opListPromises.push(annotation.getOperatorList( | ||||
|             partialEvaluator, task, renderInteractiveForms)); | ||||
|         } | ||||
|       } | ||||
| 
 | ||||
|       return Promise.all(opListPromises).then(function(opLists) { | ||||
|         pageOpList.addOp(OPS.beginAnnotations, []); | ||||
|           for (i = 0, ii = opLists.length; i < ii; i++) { | ||||
|             pageOpList.addOpList(opLists[i]); | ||||
|         for (const opList of opLists) { | ||||
|           pageOpList.addOpList(opList); | ||||
|         } | ||||
|         pageOpList.addOp(OPS.endAnnotations, []); | ||||
| 
 | ||||
|         pageOpList.flush(true); | ||||
|         return pageOpList; | ||||
|       }); | ||||
|     }); | ||||
|     }, | ||||
|   } | ||||
| 
 | ||||
|     extractTextContent({ handler, task, normalizeWhitespace, | ||||
|                          sink, combineTextItems, }) { | ||||
|       var contentStreamPromise = this.pdfManager.ensure(this, | ||||
|   extractTextContent({ handler, task, normalizeWhitespace, sink, | ||||
|                        combineTextItems, }) { | ||||
|     const contentStreamPromise = this.pdfManager.ensure(this, | ||||
|                                                         'getContentStream'); | ||||
|       var resourcesPromise = this.loadResources([ | ||||
|     const resourcesPromise = this.loadResources([ | ||||
|       'ExtGState', | ||||
|       'XObject', | ||||
|         'Font' | ||||
|       'Font', | ||||
|     ]); | ||||
| 
 | ||||
|       var dataPromises = Promise.all([contentStreamPromise, resourcesPromise]); | ||||
|     const dataPromises = Promise.all([contentStreamPromise, resourcesPromise]); | ||||
|     return dataPromises.then(([contentStream]) => { | ||||
|         var partialEvaluator = new PartialEvaluator({ | ||||
|       const partialEvaluator = new PartialEvaluator({ | ||||
|         pdfManager: this.pdfManager, | ||||
|         xref: this.xref, | ||||
|         handler, | ||||
| @ -289,11 +287,11 @@ var Page = (function PageClosure() { | ||||
|         sink, | ||||
|       }); | ||||
|     }); | ||||
|     }, | ||||
|   } | ||||
| 
 | ||||
|   getAnnotationsData(intent) { | ||||
|     return this._parsedAnnotations.then(function(annotations) { | ||||
|         let annotationsData = []; | ||||
|       const annotationsData = []; | ||||
|       for (let i = 0, ii = annotations.length; i < ii; i++) { | ||||
|         if (!intent || isAnnotationRenderable(annotations[i], intent)) { | ||||
|           annotationsData.push(annotations[i].data); | ||||
| @ -301,12 +299,12 @@ var Page = (function PageClosure() { | ||||
|       } | ||||
|       return annotationsData; | ||||
|     }); | ||||
|     }, | ||||
|   } | ||||
| 
 | ||||
|   get annotations() { | ||||
|     return shadow(this, 'annotations', | ||||
|                   this._getInheritableProperty('Annots') || []); | ||||
|     }, | ||||
|   } | ||||
| 
 | ||||
|   get _parsedAnnotations() { | ||||
|     const parsedAnnotations = | ||||
| @ -329,26 +327,44 @@ var Page = (function PageClosure() { | ||||
|       }); | ||||
| 
 | ||||
|     return shadow(this, '_parsedAnnotations', parsedAnnotations); | ||||
|     }, | ||||
|   }; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
|   return Page; | ||||
| })(); | ||||
| 
 | ||||
| /** | ||||
|  * The `PDFDocument` holds all the data of the PDF file. Compared to the | ||||
|  * `PDFDoc`, this one doesn't have any job management code. | ||||
|  * Right now there exists one PDFDocument on the main thread + one object | ||||
|  * for each worker. If there is no worker support enabled, there are two | ||||
|  * `PDFDocument` objects on the main thread created. | ||||
|  */ | ||||
| var PDFDocument = (function PDFDocumentClosure() { | ||||
|   var FINGERPRINT_FIRST_BYTES = 1024; | ||||
|   var EMPTY_FINGERPRINT = '\x00\x00\x00\x00\x00\x00\x00' + | ||||
| const FINGERPRINT_FIRST_BYTES = 1024; | ||||
| const EMPTY_FINGERPRINT = '\x00\x00\x00\x00\x00\x00\x00' + | ||||
|                           '\x00\x00\x00\x00\x00\x00\x00\x00\x00'; | ||||
| 
 | ||||
|   function PDFDocument(pdfManager, arg) { | ||||
|     var stream; | ||||
| function find(stream, needle, limit, backwards) { | ||||
|   const pos = stream.pos; | ||||
|   const end = stream.end; | ||||
|   if (pos + limit > end) { | ||||
|     limit = end - pos; | ||||
|   } | ||||
| 
 | ||||
|   const strBuf = []; | ||||
|   for (let i = 0; i < limit; ++i) { | ||||
|     strBuf.push(String.fromCharCode(stream.getByte())); | ||||
|   } | ||||
|   const str = strBuf.join(''); | ||||
| 
 | ||||
|   stream.pos = pos; | ||||
|   const index = backwards ? str.lastIndexOf(needle) : str.indexOf(needle); | ||||
|   if (index === -1) { | ||||
|     return false; | ||||
|   } | ||||
|   stream.pos += index; | ||||
|   return true; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * The `PDFDocument` class holds all the data of the PDF file. There exists | ||||
|  * one `PDFDocument` object on the main thread and one object for each worker. | ||||
|  * If no worker support is enabled, two `PDFDocument` objects are created on | ||||
|  * the main thread. | ||||
|  */ | ||||
| class PDFDocument { | ||||
|   constructor(pdfManager, arg) { | ||||
|     let stream; | ||||
|     if (isStream(arg)) { | ||||
|       stream = arg; | ||||
|     } else if (isArrayBuffer(arg)) { | ||||
| @ -357,41 +373,150 @@ var PDFDocument = (function PDFDocumentClosure() { | ||||
|       throw new Error('PDFDocument: Unknown argument type'); | ||||
|     } | ||||
|     if (stream.length <= 0) { | ||||
|       throw new Error('PDFDocument: stream must have data'); | ||||
|       throw new Error('PDFDocument: Stream must have data'); | ||||
|     } | ||||
| 
 | ||||
|     this.pdfManager = pdfManager; | ||||
|     this.stream = stream; | ||||
|     this.xref = new XRef(stream, pdfManager); | ||||
| 
 | ||||
|     let evaluatorOptions = pdfManager.evaluatorOptions; | ||||
|     this.pdfFunctionFactory = new PDFFunctionFactory({ | ||||
|       xref: this.xref, | ||||
|       isEvalSupported: evaluatorOptions.isEvalSupported, | ||||
|       isEvalSupported: pdfManager.evaluatorOptions.isEvalSupported, | ||||
|     }); | ||||
|     this._pagePromises = []; | ||||
|   } | ||||
| 
 | ||||
|   function find(stream, needle, limit, backwards) { | ||||
|     var pos = stream.pos; | ||||
|     var end = stream.end; | ||||
|     var strBuf = []; | ||||
|     if (pos + limit > end) { | ||||
|       limit = end - pos; | ||||
|     } | ||||
|     for (var n = 0; n < limit; ++n) { | ||||
|       strBuf.push(String.fromCharCode(stream.getByte())); | ||||
|     } | ||||
|     var str = strBuf.join(''); | ||||
|     stream.pos = pos; | ||||
|     var index = backwards ? str.lastIndexOf(needle) : str.indexOf(needle); | ||||
|     if (index === -1) { | ||||
|       return false; /* not found */ | ||||
|     } | ||||
|     stream.pos += index; | ||||
|     return true; /* found */ | ||||
|   parse(recoveryMode) { | ||||
|     this.setup(recoveryMode); | ||||
| 
 | ||||
|     const version = this.catalog.catDict.get('Version'); | ||||
|     if (isName(version)) { | ||||
|       this.pdfFormatVersion = version.name; | ||||
|     } | ||||
| 
 | ||||
|     // Check if AcroForms are present in the document.
 | ||||
|     try { | ||||
|       this.acroForm = this.catalog.catDict.get('AcroForm'); | ||||
|       if (this.acroForm) { | ||||
|         this.xfa = this.acroForm.get('XFA'); | ||||
|         const fields = this.acroForm.get('Fields'); | ||||
|         if ((!fields || !Array.isArray(fields) || fields.length === 0) && | ||||
|             !this.xfa) { | ||||
|           this.acroForm = null; // No fields and no XFA, so it's not a form.
 | ||||
|         } | ||||
|       } | ||||
|     } catch (ex) { | ||||
|       if (ex instanceof MissingDataException) { | ||||
|         throw ex; | ||||
|       } | ||||
|       info('Cannot fetch AcroForm entry; assuming no AcroForms are present'); | ||||
|       this.acroForm = null; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   get linearization() { | ||||
|     let linearization = null; | ||||
|     try { | ||||
|       linearization = Linearization.create(this.stream); | ||||
|     } catch (err) { | ||||
|       if (err instanceof MissingDataException) { | ||||
|         throw err; | ||||
|       } | ||||
|       info(err); | ||||
|     } | ||||
|     return shadow(this, 'linearization', linearization); | ||||
|   } | ||||
| 
 | ||||
|   get startXRef() { | ||||
|     const stream = this.stream; | ||||
|     let startXRef = 0; | ||||
| 
 | ||||
|     if (this.linearization) { | ||||
|       // Find the end of the first object.
 | ||||
|       stream.reset(); | ||||
|       if (find(stream, 'endobj', 1024)) { | ||||
|         startXRef = stream.pos + 6; | ||||
|       } | ||||
|     } else { | ||||
|       // Find `startxref` by checking backwards from the end of the file.
 | ||||
|       const step = 1024; | ||||
|       const startXRefLength = 'startxref'.length; | ||||
|       let found = false, pos = stream.end; | ||||
| 
 | ||||
|       while (!found && pos > 0) { | ||||
|         pos -= step - startXRefLength; | ||||
|         if (pos < 0) { | ||||
|           pos = 0; | ||||
|         } | ||||
|         stream.pos = pos; | ||||
|         found = find(stream, 'startxref', step, true); | ||||
|       } | ||||
| 
 | ||||
|       if (found) { | ||||
|         stream.skip(9); | ||||
|         let ch; | ||||
|         do { | ||||
|           ch = stream.getByte(); | ||||
|         } while (isSpace(ch)); | ||||
|         let str = ''; | ||||
|         while (ch >= 0x20 && ch <= 0x39) { // < '9'
 | ||||
|           str += String.fromCharCode(ch); | ||||
|           ch = stream.getByte(); | ||||
|         } | ||||
|         startXRef = parseInt(str, 10); | ||||
|         if (isNaN(startXRef)) { | ||||
|           startXRef = 0; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|     return shadow(this, 'startXRef', startXRef); | ||||
|   } | ||||
| 
 | ||||
|   // Find the header, get the PDF format version and setup the
 | ||||
|   // stream to start from the header.
 | ||||
|   checkHeader() { | ||||
|     const stream = this.stream; | ||||
|     stream.reset(); | ||||
| 
 | ||||
|     if (!find(stream, '%PDF-', 1024)) { | ||||
|       // May not be a PDF file, but don't throw an error and let
 | ||||
|       // parsing continue.
 | ||||
|       return; | ||||
|     } | ||||
|     stream.moveStart(); | ||||
| 
 | ||||
|     // Read the PDF format version.
 | ||||
|     const MAX_PDF_VERSION_LENGTH = 12; | ||||
|     let version = '', ch; | ||||
|     while ((ch = stream.getByte()) > 0x20) { // Space
 | ||||
|       if (version.length >= MAX_PDF_VERSION_LENGTH) { | ||||
|         break; | ||||
|       } | ||||
|       version += String.fromCharCode(ch); | ||||
|     } | ||||
|     if (!this.pdfFormatVersion) { | ||||
|       // Remove the "%PDF-" prefix.
 | ||||
|       this.pdfFormatVersion = version.substring(5); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   parseStartXRef() { | ||||
|     this.xref.setStartXRef(this.startXRef); | ||||
|   } | ||||
| 
 | ||||
|   setup(recoveryMode) { | ||||
|     this.xref.parse(recoveryMode); | ||||
|     this.catalog = new Catalog(this.pdfManager, this.xref); | ||||
|   } | ||||
| 
 | ||||
|   get numPages() { | ||||
|     const linearization = this.linearization; | ||||
|     const num = linearization ? linearization.numPages : this.catalog.numPages; | ||||
|     return shadow(this, 'numPages', num); | ||||
|   } | ||||
| 
 | ||||
|   get documentInfo() { | ||||
|     const DocumentInfoValidators = { | ||||
|       Title: isString, | ||||
|       Author: isString, | ||||
| @ -404,136 +529,13 @@ var PDFDocument = (function PDFDocumentClosure() { | ||||
|       Trapped: isName, | ||||
|     }; | ||||
| 
 | ||||
|   PDFDocument.prototype = { | ||||
|     parse: function PDFDocument_parse(recoveryMode) { | ||||
|       this.setup(recoveryMode); | ||||
|       var version = this.catalog.catDict.get('Version'); | ||||
|       if (isName(version)) { | ||||
|         this.pdfFormatVersion = version.name; | ||||
|       } | ||||
|       try { | ||||
|         // checking if AcroForm is present
 | ||||
|         this.acroForm = this.catalog.catDict.get('AcroForm'); | ||||
|         if (this.acroForm) { | ||||
|           this.xfa = this.acroForm.get('XFA'); | ||||
|           var fields = this.acroForm.get('Fields'); | ||||
|           if ((!fields || !Array.isArray(fields) || fields.length === 0) && | ||||
|               !this.xfa) { | ||||
|             // no fields and no XFA -- not a form (?)
 | ||||
|             this.acroForm = null; | ||||
|           } | ||||
|         } | ||||
|       } catch (ex) { | ||||
|         if (ex instanceof MissingDataException) { | ||||
|           throw ex; | ||||
|         } | ||||
|         info('Something wrong with AcroForm entry'); | ||||
|         this.acroForm = null; | ||||
|       } | ||||
|     }, | ||||
| 
 | ||||
|     get linearization() { | ||||
|       let linearization = null; | ||||
|       try { | ||||
|         linearization = Linearization.create(this.stream); | ||||
|       } catch (err) { | ||||
|         if (err instanceof MissingDataException) { | ||||
|           throw err; | ||||
|         } | ||||
|         info(err); | ||||
|       } | ||||
|       // shadow the prototype getter with a data property
 | ||||
|       return shadow(this, 'linearization', linearization); | ||||
|     }, | ||||
|     get startXRef() { | ||||
|       var stream = this.stream; | ||||
|       var startXRef = 0; | ||||
|       var linearization = this.linearization; | ||||
|       if (linearization) { | ||||
|         // Find end of first obj.
 | ||||
|         stream.reset(); | ||||
|         if (find(stream, 'endobj', 1024)) { | ||||
|           startXRef = stream.pos + 6; | ||||
|         } | ||||
|       } else { | ||||
|         // Find startxref by jumping backward from the end of the file.
 | ||||
|         var step = 1024; | ||||
|         var found = false, pos = stream.end; | ||||
|         while (!found && pos > 0) { | ||||
|           pos -= step - 'startxref'.length; | ||||
|           if (pos < 0) { | ||||
|             pos = 0; | ||||
|           } | ||||
|           stream.pos = pos; | ||||
|           found = find(stream, 'startxref', step, true); | ||||
|         } | ||||
|         if (found) { | ||||
|           stream.skip(9); | ||||
|           var ch; | ||||
|           do { | ||||
|             ch = stream.getByte(); | ||||
|           } while (isSpace(ch)); | ||||
|           var str = ''; | ||||
|           while (ch >= 0x20 && ch <= 0x39) { // < '9'
 | ||||
|             str += String.fromCharCode(ch); | ||||
|             ch = stream.getByte(); | ||||
|           } | ||||
|           startXRef = parseInt(str, 10); | ||||
|           if (isNaN(startXRef)) { | ||||
|             startXRef = 0; | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|       // shadow the prototype getter with a data property
 | ||||
|       return shadow(this, 'startXRef', startXRef); | ||||
|     }, | ||||
| 
 | ||||
|     // Find the header, remove leading garbage and setup the stream
 | ||||
|     // starting from the header.
 | ||||
|     checkHeader: function PDFDocument_checkHeader() { | ||||
|       var stream = this.stream; | ||||
|       stream.reset(); | ||||
|       if (find(stream, '%PDF-', 1024)) { | ||||
|         // Found the header, trim off any garbage before it.
 | ||||
|         stream.moveStart(); | ||||
|         // Reading file format version
 | ||||
|         var MAX_VERSION_LENGTH = 12; | ||||
|         var version = '', ch; | ||||
|         while ((ch = stream.getByte()) > 0x20) { // SPACE
 | ||||
|           if (version.length >= MAX_VERSION_LENGTH) { | ||||
|             break; | ||||
|           } | ||||
|           version += String.fromCharCode(ch); | ||||
|         } | ||||
|         if (!this.pdfFormatVersion) { | ||||
|           // removing "%PDF-"-prefix
 | ||||
|           this.pdfFormatVersion = version.substring(5); | ||||
|         } | ||||
|         return; | ||||
|       } | ||||
|       // May not be a PDF file, continue anyway.
 | ||||
|     }, | ||||
|     parseStartXRef: function PDFDocument_parseStartXRef() { | ||||
|       var startXRef = this.startXRef; | ||||
|       this.xref.setStartXRef(startXRef); | ||||
|     }, | ||||
|     setup: function PDFDocument_setup(recoveryMode) { | ||||
|       this.xref.parse(recoveryMode); | ||||
|       this.catalog = new Catalog(this.pdfManager, this.xref); | ||||
|     }, | ||||
|     get numPages() { | ||||
|       var linearization = this.linearization; | ||||
|       var num = linearization ? linearization.numPages : this.catalog.numPages; | ||||
|       // shadow the prototype getter
 | ||||
|       return shadow(this, 'numPages', num); | ||||
|     }, | ||||
|     get documentInfo() { | ||||
|     const docInfo = { | ||||
|       PDFFormatVersion: this.pdfFormatVersion, | ||||
|       IsLinearized: !!this.linearization, | ||||
|       IsAcroFormPresent: !!this.acroForm, | ||||
|       IsXFAPresent: !!this.xfa, | ||||
|     }; | ||||
| 
 | ||||
|     let infoDict; | ||||
|     try { | ||||
|       infoDict = this.xref.trailer.get('Info'); | ||||
| @ -543,10 +545,11 @@ var PDFDocument = (function PDFDocumentClosure() { | ||||
|       } | ||||
|       info('The document information dictionary is invalid.'); | ||||
|     } | ||||
| 
 | ||||
|     if (isDict(infoDict)) { | ||||
|       // Fill the document info with valid entries from the specification,
 | ||||
|       // as well as any existing well-formed custom entries.
 | ||||
|         for (let key of infoDict.getKeys()) { | ||||
|       for (const key of infoDict.getKeys()) { | ||||
|         const value = infoDict.get(key); | ||||
| 
 | ||||
|         if (DocumentInfoValidators[key]) { | ||||
| @ -579,11 +582,11 @@ var PDFDocument = (function PDFDocumentClosure() { | ||||
|       } | ||||
|     } | ||||
|     return shadow(this, 'documentInfo', docInfo); | ||||
|     }, | ||||
|     get fingerprint() { | ||||
|       var xref = this.xref, hash, fileID = ''; | ||||
|       var idArray = xref.trailer.get('ID'); | ||||
|   } | ||||
| 
 | ||||
|   get fingerprint() { | ||||
|     let hash; | ||||
|     const idArray = this.xref.trailer.get('ID'); | ||||
|     if (Array.isArray(idArray) && idArray[0] && isString(idArray[0]) && | ||||
|         idArray[0] !== EMPTY_FINGERPRINT) { | ||||
|       hash = stringToBytes(idArray[0]); | ||||
| @ -596,13 +599,13 @@ var PDFDocument = (function PDFDocumentClosure() { | ||||
|         FINGERPRINT_FIRST_BYTES), 0, FINGERPRINT_FIRST_BYTES); | ||||
|     } | ||||
| 
 | ||||
|       for (var i = 0, n = hash.length; i < n; i++) { | ||||
|         var hex = hash[i].toString(16); | ||||
|         fileID += hex.length === 1 ? '0' + hex : hex; | ||||
|     let fingerprint = ''; | ||||
|     for (const hashPart of hash) { | ||||
|       const hex = hashPart.toString(16); | ||||
|       fingerprint += (hex.length === 1 ? '0' + hex : hex); | ||||
|     } | ||||
|     return shadow(this, 'fingerprint', fingerprint); | ||||
|   } | ||||
| 
 | ||||
|       return shadow(this, 'fingerprint', fileID); | ||||
|     }, | ||||
| 
 | ||||
|   _getLinearizationPage(pageIndex) { | ||||
|     const { catalog, linearization, } = this; | ||||
| @ -624,7 +627,7 @@ var PDFDocument = (function PDFDocumentClosure() { | ||||
|       info(reason); | ||||
|       return catalog.getPageDict(pageIndex); | ||||
|     }); | ||||
|     }, | ||||
|   } | ||||
| 
 | ||||
|   getPage(pageIndex) { | ||||
|     if (this._pagePromises[pageIndex] !== undefined) { | ||||
| @ -647,7 +650,7 @@ var PDFDocument = (function PDFDocumentClosure() { | ||||
|         pdfFunctionFactory: this.pdfFunctionFactory, | ||||
|       }); | ||||
|     }); | ||||
|     }, | ||||
|   } | ||||
| 
 | ||||
|   checkFirstPage() { | ||||
|     return this.getPage(0).catch((reason) => { | ||||
| @ -661,15 +664,12 @@ var PDFDocument = (function PDFDocumentClosure() { | ||||
|         throw new XRefParseException(); | ||||
|       } | ||||
|     }); | ||||
|     }, | ||||
|   } | ||||
| 
 | ||||
|     cleanup: function PDFDocument_cleanup() { | ||||
|   cleanup() { | ||||
|     return this.catalog.cleanup(); | ||||
|     }, | ||||
|   }; | ||||
| 
 | ||||
|   return PDFDocument; | ||||
| })(); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| export { | ||||
|   Page, | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user