pdfjs-dist
Version:
Generic build of Mozilla's PDF.js library.
1,733 lines (1,403 loc) • 114 kB
JavaScript
/**
* @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