UNPKG

pdfjs-dist

Version:

Generic build of Mozilla's PDF.js library.

1,733 lines (1,403 loc) • 114 kB
/** * @licstart The following is the entire license notice for the * Javascript code in this page * * Copyright 2021 Mozilla Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @licend The above is the entire license notice for the * Javascript code in this page */ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.PartialEvaluator = exports.EvaluatorPreprocessor = void 0; var _util = require("../shared/util.js"); var _cmap = require("./cmap.js"); var _primitives = require("./primitives.js"); var _stream = require("./stream.js"); var _fonts = require("./fonts.js"); var _encodings = require("./encodings.js"); var _unicode = require("./unicode.js"); var _standard_fonts = require("./standard_fonts.js"); var _pattern = require("./pattern.js"); var _function = require("./function.js"); var _parser = require("./parser.js"); var _image_utils = require("./image_utils.js"); var _bidi = require("./bidi.js"); var _colorspace = require("./colorspace.js"); var _glyphlist = require("./glyphlist.js"); var _core_utils = require("./core_utils.js"); var _metrics = require("./metrics.js"); var _murmurhash = require("./murmurhash3.js"); var _operator_list = require("./operator_list.js"); var _image = require("./image.js"); const DefaultPartialEvaluatorOptions = Object.freeze({ maxImageSize: -1, disableFontFace: false, ignoreErrors: false, isEvalSupported: true, fontExtraProperties: false }); const PatternType = { TILING: 1, SHADING: 2 }; const deferred = Promise.resolve(); function normalizeBlendMode(value, parsingArray = false) { if (Array.isArray(value)) { for (let i = 0, ii = value.length; i < ii; i++) { const maybeBM = normalizeBlendMode(value[i], true); if (maybeBM) { return maybeBM; } } (0, _util.warn)(`Unsupported blend mode Array: ${value}`); return "source-over"; } if (!(0, _primitives.isName)(value)) { if (parsingArray) { return null; } return "source-over"; } switch (value.name) { case "Normal": case "Compatible": return "source-over"; case "Multiply": return "multiply"; case "Screen": return "screen"; case "Overlay": return "overlay"; case "Darken": return "darken"; case "Lighten": return "lighten"; case "ColorDodge": return "color-dodge"; case "ColorBurn": return "color-burn"; case "HardLight": return "hard-light"; case "SoftLight": return "soft-light"; case "Difference": return "difference"; case "Exclusion": return "exclusion"; case "Hue": return "hue"; case "Saturation": return "saturation"; case "Color": return "color"; case "Luminosity": return "luminosity"; } if (parsingArray) { return null; } (0, _util.warn)(`Unsupported blend mode: ${value.name}`); return "source-over"; } class TimeSlotManager { static get TIME_SLOT_DURATION_MS() { return (0, _util.shadow)(this, "TIME_SLOT_DURATION_MS", 20); } static get CHECK_TIME_EVERY() { return (0, _util.shadow)(this, "CHECK_TIME_EVERY", 100); } constructor() { this.reset(); } check() { if (++this.checked < TimeSlotManager.CHECK_TIME_EVERY) { return false; } this.checked = 0; return this.endTime <= Date.now(); } reset() { this.endTime = Date.now() + TimeSlotManager.TIME_SLOT_DURATION_MS; this.checked = 0; } } class PartialEvaluator { constructor({ xref, handler, pageIndex, idFactory, fontCache, builtInCMapCache, globalImageCache, options = null }) { this.xref = xref; this.handler = handler; this.pageIndex = pageIndex; this.idFactory = idFactory; this.fontCache = fontCache; this.builtInCMapCache = builtInCMapCache; this.globalImageCache = globalImageCache; this.options = options || DefaultPartialEvaluatorOptions; this.parsingType3Font = false; this._fetchBuiltInCMapBound = this.fetchBuiltInCMap.bind(this); } get _pdfFunctionFactory() { const pdfFunctionFactory = new _function.PDFFunctionFactory({ xref: this.xref, isEvalSupported: this.options.isEvalSupported }); return (0, _util.shadow)(this, "_pdfFunctionFactory", pdfFunctionFactory); } clone(newOptions = DefaultPartialEvaluatorOptions) { var newEvaluator = Object.create(this); newEvaluator.options = newOptions; return newEvaluator; } hasBlendModes(resources, nonBlendModesSet) { if (!(resources instanceof _primitives.Dict)) { return false; } if (resources.objId && nonBlendModesSet.has(resources.objId)) { return false; } const processed = new _primitives.RefSet(nonBlendModesSet); if (resources.objId) { processed.put(resources.objId); } var nodes = [resources], xref = this.xref; while (nodes.length) { var node = nodes.shift(); var graphicStates = node.get("ExtGState"); if (graphicStates instanceof _primitives.Dict) { for (let graphicState of graphicStates.getRawValues()) { if (graphicState instanceof _primitives.Ref) { if (processed.has(graphicState)) { continue; } try { graphicState = xref.fetch(graphicState); } catch (ex) { processed.put(graphicState); (0, _util.info)(`hasBlendModes - ignoring ExtGState: "${ex}".`); continue; } } if (!(graphicState instanceof _primitives.Dict)) { continue; } if (graphicState.objId) { processed.put(graphicState.objId); } const bm = graphicState.get("BM"); if (bm instanceof _primitives.Name) { if (bm.name !== "Normal") { return true; } continue; } if (bm !== undefined && Array.isArray(bm)) { for (const element of bm) { if (element instanceof _primitives.Name && element.name !== "Normal") { return true; } } } } } var xObjects = node.get("XObject"); if (!(xObjects instanceof _primitives.Dict)) { continue; } for (let xObject of xObjects.getRawValues()) { if (xObject instanceof _primitives.Ref) { if (processed.has(xObject)) { continue; } try { xObject = xref.fetch(xObject); } catch (ex) { processed.put(xObject); (0, _util.info)(`hasBlendModes - ignoring XObject: "${ex}".`); continue; } } if (!(0, _primitives.isStream)(xObject)) { continue; } if (xObject.dict.objId) { processed.put(xObject.dict.objId); } var xResources = xObject.dict.get("Resources"); if (!(xResources instanceof _primitives.Dict)) { continue; } if (xResources.objId && processed.has(xResources.objId)) { continue; } nodes.push(xResources); if (xResources.objId) { processed.put(xResources.objId); } } } processed.forEach(ref => { nonBlendModesSet.put(ref); }); return false; } async fetchBuiltInCMap(name) { const cachedData = this.builtInCMapCache.get(name); if (cachedData) { return cachedData; } const readableStream = this.handler.sendWithStream("FetchBuiltInCMap", { name }); const reader = readableStream.getReader(); const data = await new Promise(function (resolve, reject) { function pump() { reader.read().then(function ({ value, done }) { if (done) { return; } resolve(value); pump(); }, reject); } pump(); }); if (data.compressionType !== _util.CMapCompressionType.NONE) { this.builtInCMapCache.set(name, data); } return data; } async buildFormXObject(resources, xobj, smask, operatorList, task, initialState, localColorSpaceCache) { var dict = xobj.dict; var matrix = dict.getArray("Matrix"); var bbox = dict.getArray("BBox"); if (Array.isArray(bbox) && bbox.length === 4) { bbox = _util.Util.normalizeRect(bbox); } else { bbox = null; } let optionalContent = null; if (dict.has("OC")) { optionalContent = await this.parseMarkedContentProps(dict.get("OC"), resources); operatorList.addOp(_util.OPS.beginMarkedContentProps, ["OC", optionalContent]); } var group = dict.get("Group"); if (group) { var groupOptions = { matrix, bbox, smask, isolated: false, knockout: false }; var groupSubtype = group.get("S"); var colorSpace = null; if ((0, _primitives.isName)(groupSubtype, "Transparency")) { groupOptions.isolated = group.get("I") || false; groupOptions.knockout = group.get("K") || false; if (group.has("CS")) { const cs = group.getRaw("CS"); const cachedColorSpace = _colorspace.ColorSpace.getCached(cs, this.xref, localColorSpaceCache); if (cachedColorSpace) { colorSpace = cachedColorSpace; } else { colorSpace = await this.parseColorSpace({ cs, resources, localColorSpaceCache }); } } } if (smask && smask.backdrop) { colorSpace = colorSpace || _colorspace.ColorSpace.singletons.rgb; smask.backdrop = colorSpace.getRgb(smask.backdrop, 0); } operatorList.addOp(_util.OPS.beginGroup, [groupOptions]); } operatorList.addOp(_util.OPS.paintFormXObjectBegin, [matrix, bbox]); return this.getOperatorList({ stream: xobj, task, resources: dict.get("Resources") || resources, operatorList, initialState }).then(function () { operatorList.addOp(_util.OPS.paintFormXObjectEnd, []); if (group) { operatorList.addOp(_util.OPS.endGroup, [groupOptions]); } if (optionalContent) { operatorList.addOp(_util.OPS.endMarkedContent, []); } }); } _sendImgData(objId, imgData, cacheGlobally = false) { const transfers = imgData ? [imgData.data.buffer] : null; if (this.parsingType3Font || cacheGlobally) { return this.handler.send("commonobj", [objId, "Image", imgData], transfers); } return this.handler.send("obj", [objId, this.pageIndex, "Image", imgData], transfers); } async buildPaintImageXObject({ resources, image, isInline = false, operatorList, cacheKey, localImageCache, localColorSpaceCache }) { var dict = image.dict; const imageRef = dict.objId; var w = dict.get("Width", "W"); var h = dict.get("Height", "H"); if (!(w && (0, _util.isNum)(w)) || !(h && (0, _util.isNum)(h))) { (0, _util.warn)("Image dimensions are missing, or not numbers."); return undefined; } var maxImageSize = this.options.maxImageSize; if (maxImageSize !== -1 && w * h > maxImageSize) { (0, _util.warn)("Image exceeded maximum allowed size and was removed."); return undefined; } var imageMask = dict.get("ImageMask", "IM") || false; var imgData, args; if (imageMask) { var width = dict.get("Width", "W"); var height = dict.get("Height", "H"); var bitStrideLength = width + 7 >> 3; var imgArray = image.getBytes(bitStrideLength * height, true); var decode = dict.getArray("Decode", "D"); imgData = _image.PDFImage.createMask({ imgArray, width, height, imageIsFromDecodeStream: image instanceof _stream.DecodeStream, inverseDecode: !!decode && decode[0] > 0 }); imgData.cached = !!cacheKey; args = [imgData]; operatorList.addOp(_util.OPS.paintImageMaskXObject, args); if (cacheKey) { localImageCache.set(cacheKey, imageRef, { fn: _util.OPS.paintImageMaskXObject, args }); } return undefined; } var softMask = dict.get("SMask", "SM") || false; var mask = dict.get("Mask") || false; var SMALL_IMAGE_DIMENSIONS = 200; if (isInline && !softMask && !mask && w + h < SMALL_IMAGE_DIMENSIONS) { const imageObj = new _image.PDFImage({ xref: this.xref, res: resources, image, isInline, pdfFunctionFactory: this._pdfFunctionFactory, localColorSpaceCache }); imgData = imageObj.createImageData(true); operatorList.addOp(_util.OPS.paintInlineImageXObject, [imgData]); return undefined; } let objId = `img_${this.idFactory.createObjId()}`, cacheGlobally = false; if (this.parsingType3Font) { objId = `${this.idFactory.getDocId()}_type3_${objId}`; } else if (imageRef) { cacheGlobally = this.globalImageCache.shouldCache(imageRef, this.pageIndex); if (cacheGlobally) { objId = `${this.idFactory.getDocId()}_${objId}`; } } operatorList.addDependency(objId); args = [objId, w, h]; _image.PDFImage.buildImage({ xref: this.xref, res: resources, image, isInline, pdfFunctionFactory: this._pdfFunctionFactory, localColorSpaceCache }).then(imageObj => { imgData = imageObj.createImageData(false); if (cacheKey && imageRef && cacheGlobally) { this.globalImageCache.addByteSize(imageRef, imgData.data.length); } return this._sendImgData(objId, imgData, cacheGlobally); }).catch(reason => { (0, _util.warn)(`Unable to decode image "${objId}": "${reason}".`); return this._sendImgData(objId, null, cacheGlobally); }); operatorList.addOp(_util.OPS.paintImageXObject, args); if (cacheKey) { localImageCache.set(cacheKey, imageRef, { fn: _util.OPS.paintImageXObject, args }); if (imageRef) { (0, _util.assert)(!isInline, "Cannot cache an inline image globally."); this.globalImageCache.addPageIndex(imageRef, this.pageIndex); if (cacheGlobally) { this.globalImageCache.setData(imageRef, { objId, fn: _util.OPS.paintImageXObject, args, byteSize: 0 }); } } } return undefined; } handleSMask(smask, resources, operatorList, task, stateManager, localColorSpaceCache) { var smaskContent = smask.get("G"); var smaskOptions = { subtype: smask.get("S").name, backdrop: smask.get("BC") }; var transferObj = smask.get("TR"); if ((0, _function.isPDFFunction)(transferObj)) { const transferFn = this._pdfFunctionFactory.create(transferObj); var transferMap = new Uint8Array(256); var tmp = new Float32Array(1); for (var i = 0; i < 256; i++) { tmp[0] = i / 255; transferFn(tmp, 0, tmp, 0); transferMap[i] = tmp[0] * 255 | 0; } smaskOptions.transferMap = transferMap; } return this.buildFormXObject(resources, smaskContent, smaskOptions, operatorList, task, stateManager.state.clone(), localColorSpaceCache); } handleTransferFunction(tr) { let transferArray; if (Array.isArray(tr)) { transferArray = tr; } else if ((0, _function.isPDFFunction)(tr)) { transferArray = [tr]; } else { return null; } const transferMaps = []; let numFns = 0, numEffectfulFns = 0; for (const entry of transferArray) { const transferObj = this.xref.fetchIfRef(entry); numFns++; if ((0, _primitives.isName)(transferObj, "Identity")) { transferMaps.push(null); continue; } else if (!(0, _function.isPDFFunction)(transferObj)) { return null; } const transferFn = this._pdfFunctionFactory.create(transferObj); const transferMap = new Uint8Array(256), tmp = new Float32Array(1); for (let j = 0; j < 256; j++) { tmp[0] = j / 255; transferFn(tmp, 0, tmp, 0); transferMap[j] = tmp[0] * 255 | 0; } transferMaps.push(transferMap); numEffectfulFns++; } if (!(numFns === 1 || numFns === 4)) { return null; } if (numEffectfulFns === 0) { return null; } return transferMaps; } handleTilingType(fn, color, resources, pattern, patternDict, operatorList, task, cacheKey, localTilingPatternCache) { const tilingOpList = new _operator_list.OperatorList(); const patternResources = _primitives.Dict.merge({ xref: this.xref, dictArray: [patternDict.get("Resources"), resources] }); return this.getOperatorList({ stream: pattern, task, resources: patternResources, operatorList: tilingOpList }).then(function () { const operatorListIR = tilingOpList.getIR(); const tilingPatternIR = (0, _pattern.getTilingPatternIR)(operatorListIR, patternDict, color); operatorList.addDependencies(tilingOpList.dependencies); operatorList.addOp(fn, tilingPatternIR); if (cacheKey) { localTilingPatternCache.set(cacheKey, patternDict.objId, { operatorListIR, dict: patternDict }); } }).catch(reason => { if (reason instanceof _util.AbortException) { return; } if (this.options.ignoreErrors) { this.handler.send("UnsupportedFeature", { featureId: _util.UNSUPPORTED_FEATURES.errorTilingPattern }); (0, _util.warn)(`handleTilingType - ignoring pattern: "${reason}".`); return; } throw reason; }); } handleSetFont(resources, fontArgs, fontRef, operatorList, task, state, fallbackFontDict = null) { const fontName = fontArgs && fontArgs[0] instanceof _primitives.Name ? fontArgs[0].name : null; return this.loadFont(fontName, fontRef, resources, fallbackFontDict).then(translated => { if (!translated.font.isType3Font) { return translated; } return translated.loadType3Data(this, resources, task).then(function () { operatorList.addDependencies(translated.type3Dependencies); return translated; }).catch(reason => { this.handler.send("UnsupportedFeature", { featureId: _util.UNSUPPORTED_FEATURES.errorFontLoadType3 }); return new TranslatedFont({ loadedName: "g_font_error", font: new _fonts.ErrorFont(`Type3 font load error: ${reason}`), dict: translated.font, extraProperties: this.options.fontExtraProperties }); }); }).then(translated => { state.font = translated.font; translated.send(this.handler); return translated.loadedName; }); } handleText(chars, state) { const font = state.font; const glyphs = font.charsToGlyphs(chars); if (font.data) { const isAddToPathSet = !!(state.textRenderingMode & _util.TextRenderingMode.ADD_TO_PATH_FLAG); if (isAddToPathSet || state.fillColorSpace.name === "Pattern" || font.disableFontFace || this.options.disableFontFace) { PartialEvaluator.buildFontPaths(font, glyphs, this.handler); } } return glyphs; } ensureStateFont(state) { if (state.font) { return; } const reason = new _util.FormatError("Missing setFont (Tf) operator before text rendering operator."); if (this.options.ignoreErrors) { this.handler.send("UnsupportedFeature", { featureId: _util.UNSUPPORTED_FEATURES.errorFontState }); (0, _util.warn)(`ensureStateFont: "${reason}".`); return; } throw reason; } async setGState({ resources, gState, operatorList, cacheKey, task, stateManager, localGStateCache, localColorSpaceCache }) { const gStateRef = gState.objId; let isSimpleGState = true; var gStateObj = []; var gStateKeys = gState.getKeys(); var promise = Promise.resolve(); for (var i = 0, ii = gStateKeys.length; i < ii; i++) { const key = gStateKeys[i]; const value = gState.get(key); switch (key) { case "Type": break; case "LW": case "LC": case "LJ": case "ML": case "D": case "RI": case "FL": case "CA": case "ca": gStateObj.push([key, value]); break; case "Font": isSimpleGState = false; promise = promise.then(() => { return this.handleSetFont(resources, null, value[0], operatorList, task, stateManager.state).then(function (loadedName) { operatorList.addDependency(loadedName); gStateObj.push([key, [loadedName, value[1]]]); }); }); break; case "BM": gStateObj.push([key, normalizeBlendMode(value)]); break; case "SMask": if ((0, _primitives.isName)(value, "None")) { gStateObj.push([key, false]); break; } if ((0, _primitives.isDict)(value)) { isSimpleGState = false; promise = promise.then(() => { return this.handleSMask(value, resources, operatorList, task, stateManager, localColorSpaceCache); }); gStateObj.push([key, true]); } else { (0, _util.warn)("Unsupported SMask type"); } break; case "TR": const transferMaps = this.handleTransferFunction(value); gStateObj.push([key, transferMaps]); break; case "OP": case "op": case "OPM": case "BG": case "BG2": case "UCR": case "UCR2": case "TR2": case "HT": case "SM": case "SA": case "AIS": case "TK": (0, _util.info)("graphic state operator " + key); break; default: (0, _util.info)("Unknown graphic state operator " + key); break; } } return promise.then(function () { if (gStateObj.length > 0) { operatorList.addOp(_util.OPS.setGState, [gStateObj]); } if (isSimpleGState) { localGStateCache.set(cacheKey, gStateRef, gStateObj); } }); } loadFont(fontName, font, resources, fallbackFontDict = null) { const errorFont = async () => { return new TranslatedFont({ loadedName: "g_font_error", font: new _fonts.ErrorFont(`Font "${fontName}" is not available.`), dict: font, extraProperties: this.options.fontExtraProperties }); }; var fontRef, xref = this.xref; if (font) { if (!(0, _primitives.isRef)(font)) { throw new _util.FormatError('The "font" object should be a reference.'); } fontRef = font; } else { var fontRes = resources.get("Font"); if (fontRes) { fontRef = fontRes.getRaw(fontName); } } if (!fontRef) { const partialMsg = `Font "${fontName || font && font.toString()}" is not available`; if (!this.options.ignoreErrors && !this.parsingType3Font) { (0, _util.warn)(`${partialMsg}.`); return errorFont(); } this.handler.send("UnsupportedFeature", { featureId: _util.UNSUPPORTED_FEATURES.errorFontMissing }); (0, _util.warn)(`${partialMsg} -- attempting to fallback to a default font.`); if (fallbackFontDict) { fontRef = fallbackFontDict; } else { fontRef = PartialEvaluator.fallbackFontDict; } } if (this.fontCache.has(fontRef)) { return this.fontCache.get(fontRef); } font = xref.fetchIfRef(fontRef); if (!(0, _primitives.isDict)(font)) { return errorFont(); } if (font.cacheKey && this.fontCache.has(font.cacheKey)) { return this.fontCache.get(font.cacheKey); } var fontCapability = (0, _util.createPromiseCapability)(); let preEvaluatedFont; try { preEvaluatedFont = this.preEvaluateFont(font); } catch (reason) { (0, _util.warn)(`loadFont - preEvaluateFont failed: "${reason}".`); return errorFont(); } const { descriptor, hash } = preEvaluatedFont; var fontRefIsRef = (0, _primitives.isRef)(fontRef), fontID; if (fontRefIsRef) { fontID = `f${fontRef.toString()}`; } if (hash && (0, _primitives.isDict)(descriptor)) { if (!descriptor.fontAliases) { descriptor.fontAliases = Object.create(null); } var fontAliases = descriptor.fontAliases; if (fontAliases[hash]) { var aliasFontRef = fontAliases[hash].aliasRef; if (fontRefIsRef && aliasFontRef && this.fontCache.has(aliasFontRef)) { this.fontCache.putAlias(fontRef, aliasFontRef); return this.fontCache.get(fontRef); } } else { fontAliases[hash] = { fontID: this.idFactory.createFontId() }; } if (fontRefIsRef) { fontAliases[hash].aliasRef = fontRef; } fontID = fontAliases[hash].fontID; } if (fontRefIsRef) { this.fontCache.put(fontRef, fontCapability.promise); } else { if (!fontID) { fontID = this.idFactory.createFontId(); } font.cacheKey = `cacheKey_${fontID}`; this.fontCache.put(font.cacheKey, fontCapability.promise); } (0, _util.assert)(fontID && fontID.startsWith("f"), 'The "fontID" must be (correctly) defined.'); font.loadedName = `${this.idFactory.getDocId()}_${fontID}`; this.translateFont(preEvaluatedFont).then(translatedFont => { if (translatedFont.fontType !== undefined) { var xrefFontStats = xref.stats.fontTypes; xrefFontStats[translatedFont.fontType] = true; } fontCapability.resolve(new TranslatedFont({ loadedName: font.loadedName, font: translatedFont, dict: font, extraProperties: this.options.fontExtraProperties })); }).catch(reason => { this.handler.send("UnsupportedFeature", { featureId: _util.UNSUPPORTED_FEATURES.errorFontTranslate }); (0, _util.warn)(`loadFont - translateFont failed: "${reason}".`); try { var fontFile3 = descriptor && descriptor.get("FontFile3"); var subtype = fontFile3 && fontFile3.get("Subtype"); var fontType = (0, _fonts.getFontType)(preEvaluatedFont.type, subtype && subtype.name); var xrefFontStats = xref.stats.fontTypes; xrefFontStats[fontType] = true; } catch (ex) {} fontCapability.resolve(new TranslatedFont({ loadedName: font.loadedName, font: new _fonts.ErrorFont(reason instanceof Error ? reason.message : reason), dict: font, extraProperties: this.options.fontExtraProperties })); }); return fontCapability.promise; } buildPath(operatorList, fn, args, parsingText = false) { var lastIndex = operatorList.length - 1; if (!args) { args = []; } if (lastIndex < 0 || operatorList.fnArray[lastIndex] !== _util.OPS.constructPath) { if (parsingText) { (0, _util.warn)(`Encountered path operator "${fn}" inside of a text object.`); operatorList.addOp(_util.OPS.save, null); } operatorList.addOp(_util.OPS.constructPath, [[fn], args]); if (parsingText) { operatorList.addOp(_util.OPS.restore, null); } } else { var opArgs = operatorList.argsArray[lastIndex]; opArgs[0].push(fn); Array.prototype.push.apply(opArgs[1], args); } } parseColorSpace({ cs, resources, localColorSpaceCache }) { return _colorspace.ColorSpace.parseAsync({ cs, xref: this.xref, resources, pdfFunctionFactory: this._pdfFunctionFactory, localColorSpaceCache }).catch(reason => { if (reason instanceof _util.AbortException) { return null; } if (this.options.ignoreErrors) { this.handler.send("UnsupportedFeature", { featureId: _util.UNSUPPORTED_FEATURES.errorColorSpace }); (0, _util.warn)(`parseColorSpace - ignoring ColorSpace: "${reason}".`); return null; } throw reason; }); } handleColorN(operatorList, fn, args, cs, patterns, resources, task, localColorSpaceCache, localTilingPatternCache) { const patternName = args.pop(); if (patternName instanceof _primitives.Name) { const name = patternName.name; const localTilingPattern = localTilingPatternCache.getByName(name); if (localTilingPattern) { try { const color = cs.base ? cs.base.getRgb(args, 0) : null; const tilingPatternIR = (0, _pattern.getTilingPatternIR)(localTilingPattern.operatorListIR, localTilingPattern.dict, color); operatorList.addOp(fn, tilingPatternIR); return undefined; } catch (ex) {} } let pattern = patterns.get(name); if (pattern) { var dict = (0, _primitives.isStream)(pattern) ? pattern.dict : pattern; var typeNum = dict.get("PatternType"); if (typeNum === PatternType.TILING) { const color = cs.base ? cs.base.getRgb(args, 0) : null; return this.handleTilingType(fn, color, resources, pattern, dict, operatorList, task, name, localTilingPatternCache); } else if (typeNum === PatternType.SHADING) { var shading = dict.get("Shading"); var matrix = dict.getArray("Matrix"); pattern = _pattern.Pattern.parseShading(shading, matrix, this.xref, resources, this.handler, this._pdfFunctionFactory, localColorSpaceCache); operatorList.addOp(fn, pattern.getIR()); return undefined; } throw new _util.FormatError(`Unknown PatternType: ${typeNum}`); } } throw new _util.FormatError(`Unknown PatternName: ${patternName}`); } async parseMarkedContentProps(contentProperties, resources) { let optionalContent; if ((0, _primitives.isName)(contentProperties)) { const properties = resources.get("Properties"); optionalContent = properties.get(contentProperties.name); } else if ((0, _primitives.isDict)(contentProperties)) { optionalContent = contentProperties; } else { throw new _util.FormatError("Optional content properties malformed."); } const optionalContentType = optionalContent.get("Type").name; if (optionalContentType === "OCG") { return { type: optionalContentType, id: optionalContent.objId }; } else if (optionalContentType === "OCMD") { const optionalContentGroups = optionalContent.get("OCGs"); if (Array.isArray(optionalContentGroups) || (0, _primitives.isDict)(optionalContentGroups)) { const groupIds = []; if (Array.isArray(optionalContentGroups)) { optionalContent.get("OCGs").forEach(ocg => { groupIds.push(ocg.toString()); }); } else { groupIds.push(optionalContentGroups.objId); } let expression = null; if (optionalContent.get("VE")) { expression = true; } return { type: optionalContentType, ids: groupIds, policy: (0, _primitives.isName)(optionalContent.get("P")) ? optionalContent.get("P").name : null, expression }; } else if ((0, _primitives.isRef)(optionalContentGroups)) { return { type: optionalContentType, id: optionalContentGroups.toString() }; } } return null; } getOperatorList({ stream, task, resources, operatorList, initialState = null, fallbackFontDict = null }) { resources = resources || _primitives.Dict.empty; initialState = initialState || new EvalState(); if (!operatorList) { throw new Error('getOperatorList: missing "operatorList" parameter'); } var self = this; var xref = this.xref; let parsingText = false; const localImageCache = new _image_utils.LocalImageCache(); const localColorSpaceCache = new _image_utils.LocalColorSpaceCache(); const localGStateCache = new _image_utils.LocalGStateCache(); const localTilingPatternCache = new _image_utils.LocalTilingPatternCache(); var xobjs = resources.get("XObject") || _primitives.Dict.empty; var patterns = resources.get("Pattern") || _primitives.Dict.empty; var stateManager = new StateManager(initialState); var preprocessor = new EvaluatorPreprocessor(stream, xref, stateManager); var timeSlotManager = new TimeSlotManager(); function closePendingRestoreOPS(argument) { for (var i = 0, ii = preprocessor.savedStatesDepth; i < ii; i++) { operatorList.addOp(_util.OPS.restore, []); } } return new Promise(function promiseBody(resolve, reject) { const next = function (promise) { Promise.all([promise, operatorList.ready]).then(function () { try { promiseBody(resolve, reject); } catch (ex) { reject(ex); } }, reject); }; task.ensureNotTerminated(); timeSlotManager.reset(); var stop, operation = {}, i, ii, cs, name; while (!(stop = timeSlotManager.check())) { operation.args = null; if (!preprocessor.read(operation)) { break; } var args = operation.args; var fn = operation.fn; switch (fn | 0) { case _util.OPS.paintXObject: name = args[0].name; if (name) { const localImage = localImageCache.getByName(name); if (localImage) { operatorList.addOp(localImage.fn, localImage.args); args = null; continue; } } next(new Promise(function (resolveXObject, rejectXObject) { if (!name) { throw new _util.FormatError("XObject must be referred to by name."); } let xobj = xobjs.getRaw(name); if (xobj instanceof _primitives.Ref) { const localImage = localImageCache.getByRef(xobj); if (localImage) { operatorList.addOp(localImage.fn, localImage.args); resolveXObject(); return; } const globalImage = self.globalImageCache.getData(xobj, self.pageIndex); if (globalImage) { operatorList.addDependency(globalImage.objId); operatorList.addOp(globalImage.fn, globalImage.args); resolveXObject(); return; } xobj = xref.fetch(xobj); } if (!(0, _primitives.isStream)(xobj)) { throw new _util.FormatError("XObject should be a stream"); } const type = xobj.dict.get("Subtype"); if (!(0, _primitives.isName)(type)) { throw new _util.FormatError("XObject should have a Name subtype"); } if (type.name === "Form") { stateManager.save(); self.buildFormXObject(resources, xobj, null, operatorList, task, stateManager.state.clone(), localColorSpaceCache).then(function () { stateManager.restore(); resolveXObject(); }, rejectXObject); return; } else if (type.name === "Image") { self.buildPaintImageXObject({ resources, image: xobj, operatorList, cacheKey: name, localImageCache, localColorSpaceCache }).then(resolveXObject, rejectXObject); return; } else if (type.name === "PS") { (0, _util.info)("Ignored XObject subtype PS"); } else { throw new _util.FormatError(`Unhandled XObject subtype ${type.name}`); } resolveXObject(); }).catch(function (reason) { if (reason instanceof _util.AbortException) { return; } if (self.options.ignoreErrors) { self.handler.send("UnsupportedFeature", { featureId: _util.UNSUPPORTED_FEATURES.errorXObject }); (0, _util.warn)(`getOperatorList - ignoring XObject: "${reason}".`); return; } throw reason; })); return; case _util.OPS.setFont: var fontSize = args[1]; next(self.handleSetFont(resources, args, null, operatorList, task, stateManager.state, fallbackFontDict).then(function (loadedName) { operatorList.addDependency(loadedName); operatorList.addOp(_util.OPS.setFont, [loadedName, fontSize]); })); return; case _util.OPS.beginText: parsingText = true; break; case _util.OPS.endText: parsingText = false; break; case _util.OPS.endInlineImage: var cacheKey = args[0].cacheKey; if (cacheKey) { const localImage = localImageCache.getByName(cacheKey); if (localImage) { operatorList.addOp(localImage.fn, localImage.args); args = null; continue; } } next(self.buildPaintImageXObject({ resources, image: args[0], isInline: true, operatorList, cacheKey, localImageCache, localColorSpaceCache })); return; case _util.OPS.showText: if (!stateManager.state.font) { self.ensureStateFont(stateManager.state); continue; } args[0] = self.handleText(args[0], stateManager.state); break; case _util.OPS.showSpacedText: if (!stateManager.state.font) { self.ensureStateFont(stateManager.state); continue; } var arr = args[0]; var combinedGlyphs = []; var arrLength = arr.length; var state = stateManager.state; for (i = 0; i < arrLength; ++i) { var arrItem = arr[i]; if ((0, _util.isString)(arrItem)) { Array.prototype.push.apply(combinedGlyphs, self.handleText(arrItem, state)); } else if ((0, _util.isNum)(arrItem)) { combinedGlyphs.push(arrItem); } } args[0] = combinedGlyphs; fn = _util.OPS.showText; break; case _util.OPS.nextLineShowText: if (!stateManager.state.font) { self.ensureStateFont(stateManager.state); continue; } operatorList.addOp(_util.OPS.nextLine); args[0] = self.handleText(args[0], stateManager.state); fn = _util.OPS.showText; break; case _util.OPS.nextLineSetSpacingShowText: if (!stateManager.state.font) { self.ensureStateFont(stateManager.state); continue; } operatorList.addOp(_util.OPS.nextLine); operatorList.addOp(_util.OPS.setWordSpacing, [args.shift()]); operatorList.addOp(_util.OPS.setCharSpacing, [args.shift()]); args[0] = self.handleText(args[0], stateManager.state); fn = _util.OPS.showText; break; case _util.OPS.setTextRenderingMode: stateManager.state.textRenderingMode = args[0]; break; case _util.OPS.setFillColorSpace: { const cachedColorSpace = _colorspace.ColorSpace.getCached(args[0], xref, localColorSpaceCache); if (cachedColorSpace) { stateManager.state.fillColorSpace = cachedColorSpace; continue; } next(self.parseColorSpace({ cs: args[0], resources, localColorSpaceCache }).then(function (colorSpace) { if (colorSpace) { stateManager.state.fillColorSpace = colorSpace; } })); return; } case _util.OPS.setStrokeColorSpace: { const cachedColorSpace = _colorspace.ColorSpace.getCached(args[0], xref, localColorSpaceCache); if (cachedColorSpace) { stateManager.state.strokeColorSpace = cachedColorSpace; continue; } next(self.parseColorSpace({ cs: args[0], resources, localColorSpaceCache }).then(function (colorSpace) { if (colorSpace) { stateManager.state.strokeColorSpace = colorSpace; } })); return; } case _util.OPS.setFillColor: cs = stateManager.state.fillColorSpace; args = cs.getRgb(args, 0); fn = _util.OPS.setFillRGBColor; break; case _util.OPS.setStrokeColor: cs = stateManager.state.strokeColorSpace; args = cs.getRgb(args, 0); fn = _util.OPS.setStrokeRGBColor; break; case _util.OPS.setFillGray: stateManager.state.fillColorSpace = _colorspace.ColorSpace.singletons.gray; args = _colorspace.ColorSpace.singletons.gray.getRgb(args, 0); fn = _util.OPS.setFillRGBColor; break; case _util.OPS.setStrokeGray: stateManager.state.strokeColorSpace = _colorspace.ColorSpace.singletons.gray; args = _colorspace.ColorSpace.singletons.gray.getRgb(args, 0); fn = _util.OPS.setStrokeRGBColor; break; case _util.OPS.setFillCMYKColor: stateManager.state.fillColorSpace = _colorspace.ColorSpace.singletons.cmyk; args = _colorspace.ColorSpace.singletons.cmyk.getRgb(args, 0); fn = _util.OPS.setFillRGBColor; break; case _util.OPS.setStrokeCMYKColor: stateManager.state.strokeColorSpace = _colorspace.ColorSpace.singletons.cmyk; args = _colorspace.ColorSpace.singletons.cmyk.getRgb(args, 0); fn = _util.OPS.setStrokeRGBColor; break; case _util.OPS.setFillRGBColor: stateManager.state.fillColorSpace = _colorspace.ColorSpace.singletons.rgb; args = _colorspace.ColorSpace.singletons.rgb.getRgb(args, 0); break; case _util.OPS.setStrokeRGBColor: stateManager.state.strokeColorSpace = _colorspace.ColorSpace.singletons.rgb; args = _colorspace.ColorSpace.singletons.rgb.getRgb(args, 0); break; case _util.OPS.setFillColorN: cs = stateManager.state.fillColorSpace; if (cs.name === "Pattern") { next(self.handleColorN(operatorList, _util.OPS.setFillColorN, args, cs, patterns, resources, task, localColorSpaceCache, localTilingPatternCache)); return; } args = cs.getRgb(args, 0); fn = _util.OPS.setFillRGBColor; break; case _util.OPS.setStrokeColorN: cs = stateManager.state.strokeColorSpace; if (cs.name === "Pattern") { next(self.handleColorN(operatorList, _util.OPS.setStrokeColorN, args, cs, patterns, resources, task, localColorSpaceCache, localTilingPatternCache)); return; } args = cs.getRgb(args, 0); fn = _util.OPS.setStrokeRGBColor; break; case _util.OPS.shadingFill: var shadingRes = resources.get("Shading"); if (!shadingRes) { throw new _util.FormatError("No shading resource found"); } var shading = shadingRes.get(args[0].name); if (!shading) { throw new _util.FormatError("No shading object found"); } var shadingFill = _pattern.Pattern.parseShading(shading, null, xref, resources, self.handler, self._pdfFunctionFactory, localColorSpaceCache); var patternIR = shadingFill.getIR(); args = [patternIR]; fn = _util.OPS.shadingFill; break; case _util.OPS.setGState: name = args[0].name; if (name) { const localGStateObj = localGStateCache.getByName(name); if (localGStateObj) { if (localGStateObj.length > 0) { operatorList.addOp(_util.OPS.setGState, [localGStateObj]); } args = null; continue; } } next(new Promise(function (resolveGState, rejectGState) { if (!name) { throw new _util.FormatError("GState must be referred to by name."); } const extGState = resources.get("ExtGState"); if (!(extGState instanceof _primitives.Dict)) { throw new _util.FormatError("ExtGState should be a dictionary."); } const gState = extGState.get(name); if (!(gState instanceof _primitives.Dict)) { throw new _util.FormatError("GState should be a dictionary."); } self.setGState({ resources, gState, operatorList, cacheKey: name, task, stateManager, localGStateCache, localColorSpaceCache }).then(resolveGState, rejectGState); }).catch(function (reason) { if (reason instanceof _util.AbortException) { return; } if (self.options.ignoreErrors) { self.handler.send("UnsupportedFeature", { featureId: _util.UNSUPPORTED_FEATURES.errorExtGState }); (0, _util.warn)(`getOperatorList - ignoring ExtGState: "${reason}".`); return; } throw reason; })); return; case _util.OPS.moveTo: case _util.OPS.lineTo: case _util.OPS.curveTo: case _util.OPS.curveTo2: case _util.OPS.curveTo3: case _util.OPS.closePath: case _util.OPS.rectangle: self.buildPath(operatorList, fn, args, parsingText); continue; case _util.OPS.markPoint: case _util.OPS.markPointProps: case _util.OPS.beginCompat: case _util.OPS.endCompat: continue; case _util.OPS.beginMarkedContentProps: if (!(0, _primitives.isName)(args[0])) { (0, _util.warn)(`Expected name for beginMarkedContentProps arg0=${args[0]}`); continue; } if (args[0].name === "OC") { next(self.parseMarkedContentProps(args[1], resources).then(data => { operatorList.addOp(_util.OPS.beginMarkedContentProps, ["OC", data]); }).catch(reason => { if (reason instanceof _util.AbortException) { return; } if (self.options.ignoreErrors) { self.handler.send("UnsupportedFeature", { featureId: _util.UNSUPPORTED_FEATURES.errorMarkedContent }); (0, _util.warn)(`getOperatorList - ignoring beginMarkedContentProps: "${reason}".`); return; } throw reason; })); return; } args = [args[0].name]; break; case _util.OPS.beginMarkedContent: case _util.OPS.endMarkedContent: default: if (args !== null) { for (i = 0, ii = args.length; i < ii; i++) { if (args[i] instanceof _primitives.Dict) { break; } } if (i < ii) { (0, _util.warn)("getOperatorList - ignoring operator: " + fn); continue; } } } operatorList.addOp(fn, args); } if (stop) { next(deferred); return; } closePendingRestoreOPS(); resolve(); }).catch(reason => { if (reason insta