: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
result.fillColorSpace = ColorSpace.parse({
resources: this.resources,
pdfFunctionFactory: this._pdfFunctionFactory,
localColorSpaceCache: this._localColorSpaceCache
const cs = result.fillColorSpace;
cs.getRgbItem(args, 0, result.fontColor, 0);
case OPS.setFillRGBColor:
ColorSpace.singletons.rgb.getRgbItem(args, 0, result.fontColor, 0);
ColorSpace.singletons.gray.getRgbItem(args, 0, result.fontColor, 0);
case OPS.setFillCMYKColor:
ColorSpace.singletons.cmyk.getRgbItem(args, 0, result.fontColor, 0);
case OPS.nextLineShowText:
case OPS.nextLineSetSpacingShowText:
warn(`parseAppearanceStream - ignoring errors: "${reason}".`);
delete result.scaleFactor;
delete result.fillColorSpace;
get _localColorSpaceCache() {
return shadow(this, "_localColorSpaceCache", new LocalColorSpaceCache());
get _pdfFunctionFactory() {
const pdfFunctionFactory = new PDFFunctionFactory({
isEvalSupported: this.evaluatorOptions.isEvalSupported
return shadow(this, "_pdfFunctionFactory", pdfFunctionFactory);
function parseAppearanceStream(stream, evaluatorOptions, xref) {
return new AppearanceStreamEvaluator(stream, evaluatorOptions, xref).parse();
function getPdfColor(color, isFill) {
if (color[0] === color[1] && color[1] === color[2]) {
const gray = color[0] / 255;
return `${numberToString(gray)} ${isFill ? "g" : "G"}`;
return Array.from(color, c => numberToString(c / 255)).join(" ") + ` ${isFill ? "rg" : "RG"}`;
function createDefaultAppearance({
return `/${escapePDFName(fontName)} ${fontSize} Tf ${getPdfColor(fontColor, true)}`;
constructor(xref, fontFamily) {
this.firstChar = Infinity;
this.lastChar = -Infinity;
this.fontFamily = fontFamily;
const canvas = new OffscreenCanvas(1, 1);
this.ctxMeasure = canvas.getContext("2d");
if (!FakeUnicodeFont._fontNameId) {
FakeUnicodeFont._fontNameId = 1;
this.fontName = Name.get(`InvalidPDFjsFont_${fontFamily}_${FakeUnicodeFont._fontNameId++}`);
get fontDescriptorRef() {
if (!FakeUnicodeFont._fontDescriptorRef) {
const fontDescriptor = new Dict(this.xref);
fontDescriptor.set("Type", Name.get("FontDescriptor"));
fontDescriptor.set("FontName", this.fontName);
fontDescriptor.set("FontFamily", "MyriadPro Regular");
fontDescriptor.set("FontBBox", [0, 0, 0, 0]);
fontDescriptor.set("FontStretch", Name.get("Normal"));
fontDescriptor.set("FontWeight", 400);
fontDescriptor.set("ItalicAngle", 0);
FakeUnicodeFont._fontDescriptorRef = this.xref.getNewPersistentRef(fontDescriptor);
return FakeUnicodeFont._fontDescriptorRef;
get descendantFontRef() {
const descendantFont = new Dict(this.xref);
descendantFont.set("BaseFont", this.fontName);
descendantFont.set("Type", Name.get("Font"));
descendantFont.set("Subtype", Name.get("CIDFontType0"));
descendantFont.set("CIDToGIDMap", Name.get("Identity"));
descendantFont.set("FirstChar", this.firstChar);
descendantFont.set("LastChar", this.lastChar);
descendantFont.set("FontDescriptor", this.fontDescriptorRef);
descendantFont.set("DW", 1000);
const chars = [...this.widths.entries()].sort();
let currentWidths = null;
for (const [char, width] of chars) {
if (char === currentChar + currentWidths.length) {
currentWidths.push(width);
widths.push(currentChar, currentWidths);
widths.push(currentChar, currentWidths);
descendantFont.set("W", widths);
const cidSystemInfo = new Dict(this.xref);
cidSystemInfo.set("Ordering", "Identity");
cidSystemInfo.set("Registry", "Adobe");
cidSystemInfo.set("Supplement", 0);
descendantFont.set("CIDSystemInfo", cidSystemInfo);
return this.xref.getNewPersistentRef(descendantFont);
const baseFont = new Dict(this.xref);
baseFont.set("BaseFont", this.fontName);
baseFont.set("Type", Name.get("Font"));
baseFont.set("Subtype", Name.get("Type0"));
baseFont.set("Encoding", Name.get("Identity-H"));
baseFont.set("DescendantFonts", [this.descendantFontRef]);
baseFont.set("ToUnicode", Name.get("Identity-H"));
return this.xref.getNewPersistentRef(baseFont);
const resources = new Dict(this.xref);
const font = new Dict(this.xref);
font.set(this.fontName.name, this.baseFontRef);
resources.set("Font", font);
this.ctxMeasure.font = `1000px ${this.fontFamily}`;
createFontResources(text) {
const ctx = this._createContext();
for (const line of text.split(/\r\n?|\n/)) {
for (const char of line.split("")) {
const code = char.charCodeAt(0);
if (this.widths.has(code)) {
const metrics = ctx.measureText(char);
const width = Math.ceil(metrics.width);
this.widths.set(code, width);
this.firstChar = Math.min(code, this.firstChar);
this.lastChar = Math.max(code, this.lastChar);
static getFirstPositionInfo(rect, rotation, fontSize) {
const [x1, y1, x2, y2] = rect;
if (rotation % 180 !== 0) {
const lineHeight = LINE_FACTOR * fontSize;
const lineDescent = LINE_DESCENT_FACTOR * fontSize;
coords: [0, h + lineDescent - lineHeight],
matrix: rotation !== 0 ? getRotationMatrix(rotation, h, lineHeight) : undefined
createAppearance(text, rect, rotation, fontSize, bgColor, strokeAlpha) {
const ctx = this._createContext();
let maxWidth = -Infinity;
for (const line of text.split(/\r\n?|\n/)) {
const lineWidth = ctx.measureText(line).width;
maxWidth = Math.max(maxWidth, lineWidth);
for (const code of codePointIter(line)) {
const char = String.fromCodePoint(code);
let width = this.widths.get(code);
if (width === undefined) {
const metrics = ctx.measureText(char);
width = Math.ceil(metrics.width);
this.widths.set(code, width);
this.firstChar = Math.min(code, this.firstChar);
this.lastChar = Math.max(code, this.lastChar);
maxWidth *= fontSize / 1000;
const [x1, y1, x2, y2] = rect;
if (rotation % 180 !== 0) {
const lineHeight = LINE_FACTOR * fontSize;
const lineDescent = LINE_DESCENT_FACTOR * fontSize;
const maxHeight = lineHeight * lines.length;
const fscale = Math.min(hscale, vscale);
const newFontSize = fontSize * fscale;
const buffer = ["q", `0 0 ${numberToString(w)} ${numberToString(h)} re W n`, `BT`, `1 0 0 1 0 ${numberToString(h + lineDescent)} Tm 0 Tc ${getPdfColor(bgColor, true)}`, `/${this.fontName.name} ${numberToString(newFontSize)} Tf`];
strokeAlpha = typeof strokeAlpha === "number" && strokeAlpha >= 0 && strokeAlpha <= 1 ? strokeAlpha : 1;
const extGState = new Dict(this.xref);
const r0 = new Dict(this.xref);
r0.set("ca", strokeAlpha);
r0.set("CA", strokeAlpha);
r0.set("Type", Name.get("ExtGState"));
resources.set("ExtGState", extGState);
const vShift = numberToString(lineHeight);
for (const line of lines) {
buffer.push(`0 -${vShift} Td <${stringToUTF16HexString(line)}> Tj`);
const appearance = buffer.join("\n");
const appearanceStreamDict = new Dict(this.xref);
appearanceStreamDict.set("Subtype", Name.get("Form"));
appearanceStreamDict.set("Type", Name.get("XObject"));
appearanceStreamDict.set("BBox", [0, 0, w, h]);
appearanceStreamDict.set("Length", appearance.length);
appearanceStreamDict.set("Resources", resources);
const matrix = getRotationMatrix(rotation, w, h);
appearanceStreamDict.set("Matrix", matrix);
const ap = new StringStream(appearance);
ap.dict = appearanceStreamDict;
;// CONCATENATED MODULE: ./src/core/name_number_tree.js
constructor(root, xref, type) {
if (this.constructor === NameOrNumberTree) {
unreachable("Cannot initialize NameOrNumberTree.");
const processed = new RefSet();
processed.put(this.root);
const queue = [this.root];
while (queue.length > 0) {
const obj = xref.fetchIfRef(queue.shift());
if (!(obj instanceof Dict)) {
const kids = obj.get("Kids");
if (!Array.isArray(kids)) {
for (const kid of kids) {
if (processed.has(kid)) {
throw new FormatError(`Duplicate entry in "${this._type}" tree.`);
const entries = obj.get(this._type);
if (!Array.isArray(entries)) {
for (let i = 0, ii = entries.length; i < ii; i += 2) {
map.set(xref.fetchIfRef(entries[i]), xref.fetchIfRef(entries[i + 1]));
let kidsOrEntries = xref.fetchIfRef(this.root);
while (kidsOrEntries.has("Kids")) {
if (++loopCount > MAX_LEVELS) {
warn(`Search depth limit reached for "${this._type}" tree.`);
const kids = kidsOrEntries.get("Kids");
if (!Array.isArray(kids)) {
const kid = xref.fetchIfRef(kids[m]);
const limits = kid.get("Limits");
if (key < xref.fetchIfRef(limits[0])) {
} else if (key > xref.fetchIfRef(limits[1])) {
const entries = kidsOrEntries.get(this._type);
if (Array.isArray(entries)) {
const currentKey = xref.fetchIfRef(entries[m]);
} else if (key > currentKey) {
return xref.fetchIfRef(entries[m + 1]);
class NameTree extends NameOrNumberTree {
constructor(root, xref) {
super(root, xref, "Names");
class NumberTree extends NameOrNumberTree {
constructor(root, xref) {
super(root, xref, "Nums");
;// CONCATENATED MODULE: ./src/core/cleanup_helper.js
function clearGlobalCaches() {
;// CONCATENATED MODULE: ./src/core/file_spec.js
function pickPlatformItem(dict) {
if (!(dict instanceof Dict)) {
} else if (dict.has("F")) {
} else if (dict.has("Unix")) {
} else if (dict.has("Mac")) {
} else if (dict.has("DOS")) {
function stripPath(str) {
return str.substring(str.lastIndexOf("/") + 1);
#contentAvailable = false;
constructor(root, xref, skipContent = false) {
if (!(root instanceof Dict)) {
this.fs = root.get("FS");
warn("Related file specifications are not supported");
this.#contentAvailable = true;
warn("Non-embedded file specifications are not supported");
const item = pickPlatformItem(this.root);
if (item && typeof item === "string") {
filename = stringToPDFString(item).replaceAll("\\\\", "\\").replaceAll("\\/", "/").replaceAll("\\", "/");
return shadow(this, "filename", filename || "unnamed");
if (!this.#contentAvailable) {
this._contentRef ||= pickPlatformItem(this.root?.get("EF"));
const fileObj = this.xref.fetchIfRef(this._contentRef);
if (fileObj instanceof BaseStream) {
content = fileObj.getBytes();
warn("Embedded file specification points to non-existing/invalid content");
warn("Embedded file specification does not have any content");
const desc = this.root?.get("Desc");
if (desc && typeof desc === "string") {
description = stringToPDFString(desc);
return shadow(this, "description", description);
rawFilename: this.filename,
filename: stripPath(this.filename),
description: this.description
;// CONCATENATED MODULE: ./src/core/xml_parser.js
const XMLParserErrorCode = {
UnterminatedXmlDeclaration: -3,
UnterminatedDoctypeDeclaration: -4,
UnterminatedAttributeValue: -8,