pdfjs-dist
Version:
Generic build of Mozilla's PDF.js library.
1,619 lines (1,318 loc) • 108 kB
JavaScript
/**
* @licstart The following is the entire license notice for the
* Javascript code in this page
*
* Copyright 2020 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 = void 0;
var _util = require("../shared/util.js");
var _cmap = require("./cmap.js");
var _primitives = require("./primitives.js");
var _fonts = require("./fonts.js");
var _encodings = require("./encodings.js");
var _core_utils = require("./core_utils.js");
var _unicode = require("./unicode.js");
var _standard_fonts = require("./standard_fonts.js");
var _pattern = require("./pattern.js");
var _parser = require("./parser.js");
var _bidi = require("./bidi.js");
var _colorspace = require("./colorspace.js");
var _stream = require("./stream.js");
var _glyphlist = require("./glyphlist.js");
var _metrics = require("./metrics.js");
var _function = require("./function.js");
var _jpeg_stream = require("./jpeg_stream.js");
var _murmurhash = require("./murmurhash3.js");
var _image_utils = require("./image_utils.js");
var _operator_list = require("./operator_list.js");
var _image = require("./image.js");
var PartialEvaluator = function PartialEvaluatorClosure() {
const DefaultPartialEvaluatorOptions = {
forceDataSchema: false,
maxImageSize: -1,
disableFontFace: false,
nativeImageDecoderSupport: _util.NativeImageDecoding.DECODE,
ignoreErrors: false,
isEvalSupported: true
};
function PartialEvaluator({
xref,
handler,
pageIndex,
idFactory,
fontCache,
builtInCMapCache,
options = null,
pdfFunctionFactory
}) {
this.xref = xref;
this.handler = handler;
this.pageIndex = pageIndex;
this.idFactory = idFactory;
this.fontCache = fontCache;
this.builtInCMapCache = builtInCMapCache;
this.options = options || DefaultPartialEvaluatorOptions;
this.pdfFunctionFactory = pdfFunctionFactory;
this.parsingType3Font = false;
this.fetchBuiltInCMap = async name => {
if (this.builtInCMapCache.has(name)) {
return this.builtInCMapCache.get(name);
}
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;
};
}
var TIME_SLOT_DURATION_MS = 20;
var CHECK_TIME_EVERY = 100;
function TimeSlotManager() {
this.reset();
}
TimeSlotManager.prototype = {
check: function TimeSlotManager_check() {
if (++this.checked < CHECK_TIME_EVERY) {
return false;
}
this.checked = 0;
return this.endTime <= Date.now();
},
reset: function TimeSlotManager_reset() {
this.endTime = Date.now() + TIME_SLOT_DURATION_MS;
this.checked = 0;
}
};
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";
}
var deferred = Promise.resolve();
var TILING_PATTERN = 1,
SHADING_PATTERN = 2;
PartialEvaluator.prototype = {
clone(newOptions = DefaultPartialEvaluatorOptions) {
var newEvaluator = Object.create(this);
newEvaluator.options = newOptions;
return newEvaluator;
},
hasBlendModes: function PartialEvaluator_hasBlendModes(resources) {
if (!(resources instanceof _primitives.Dict)) {
return false;
}
var processed = Object.create(null);
if (resources.objId) {
processed[resources.objId] = true;
}
var nodes = [resources],
xref = this.xref;
while (nodes.length) {
var node = nodes.shift();
var graphicStates = node.get("ExtGState");
if (graphicStates instanceof _primitives.Dict) {
var graphicStatesKeys = graphicStates.getKeys();
for (let i = 0, ii = graphicStatesKeys.length; i < ii; i++) {
const key = graphicStatesKeys[i];
let graphicState = graphicStates.getRaw(key);
if (graphicState instanceof _primitives.Ref) {
if (processed[graphicState.toString()]) {
continue;
}
try {
graphicState = xref.fetch(graphicState);
} catch (ex) {
if (ex instanceof _core_utils.MissingDataException) {
throw ex;
}
if (this.options.ignoreErrors) {
if (graphicState instanceof _primitives.Ref) {
processed[graphicState.toString()] = true;
}
this.handler.send("UnsupportedFeature", {
featureId: _util.UNSUPPORTED_FEATURES.unknown
});
(0, _util.warn)(`hasBlendModes - ignoring ExtGState: "${ex}".`);
continue;
}
throw ex;
}
}
if (!(graphicState instanceof _primitives.Dict)) {
continue;
}
if (graphicState.objId) {
processed[graphicState.objId] = true;
}
const bm = graphicState.get("BM");
if (bm instanceof _primitives.Name) {
if (bm.name !== "Normal") {
return true;
}
continue;
}
if (bm !== undefined && Array.isArray(bm)) {
for (let j = 0, jj = bm.length; j < jj; j++) {
if (bm[j] instanceof _primitives.Name && bm[j].name !== "Normal") {
return true;
}
}
}
}
}
var xObjects = node.get("XObject");
if (!(xObjects instanceof _primitives.Dict)) {
continue;
}
var xObjectsKeys = xObjects.getKeys();
for (let i = 0, ii = xObjectsKeys.length; i < ii; i++) {
const key = xObjectsKeys[i];
var xObject = xObjects.getRaw(key);
if (xObject instanceof _primitives.Ref) {
if (processed[xObject.toString()]) {
continue;
}
try {
xObject = xref.fetch(xObject);
} catch (ex) {
if (ex instanceof _core_utils.MissingDataException) {
throw ex;
}
if (this.options.ignoreErrors) {
if (xObject instanceof _primitives.Ref) {
processed[xObject.toString()] = true;
}
this.handler.send("UnsupportedFeature", {
featureId: _util.UNSUPPORTED_FEATURES.unknown
});
(0, _util.warn)(`hasBlendModes - ignoring XObject: "${ex}".`);
continue;
}
throw ex;
}
}
if (!(0, _primitives.isStream)(xObject)) {
continue;
}
if (xObject.dict.objId) {
if (processed[xObject.dict.objId]) {
continue;
}
processed[xObject.dict.objId] = true;
}
var xResources = xObject.dict.get("Resources");
if (xResources instanceof _primitives.Dict && (!xResources.objId || !processed[xResources.objId])) {
nodes.push(xResources);
if (xResources.objId) {
processed[xResources.objId] = true;
}
}
}
}
return false;
},
async buildFormXObject(resources, xobj, smask, operatorList, task, initialState) {
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;
}
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")) {
colorSpace = await this.parseColorSpace({
cs: group.get("CS"),
resources
});
}
}
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]);
}
});
},
async buildPaintImageXObject({
resources,
image,
isInline = false,
operatorList,
cacheKey,
imageCache,
forceDisableNativeImageDecoder = false
}) {
var dict = image.dict;
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) {
imageCache[cacheKey] = {
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 && !(image instanceof _jpeg_stream.JpegStream) && w + h < SMALL_IMAGE_DIMENSIONS) {
const imageObj = new _image.PDFImage({
xref: this.xref,
res: resources,
image,
isInline,
pdfFunctionFactory: this.pdfFunctionFactory
});
imgData = imageObj.createImageData(true);
operatorList.addOp(_util.OPS.paintInlineImageXObject, [imgData]);
return undefined;
}
const nativeImageDecoderSupport = forceDisableNativeImageDecoder ? _util.NativeImageDecoding.NONE : this.options.nativeImageDecoderSupport;
let objId = `img_${this.idFactory.createObjId()}`;
if (this.parsingType3Font) {
(0, _util.assert)(nativeImageDecoderSupport === _util.NativeImageDecoding.NONE, "Type3 image resources should be completely decoded in the worker.");
objId = `${this.idFactory.getDocId()}_type3res_${objId}`;
}
if (nativeImageDecoderSupport !== _util.NativeImageDecoding.NONE && !softMask && !mask && image instanceof _jpeg_stream.JpegStream && _image_utils.NativeImageDecoder.isSupported(image, this.xref, resources, this.pdfFunctionFactory) && image.maybeValidDimensions) {
return this.handler.sendWithPromise("obj", [objId, this.pageIndex, "JpegStream", image.getIR(this.options.forceDataSchema)]).then(function () {
operatorList.addDependency(objId);
args = [objId, w, h];
operatorList.addOp(_util.OPS.paintJpegXObject, args);
if (cacheKey) {
imageCache[cacheKey] = {
fn: _util.OPS.paintJpegXObject,
args
};
}
}, reason => {
(0, _util.warn)("Native JPEG decoding failed -- trying to recover: " + (reason && reason.message));
return this.buildPaintImageXObject({
resources,
image,
isInline,
operatorList,
cacheKey,
imageCache,
forceDisableNativeImageDecoder: true
});
});
}
var nativeImageDecoder = null;
if (nativeImageDecoderSupport === _util.NativeImageDecoding.DECODE && (image instanceof _jpeg_stream.JpegStream || mask instanceof _jpeg_stream.JpegStream || softMask instanceof _jpeg_stream.JpegStream)) {
nativeImageDecoder = new _image_utils.NativeImageDecoder({
xref: this.xref,
resources,
handler: this.handler,
forceDataSchema: this.options.forceDataSchema,
pdfFunctionFactory: this.pdfFunctionFactory
});
}
operatorList.addDependency(objId);
args = [objId, w, h];
const imgPromise = _image.PDFImage.buildImage({
handler: this.handler,
xref: this.xref,
res: resources,
image,
isInline,
nativeDecoder: nativeImageDecoder,
pdfFunctionFactory: this.pdfFunctionFactory
}).then(imageObj => {
var imgData = imageObj.createImageData(false);
if (this.parsingType3Font) {
return this.handler.sendWithPromise("commonobj", [objId, "FontType3Res", imgData], [imgData.data.buffer]);
}
this.handler.send("obj", [objId, this.pageIndex, "Image", imgData], [imgData.data.buffer]);
return undefined;
}).catch(reason => {
(0, _util.warn)("Unable to decode image: " + reason);
if (this.parsingType3Font) {
return this.handler.sendWithPromise("commonobj", [objId, "FontType3Res", null]);
}
this.handler.send("obj", [objId, this.pageIndex, "Image", null]);
return undefined;
});
if (this.parsingType3Font) {
await imgPromise;
}
operatorList.addOp(_util.OPS.paintImageXObject, args);
if (cacheKey) {
imageCache[cacheKey] = {
fn: _util.OPS.paintImageXObject,
args
};
}
return undefined;
},
handleSMask: function PartialEvaluator_handleSmask(smask, resources, operatorList, task, stateManager) {
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());
},
handleTilingType(fn, args, resources, pattern, patternDict, operatorList, task) {
const tilingOpList = new _operator_list.OperatorList();
const resourcesArray = [patternDict.get("Resources"), resources];
const patternResources = _primitives.Dict.merge(this.xref, resourcesArray);
return this.getOperatorList({
stream: pattern,
task,
resources: patternResources,
operatorList: tilingOpList
}).then(function () {
return (0, _pattern.getTilingPatternIR)({
fnArray: tilingOpList.fnArray,
argsArray: tilingOpList.argsArray
}, patternDict, args);
}).then(function (tilingPatternIR) {
operatorList.addDependencies(tilingOpList.dependencies);
operatorList.addOp(fn, tilingPatternIR);
}, reason => {
if (reason instanceof _util.AbortException) {
return;
}
if (this.options.ignoreErrors) {
this.handler.send("UnsupportedFeature", {
featureId: _util.UNSUPPORTED_FEATURES.unknown
});
(0, _util.warn)(`handleTilingType - ignoring pattern: "${reason}".`);
return;
}
throw reason;
});
},
handleSetFont: function PartialEvaluator_handleSetFont(resources, fontArgs, fontRef, operatorList, task, state) {
var fontName;
if (fontArgs) {
fontArgs = fontArgs.slice();
fontName = fontArgs[0].name;
}
return this.loadFont(fontName, fontRef, resources).then(translated => {
if (!translated.font.isType3Font) {
return translated;
}
return translated.loadType3Data(this, resources, operatorList, task).then(function () {
return translated;
}).catch(reason => {
this.handler.send("UnsupportedFeature", {
featureId: _util.UNSUPPORTED_FEATURES.font
});
return new TranslatedFont("g_font_error", new _fonts.ErrorFont("Type3 font load error: " + reason), translated.font);
});
}).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.font
});
(0, _util.warn)(`ensureStateFont: "${reason}".`);
return;
}
throw reason;
},
setGState: function PartialEvaluator_setGState(resources, gState, operatorList, task, stateManager) {
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":
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)) {
promise = promise.then(() => {
return this.handleSMask(value, resources, operatorList, task, stateManager);
});
gStateObj.push([key, true]);
} else {
(0, _util.warn)("Unsupported SMask type");
}
break;
case "OP":
case "op":
case "OPM":
case "BG":
case "BG2":
case "UCR":
case "UCR2":
case "TR":
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]);
}
});
},
loadFont: function PartialEvaluator_loadFont(fontName, font, resources) {
function errorFont() {
return Promise.resolve(new TranslatedFont("g_font_error", new _fonts.ErrorFont("Font " + fontName + " is not available"), font));
}
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.font
});
(0, _util.warn)(`${partialMsg} -- attempting to fallback to a default font.`);
fontRef = PartialEvaluator.getFallbackFontDict();
}
if (this.fontCache.has(fontRef)) {
return this.fontCache.get(fontRef);
}
font = xref.fetchIfRef(fontRef);
if (!(0, _primitives.isDict)(font)) {
return errorFont();
}
if (font.translated) {
return font.translated;
}
var fontCapability = (0, _util.createPromiseCapability)();
var preEvaluatedFont = this.preEvaluateFont(font);
const {
descriptor,
hash
} = preEvaluatedFont;
var fontRefIsRef = (0, _primitives.isRef)(fontRef),
fontID;
if (fontRefIsRef) {
fontID = 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: _fonts.Font.getFontID()
};
}
if (fontRefIsRef) {
fontAliases[hash].aliasRef = fontRef;
}
fontID = fontAliases[hash].fontID;
}
if (fontRefIsRef) {
this.fontCache.put(fontRef, fontCapability.promise);
} else {
if (!fontID) {
fontID = this.idFactory.createObjId();
}
this.fontCache.put(`id_${fontID}`, fontCapability.promise);
}
(0, _util.assert)(fontID, 'The "fontID" must be defined.');
font.loadedName = `${this.idFactory.getDocId()}_f${fontID}`;
font.translated = fontCapability.promise;
var translatedPromise;
try {
translatedPromise = this.translateFont(preEvaluatedFont);
} catch (e) {
translatedPromise = Promise.reject(e);
}
translatedPromise.then(function (translatedFont) {
if (translatedFont.fontType !== undefined) {
var xrefFontStats = xref.stats.fontTypes;
xrefFontStats[translatedFont.fontType] = true;
}
fontCapability.resolve(new TranslatedFont(font.loadedName, translatedFont, font));
}).catch(reason => {
this.handler.send("UnsupportedFeature", {
featureId: _util.UNSUPPORTED_FEATURES.font
});
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(font.loadedName, new _fonts.ErrorFont(reason instanceof Error ? reason.message : reason), font));
});
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
}) {
return new Promise(resolve => {
resolve(_colorspace.ColorSpace.parse(cs, this.xref, resources, this.pdfFunctionFactory));
}).catch(reason => {
if (reason instanceof _util.AbortException) {
return null;
}
if (this.options.ignoreErrors) {
this.handler.send("UnsupportedFeature", {
featureId: _util.UNSUPPORTED_FEATURES.unknown
});
(0, _util.warn)(`parseColorSpace - ignoring ColorSpace: "${reason}".`);
return null;
}
throw reason;
});
},
async handleColorN(operatorList, fn, args, cs, patterns, resources, task) {
var patternName = args[args.length - 1];
var pattern;
if ((0, _primitives.isName)(patternName) && (pattern = patterns.get(patternName.name))) {
var dict = (0, _primitives.isStream)(pattern) ? pattern.dict : pattern;
var typeNum = dict.get("PatternType");
if (typeNum === TILING_PATTERN) {
var color = cs.base ? cs.base.getRgb(args, 0) : null;
return this.handleTilingType(fn, color, resources, pattern, dict, operatorList, task);
} else if (typeNum === SHADING_PATTERN) {
var shading = dict.get("Shading");
var matrix = dict.getArray("Matrix");
pattern = _pattern.Pattern.parseShading(shading, matrix, this.xref, resources, this.handler, this.pdfFunctionFactory);
operatorList.addOp(fn, pattern.getIR());
return undefined;
}
throw new _util.FormatError(`Unknown PatternType: ${typeNum}`);
}
throw new _util.FormatError(`Unknown PatternName: ${patternName}`);
},
getOperatorList({
stream,
task,
resources,
operatorList,
initialState = 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;
var imageCache = Object.create(null);
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;
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:
var name = args[0].name;
if (name && imageCache[name] !== undefined) {
operatorList.addOp(imageCache[name].fn, imageCache[name].args);
args = null;
continue;
}
next(new Promise(function (resolveXObject, rejectXObject) {
if (!name) {
throw new _util.FormatError("XObject must be referred to by name.");
}
const xobj = xobjs.get(name);
if (!xobj) {
operatorList.addOp(fn, args);
resolveXObject();
return;
}
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()).then(function () {
stateManager.restore();
resolveXObject();
}, rejectXObject);
return;
} else if (type.name === "Image") {
self.buildPaintImageXObject({
resources,
image: xobj,
operatorList,
cacheKey: name,
imageCache
}).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.unknown
});
(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).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) {
var cacheEntry = imageCache[cacheKey];
if (cacheEntry !== undefined) {
operatorList.addOp(cacheEntry.fn, cacheEntry.args);
args = null;
continue;
}
}
next(self.buildPaintImageXObject({
resources,
image: args[0],
isInline: true,
operatorList,
cacheKey,
imageCache
}));
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:
next(self.parseColorSpace({
cs: args[0],
resources
}).then(function (colorSpace) {
if (colorSpace) {
stateManager.state.fillColorSpace = colorSpace;
}
}));
return;
case _util.OPS.setStrokeColorSpace:
next(self.parseColorSpace({
cs: args[0],
resources
}).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));
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));
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);
var patternIR = shadingFill.getIR();
args = [patternIR];
fn = _util.OPS.shadingFill;
break;
case _util.OPS.setGState:
var dictName = args[0];
var extGState = resources.get("ExtGState");
if (!(0, _primitives.isDict)(extGState) || !extGState.has(dictName.name)) {
break;
}
var gState = extGState.get(dictName.name);
next(self.setGState(resources, gState, operatorList, task, stateManager));
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.beginMarkedContent:
case _util.OPS.beginMarkedContentProps:
case _util.OPS.endMarkedContent:
case _util.OPS.beginCompat:
case _util.OPS.endCompat:
continue;
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 instanceof _util.AbortException) {
return;
}
if (this.options.ignoreErrors) {
this.handler.send("UnsupportedFeature", {
featureId: _util.UNSUPPORTED_FEATURES.unknown
});
(0, _util.warn)(`getOperatorList - ignoring errors during "${task.name}" ` + `task: "${reason}".`);
closePendingRestoreOPS();
return;
}
throw reason;
});
},
getTextContent({
stream,
task,
resources,
stateManager = null,
normalizeWhitespace = false,
combineTextItems = false,
sink,
seenStyles = Object.create(null)
}) {
resources = resources || _primitives.Dict.empty;
stateManager = stateManager || new StateManager(new TextState());
var WhitespaceRegexp = /\s/g;
var textContent = {
items: [],
styles: Object.create(null)
};
var textContentItem = {
initialized: false,
str: [],
width: 0,
height: 0,
vertical: false,
lastAdvanceWidth: 0,
lastAdvanceHeight: 0,
textAdvanceScale: 0,
spaceWidth: 0,
fakeSpaceMin: Infinity,
fakeMultiSpaceMin: Infinity,
fakeMultiSpaceMax: -0,
textRunBreakAllowed: false,
transform: null,
fontName: null
};
var SPACE_FACTOR = 0.3;
var MULTI_SPACE_FACTOR = 1.5;
var MULTI_SPACE_FACTOR_MAX = 4;
var self = this;
var xref = this.xref;
var xobjs = null;
var skipEmptyXObjs = Object.create(null);
var preprocessor = new EvaluatorPreprocessor(stream, xref, stateManager);
var textState;
function ensureTextContentItem() {
if (textContentItem.initialized) {
return textContentItem;
}
var font = textState.font;
if (!(font.loadedName in seenStyles)) {
seenStyles[font.loadedName] = true;
textContent.styles[font.loadedName] = {
fontFamily: font.fallbackName,
ascent: font.ascent,
descent: font.descent,
vertical: !!font.vertical
};
}
textContentItem.fontName = font.loadedName;
var tsm = [textState.fontSize * textState.textHScale, 0, 0, textState.fontSize, 0, textState.textRise];
if (font.isType3Font && textState.fontSize <= 1 && !(0, _util.isArrayEqual)(textState.fontMatrix, _util.FONT_IDENTITY_MATRIX)) {
const glyphHeight = font.bbox[3] - font.bbox[1];
if (glyphHeight > 0) {
tsm[3] *= glyphHeight * textState.fontMatrix[3];
}
}
var trm = _util.Util.transform(textState.ctm, _util.Util.transform(textState.textMatrix, tsm));
textContentItem.transform = trm;
if (!font.vertical) {
textContentItem.width = 0;
textContentItem.height = Math.sqrt(trm[2] * trm[2] + trm[3] * trm[3]);
textContentItem.vertical = false;
} else {
textContentItem.width = Math.sqrt(trm[0] * trm[0] + trm[1] * trm[1]);
textContentItem.height = 0;
textContentItem.vertical = true;
}
var a = textState.textLineMatrix[0];
var b = textState.textLineMatrix[1];
var scaleLineX = Math.sqrt(a * a + b * b);
a = textState.ctm[0];
b = textState.ctm[1];
var scaleCtmX = Math.sqrt(a * a + b * b);
textContentItem.textAdvanceScale = scaleCtmX * scaleLineX;
textContentItem.lastAdvanceWidth = 0;
textContentItem.lastAdvanceHeight = 0;
var spaceWidth = font.spaceWidth / 1000 * textState.fontSize;
if (spaceWidth) {
textContentItem.spaceWidth = spaceWidth;
textContentItem.fakeSpaceMin = spaceWidth * SPACE_FACTOR;
textContentItem.fakeMultiSpaceMin = spaceWidth * MULTI_SPACE_FACTOR;
textContentItem.fakeMultiSpaceMax = spaceWidth * MULTI_SPACE_FACTOR_MAX;
textContentItem.textRunBreakAllowed = !font.isMonospace;
} else {
textContentItem.spaceWidth = 0;
textContentItem.fakeSpaceMin = Infinity;
textContentItem.fakeMultiSpaceMin = Infinity;
textContentItem.fakeMultiSpaceMax = 0;
textContentItem.textRunBreakAllowed = false;
}
textContentItem.initialized = true;
return textContentItem;
}
function replaceWhitespace(str) {
var i = 0,
ii = str.length,
code;
while (i < ii && (code = str.charCodeAt(i)) >= 0x20 && code <= 0x7f) {
i++;
}
return i < ii ? str.replace(WhitespaceRegexp, " ") : str;
}
function runBidiTransform(textChunk) {
var str = textChunk.str.join("");
var bidiResult = (0, _bidi.bidi)(str, -1, textChunk.vertical);
return {
str: normalizeWhitespace ? replaceWhitespace(bidiResult.str) : bidiResult.str,
dir: bidiResult.dir,
width: textChunk.width,
height: textChunk.height,
transform: textChunk.transform,
fontName: textChunk.fontName
};
}
function handleSetFont(fontName, fontRef) {
return self.loadFont(fontName, fontRef, resources).then(function (translated) {
textState.font = translated.font;
textState.fontMatrix = translated.font.fontMatrix || _util.FONT_IDENTITY_MATRIX;
});
}
function buildTextContentItem(chars) {
var font = textState.font;
var textChunk = ensureTextContentItem();
var width = 0;
var height = 0;
var glyphs = font.charsToGlyphs(chars);
for (var i = 0; i < glyphs.length; i++) {
var glyph = glyphs[i];
var glyphWidth = null;
if (font.ver