: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
if (!isOffscreenCanvasSupported) {
const image = await imagePromises.get(annotation.bitmapId);
const smaskRef = xref.getNewTemporaryRef();
await writeObject(smaskRef, smaskStream, buffer, xref);
imageStream.dict.set("SMask", smaskRef);
const imageRef = image.imageRef = xref.getNewTemporaryRef();
await writeObject(imageRef, imageStream, buffer, xref);
image.imageStream = image.smaskStream = null;
promises.push(StampAnnotation.createNewAnnotation(xref, annotation, dependencies, {
annotations: await Promise.all(promises),
static async printNewAnnotations(annotationGlobals, evaluator, task, annotations, imagePromises) {
for (const annotation of annotations) {
if (annotation.deleted) {
switch (annotation.annotationType) {
case AnnotationEditorType.FREETEXT:
promises.push(FreeTextAnnotation.createNewPrintAnnotation(annotationGlobals, xref, annotation, {
evaluatorOptions: options
case AnnotationEditorType.HIGHLIGHT:
if (annotation.quadPoints) {
promises.push(HighlightAnnotation.createNewPrintAnnotation(annotationGlobals, xref, annotation, {
evaluatorOptions: options
promises.push(InkAnnotation.createNewPrintAnnotation(annotationGlobals, xref, annotation, {
evaluatorOptions: options
case AnnotationEditorType.INK:
promises.push(InkAnnotation.createNewPrintAnnotation(annotationGlobals, xref, annotation, {
evaluatorOptions: options
case AnnotationEditorType.STAMP:
if (!options.isOffscreenCanvasSupported) {
const image = await imagePromises.get(annotation.bitmapId);
imageStream.dict.set("SMask", smaskStream);
image.imageRef = new JpegStream(imageStream, imageStream.length);
image.imageStream = image.smaskStream = null;
promises.push(StampAnnotation.createNewPrintAnnotation(annotationGlobals, xref, annotation, {
evaluatorOptions: options
return Promise.all(promises);
function getRgbColor(color, defaultColor = new Uint8ClampedArray(3)) {
if (!Array.isArray(color)) {
const rgbColor = defaultColor || new Uint8ClampedArray(3);
ColorSpace.singletons.gray.getRgbItem(color, 0, rgbColor, 0);
ColorSpace.singletons.rgb.getRgbItem(color, 0, rgbColor, 0);
ColorSpace.singletons.cmyk.getRgbItem(color, 0, rgbColor, 0);
function getPdfColorArray(color) {
return Array.from(color, c => c / 255);
function getQuadPoints(dict, rect) {
const quadPoints = dict.getArray("QuadPoints");
if (!isNumberArray(quadPoints, null) || quadPoints.length === 0 || quadPoints.length % 8 > 0) {
const quadPointsLists = [];
for (let i = 0, ii = quadPoints.length / 8; i < ii; i++) {
for (let j = i * 8, jj = i * 8 + 8; j < jj; j += 2) {
const y = quadPoints[j + 1];
minX = Math.min(x, minX);
maxX = Math.max(x, maxX);
minY = Math.min(y, minY);
maxY = Math.max(y, maxY);
if (rect !== null && (minX < rect[0] || maxX > rect[2] || minY < rect[1] || maxY > rect[3])) {
function getTransformMatrix(rect, bbox, matrix) {
const [minX, minY, maxX, maxY] = Util.getAxialAlignedBoundingBox(bbox, matrix);
if (minX === maxX || minY === maxY) {
return [1, 0, 0, 1, rect[0], rect[1]];
const xRatio = (rect[2] - rect[0]) / (maxX - minX);
const yRatio = (rect[3] - rect[1]) / (maxY - minY);
return [xRatio, 0, 0, yRatio, rect[0] - minX * xRatio, rect[1] - minY * yRatio];
this.setTitle(dict.get("T"));
this.setContents(dict.get("Contents"));
this.setModificationDate(dict.get("M"));
this.setFlags(dict.get("F"));
this.setRectangle(dict.getArray("Rect"));
this.setColor(dict.getArray("C"));
this.setBorderStyle(dict);
this.setAppearance(dict);
this.setOptionalContent(dict);
const MK = dict.get("MK");
this.setBorderAndBackgroundColors(MK);
this.setRotation(MK, dict);
this.ref = params.ref instanceof Ref ? params.ref : null;
this._streams.push(this.appearance);
const isLocked = !!(this.flags & AnnotationFlag.LOCKED);
const isContentLocked = !!(this.flags & AnnotationFlag.LOCKEDCONTENTS);
if (annotationGlobals.structTreeRoot) {
let structParent = dict.get("StructParent");
structParent = Number.isInteger(structParent) && structParent >= 0 ? structParent : -1;
annotationGlobals.structTreeRoot.addAnnotationIdToPage(params.pageRef, structParent);
annotationFlags: this.flags,
borderStyle: this.borderStyle,
backgroundColor: this.backgroundColor,
borderColor: this.borderColor,
contentsObj: this._contents,
hasAppearance: !!this.appearance,
modificationDate: this.modificationDate,
noRotate: !!(this.flags & AnnotationFlag.NOROTATE),
noHTML: isLocked && isContentLocked
if (params.collectFields) {
const kids = dict.get("Kids");
if (Array.isArray(kids)) {
for (const kid of kids) {
if (kid instanceof Ref) {
kidIds.push(kid.toString());
if (kidIds.length !== 0) {
this.data.kidIds = kidIds;
this.data.actions = collectActions(xref, dict, AnnotationActionEventType);
this.data.fieldName = this._constructFieldName(dict);
this.data.pageIndex = params.pageIndex;
this._isOffscreenCanvasSupported = params.evaluatorOptions.isOffscreenCanvasSupported;
this._fallbackFontDict = null;
this._needAppearances = false;
return !this._hasFlag(flags, AnnotationFlag.INVISIBLE) && !this._hasFlag(flags, AnnotationFlag.NOVIEW);
return this._hasFlag(flags, AnnotationFlag.PRINT) && !this._hasFlag(flags, AnnotationFlag.HIDDEN) && !this._hasFlag(flags, AnnotationFlag.INVISIBLE);
mustBeViewed(annotationStorage, _renderForms) {
const noView = annotationStorage?.get(this.data.id)?.noView;
if (noView !== undefined) {
return this.viewable && !this._hasFlag(this.flags, AnnotationFlag.HIDDEN);
mustBePrinted(annotationStorage) {
const noPrint = annotationStorage?.get(this.data.id)?.noPrint;
if (noPrint !== undefined) {
if (this.data.quadPoints === null) {
return this._isViewable(this.flags);
if (this.data.quadPoints === null) {
return this._isPrintable(this.flags);
_parseStringHelper(data) {
const str = typeof data === "string" ? stringToPDFString(data) : "";
const dir = str && bidi(str).dir === "rtl" ? "rtl" : "ltr";
setDefaultAppearance(params) {
const defaultAppearance = getInheritableProperty({
}) || annotationGlobals.acroForm.get("DA");
this._defaultAppearance = typeof defaultAppearance === "string" ? defaultAppearance : "";
this.data.defaultAppearanceData = parseDefaultAppearance(this._defaultAppearance);
this._title = this._parseStringHelper(title);
this._contents = this._parseStringHelper(contents);
setModificationDate(modificationDate) {
this.modificationDate = typeof modificationDate === "string" ? modificationDate : null;
this.flags = Number.isInteger(flags) && flags > 0 ? flags : 0;
if (this.flags & AnnotationFlag.INVISIBLE && this.constructor.name !== "Annotation") {
this.flags ^= AnnotationFlag.INVISIBLE;
return this._hasFlag(this.flags, flag);
setRectangle(rectangle) {
this.rectangle = lookupNormalRect(rectangle, [0, 0, 0, 0]);
this.color = getRgbColor(color);
setLineEndings(lineEndings) {
this.lineEndings = ["None", "None"];
if (Array.isArray(lineEndings) && lineEndings.length === 2) {
for (let i = 0; i < 2; i++) {
const obj = lineEndings[i];
if (obj instanceof Name) {
this.lineEndings[i] = obj.name;
warn(`Ignoring invalid lineEnding: ${obj}`);
let angle = mk instanceof Dict ? mk.get("R") || 0 : dict.get("Rotate") || 0;
if (Number.isInteger(angle) && angle !== 0) {
setBorderAndBackgroundColors(mk) {
if (mk instanceof Dict) {
this.borderColor = getRgbColor(mk.getArray("BC"), null);
this.backgroundColor = getRgbColor(mk.getArray("BG"), null);
this.borderColor = this.backgroundColor = null;
setBorderStyle(borderStyle) {
this.borderStyle = new AnnotationBorderStyle();
if (!(borderStyle instanceof Dict)) {
if (borderStyle.has("BS")) {
const dict = borderStyle.get("BS");
if (dict instanceof Dict) {
const dictType = dict.get("Type");
if (!dictType || isName(dictType, "Border")) {
this.borderStyle.setWidth(dict.get("W"), this.rectangle);
this.borderStyle.setStyle(dict.get("S"));
this.borderStyle.setDashArray(dict.getArray("D"));
} else if (borderStyle.has("Border")) {
const array = borderStyle.getArray("Border");
if (Array.isArray(array) && array.length >= 3) {
this.borderStyle.setHorizontalCornerRadius(array[0]);
this.borderStyle.setVerticalCornerRadius(array[1]);
this.borderStyle.setWidth(array[2], this.rectangle);
if (array.length === 4) {
this.borderStyle.setDashArray(array[3], true);
this.borderStyle.setWidth(0);
const appearanceStates = dict.get("AP");
if (!(appearanceStates instanceof Dict)) {
const normalAppearanceState = appearanceStates.get("N");
if (normalAppearanceState instanceof BaseStream) {
this.appearance = normalAppearanceState;
if (!(normalAppearanceState instanceof Dict)) {
const as = dict.get("AS");
if (!(as instanceof Name) || !normalAppearanceState.has(as.name)) {
const appearance = normalAppearanceState.get(as.name);
if (appearance instanceof BaseStream) {
this.appearance = appearance;
setOptionalContent(dict) {
const oc = dict.get("OC");
if (oc instanceof Name) {
warn("setOptionalContent: Support for /Name-entry is not implemented.");
} else if (oc instanceof Dict) {
loadResources(keys, appearance) {
return appearance.dict.getAsync("Resources").then(resources => {
const objectLoader = new ObjectLoader(resources, keys, resources.xref);
return objectLoader.load().then(function () {
async getOperatorList(evaluator, task, intent, renderForms, annotationStorage) {
let appearance = this.appearance;
const isUsingOwnCanvas = !!(hasOwnCanvas && intent & RenderingIntentFlag.DISPLAY);
if (isUsingOwnCanvas && (rect[0] === rect[2] || rect[1] === rect[3])) {
this.data.hasOwnCanvas = false;
opList: new OperatorList(),
opList: new OperatorList(),
appearance = new StringStream("");
appearance.dict = new Dict();
const appearanceDict = appearance.dict;
const resources = await this.loadResources(["ExtGState", "ColorSpace", "Pattern", "Shading", "XObject", "Font"], appearance);
const bbox = lookupRect(appearanceDict.getArray("BBox"), [0, 0, 1, 1]);
const matrix = lookupMatrix(appearanceDict.getArray("Matrix"), IDENTITY_MATRIX);
const transform = getTransformMatrix(rect, bbox, matrix);
const opList = new OperatorList();
optionalContent = await evaluator.parseMarkedContentProps(this.oc, null);
if (optionalContent !== undefined) {
opList.addOp(OPS.beginMarkedContentProps, ["OC", optionalContent]);
opList.addOp(OPS.beginAnnotation, [id, rect, transform, matrix, isUsingOwnCanvas]);
await evaluator.getOperatorList({
fallbackFontDict: this._fallbackFontDict
opList.addOp(OPS.endAnnotation, []);
if (optionalContent !== undefined) {
opList.addOp(OPS.endMarkedContent, []);