: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
warn(`Unsupported blend mode: ${value.name}`);
function incrementCachedImageMaskCount(data) {
if (data.fn === OPS.paintImageMaskXObject && data.args[0]?.count > 0) {
static TIME_SLOT_DURATION_MS = 20;
static CHECK_TIME_EVERY = 100;
if (++this.checked < TimeSlotManager.CHECK_TIME_EVERY) {
return this.endTime <= Date.now();
this.endTime = Date.now() + TimeSlotManager.TIME_SLOT_DURATION_MS;
this.pageIndex = pageIndex;
this.idFactory = idFactory;
this.fontCache = fontCache;
this.builtInCMapCache = builtInCMapCache;
this.standardFontDataCache = standardFontDataCache;
this.globalImageCache = globalImageCache;
this.systemFontCache = systemFontCache;
this.options = options || DefaultPartialEvaluatorOptions;
this.type3FontRefs = null;
this._regionalImageCache = new RegionalImageCache();
this._fetchBuiltInCMapBound = this.fetchBuiltInCMap.bind(this);
ImageResizer.setMaxArea(this.options.canvasMaxAreaInBytes);
get _pdfFunctionFactory() {
const pdfFunctionFactory = new PDFFunctionFactory({
isEvalSupported: this.options.isEvalSupported
return shadow(this, "_pdfFunctionFactory", pdfFunctionFactory);
return !!this.type3FontRefs;
clone(newOptions = null) {
const newEvaluator = Object.create(this);
newEvaluator.options = Object.assign(Object.create(null), this.options, newOptions);
hasBlendModes(resources, nonBlendModesSet) {
if (!(resources instanceof Dict)) {
if (resources.objId && nonBlendModesSet.has(resources.objId)) {
const processed = new RefSet(nonBlendModesSet);
processed.put(resources.objId);
const nodes = [resources],
const node = nodes.shift();
const graphicStates = node.get("ExtGState");
if (graphicStates instanceof Dict) {
for (let graphicState of graphicStates.getRawValues()) {
if (graphicState instanceof Ref) {
if (processed.has(graphicState)) {
graphicState = xref.fetch(graphicState);
processed.put(graphicState);
info(`hasBlendModes - ignoring ExtGState: "${ex}".`);
if (!(graphicState instanceof Dict)) {
if (graphicState.objId) {
processed.put(graphicState.objId);
const bm = graphicState.get("BM");
if (bm instanceof Name) {
if (bm.name !== "Normal") {
if (bm !== undefined && Array.isArray(bm)) {
for (const element of bm) {
if (element instanceof Name && element.name !== "Normal") {
const xObjects = node.get("XObject");
if (!(xObjects instanceof Dict)) {
for (let xObject of xObjects.getRawValues()) {
if (xObject instanceof Ref) {
if (processed.has(xObject)) {
xObject = xref.fetch(xObject);
info(`hasBlendModes - ignoring XObject: "${ex}".`);
if (!(xObject instanceof BaseStream)) {
if (xObject.dict.objId) {
processed.put(xObject.dict.objId);
const xResources = xObject.dict.get("Resources");
if (!(xResources instanceof Dict)) {
if (xResources.objId && processed.has(xResources.objId)) {
processed.put(xResources.objId);
for (const ref of processed) {
nonBlendModesSet.put(ref);
async fetchBuiltInCMap(name) {
const cachedData = this.builtInCMapCache.get(name);
if (this.options.cMapUrl !== null) {
const url = `${this.options.cMapUrl}${name}.bcmap`;
const response = await fetch(url);
throw new Error(`fetchBuiltInCMap: failed to fetch file "${url}" with "${response.statusText}".`);
cMapData: new Uint8Array(await response.arrayBuffer()),
compressionType: CMapCompressionType.BINARY
data = await this.handler.sendWithPromise("FetchBuiltInCMap", {
if (data.compressionType !== CMapCompressionType.NONE) {
this.builtInCMapCache.set(name, data);
async fetchStandardFontData(name) {
const cachedData = this.standardFontDataCache.get(name);
return new Stream(cachedData);
if (this.options.useSystemFonts && name !== "Symbol" && name !== "ZapfDingbats") {
const standardFontNameToFileName = getFontNameToFileMap(),
filename = standardFontNameToFileName[name];
if (this.options.standardFontDataUrl !== null) {
const url = `${this.options.standardFontDataUrl}${filename}`;
const response = await fetch(url);
warn(`fetchStandardFontData: failed to fetch file "${url}" with "${response.statusText}".`);
data = new Uint8Array(await response.arrayBuffer());
data = await this.handler.sendWithPromise("FetchStandardFontData", {
warn(`fetchStandardFontData: failed to fetch file "${filename}" with "${e}".`);
this.standardFontDataCache.set(name, data);
async buildFormXObject(resources, xobj, smask, operatorList, task, initialState, localColorSpaceCache) {
const matrix = lookupMatrix(dict.getArray("Matrix"), null);
const bbox = lookupNormalRect(dict.getArray("BBox"), null);
let optionalContent, groupOptions;
optionalContent = await this.parseMarkedContentProps(dict.get("OC"), resources);
if (optionalContent !== undefined) {
operatorList.addOp(OPS.beginMarkedContentProps, ["OC", optionalContent]);
const group = dict.get("Group");
const groupSubtype = group.get("S");
if (isName(groupSubtype, "Transparency")) {
groupOptions.isolated = group.get("I") || false;
groupOptions.knockout = group.get("K") || false;
const cs = group.getRaw("CS");
const cachedColorSpace = ColorSpace.getCached(cs, this.xref, localColorSpaceCache);
colorSpace = cachedColorSpace;
colorSpace = await this.parseColorSpace({
colorSpace ||= ColorSpace.singletons.rgb;
smask.backdrop = colorSpace.getRgb(smask.backdrop, 0);
operatorList.addOp(OPS.beginGroup, [groupOptions]);
const args = group ? [matrix, null] : [matrix, bbox];
operatorList.addOp(OPS.paintFormXObjectBegin, args);
await this.getOperatorList({
resources: dict.get("Resources") || resources,
operatorList.addOp(OPS.paintFormXObjectEnd, []);
operatorList.addOp(OPS.endGroup, [groupOptions]);
if (optionalContent !== undefined) {
operatorList.addOp(OPS.endMarkedContent, []);
_sendImgData(objId, imgData, cacheGlobally = false) {
const transfers = imgData ? [imgData.bitmap || 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({
const imageRef = dict.objId;
const w = dict.get("W", "Width");
const h = dict.get("H", "Height");
if (!(w && typeof w === "number") || !(h && typeof h === "number")) {
warn("Image dimensions are missing, or not numbers.");
const maxImageSize = this.options.maxImageSize;
if (maxImageSize !== -1 && w * h > maxImageSize) {
const msg = "Image exceeded maximum allowed size and was removed.";
if (this.options.ignoreErrors) {
optionalContent = await this.parseMarkedContentProps(dict.get("OC"), resources);
const imageMask = dict.get("IM", "ImageMask") || false;
const interpolate = dict.get("I", "Interpolate");
const bitStrideLength = w + 7 >> 3;
const imgArray = image.getBytes(bitStrideLength * h);
const decode = dict.getArray("D", "Decode");
if (this.parsingType3Font) {
imgData = PDFImage.createRawMask({
imageIsFromDecodeStream: image instanceof DecodeStream,
inverseDecode: decode?.[0] > 0,
imgData.cached = !!cacheKey;
operatorList.addImageOps(OPS.paintImageMaskXObject, args, optionalContent);
fn: OPS.paintImageMaskXObject,
localImageCache.set(cacheKey, imageRef, cacheData);
this._regionalImageCache.set(null, imageRef, cacheData);
imgData = await PDFImage.createMask({
imageIsFromDecodeStream: image instanceof DecodeStream,
inverseDecode: decode?.[0] > 0,
isOffscreenCanvasSupported: this.options.isOffscreenCanvasSupported
if (imgData.isSingleOpaquePixel) {
operatorList.addImageOps(OPS.paintSolidColorImageMask, [], optionalContent);
fn: OPS.paintSolidColorImageMask,
localImageCache.set(cacheKey, imageRef, cacheData);
this._regionalImageCache.set(null, imageRef, cacheData);
const objId = `mask_${this.idFactory.createObjId()}`;
operatorList.addDependency(objId);
imgData.dataLen = imgData.bitmap ? imgData.width * imgData.height * 4 : imgData.data.length;
this._sendImgData(objId, imgData);
interpolate: imgData.interpolate,
operatorList.addImageOps(OPS.paintImageMaskXObject, args, optionalContent);
fn: OPS.paintImageMaskXObject,
localImageCache.set(cacheKey, imageRef, cacheData);
this._regionalImageCache.set(null, imageRef, cacheData);
const SMALL_IMAGE_DIMENSIONS = 200;
if (isInline && w + h < SMALL_IMAGE_DIMENSIONS && !dict.has("SMask") && !dict.has("Mask")) {
const imageObj = new PDFImage({
pdfFunctionFactory: this._pdfFunctionFactory,
imgData = await imageObj.createImageData(true, false);
operatorList.isOffscreenCanvasSupported = this.options.isOffscreenCanvasSupported;
operatorList.addImageOps(OPS.paintInlineImageXObject, [imgData], optionalContent);
const msg = `Unable to decode inline image: "${reason}".`;
if (!this.options.ignoreErrors) {
let objId = `img_${this.idFactory.createObjId()}`,
if (this.parsingType3Font) {
objId = `${this.idFactory.getDocId()}_type3_${objId}`;
} else if (cacheKey && imageRef) {
cacheGlobally = this.globalImageCache.shouldCache(imageRef, this.pageIndex);
assert(!isInline, "Cannot cache an inline image globally.");
objId = `${this.idFactory.getDocId()}_${objId}`;
operatorList.addDependency(objId);
operatorList.addImageOps(OPS.paintImageXObject, args, optionalContent);
if (this.globalImageCache.hasDecodeFailed(imageRef)) {
this.globalImageCache.setData(imageRef, {
fn: OPS.paintImageXObject,
this._sendImgData(objId, null, cacheGlobally);
if (w * h > 250000 || dict.has("SMask") || dict.has("Mask")) {
const localLength = await this.handler.sendWithPromise("commonobj", [objId, "CopyLocalImage", {
this.globalImageCache.setData(imageRef, {
fn: OPS.paintImageXObject,
this.globalImageCache.addByteSize(imageRef, localLength);
pdfFunctionFactory: this._pdfFunctionFactory,
}).then(async imageObj => {
imgData = await imageObj.createImageData(false, this.options.isOffscreenCanvasSupported);
imgData.dataLen = imgData.bitmap ? imgData.width * imgData.height * 4 : imgData.data.length;
this.globalImageCache.addByteSize(imageRef, imgData.dataLen);
return this._sendImgData(objId, imgData, cacheGlobally);
warn(`Unable to decode image "${objId}": "${reason}".`);
this.globalImageCache.addDecodeFailed(imageRef);
return this._sendImgData(objId, null, cacheGlobally);
fn: OPS.paintImageXObject,