: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
for (let i = 0, j = 0, ii = options.length; i < ii; i++) {
if (options[i].exportValue === values[j]) {
async _getAppearance(evaluator, task, intent, annotationStorage) {
return super._getAppearance(evaluator, task, intent, annotationStorage);
let exportedValue, rotation;
const storageEntry = annotationStorage?.get(this.data.id);
rotation = storageEntry.rotation;
exportedValue = storageEntry.value;
if (rotation === undefined && exportedValue === undefined && !this._needAppearances) {
if (exportedValue === undefined) {
exportedValue = this.data.fieldValue;
} else if (!Array.isArray(exportedValue)) {
exportedValue = [exportedValue];
const defaultPadding = 1;
const defaultHPadding = 2;
let totalHeight = this.data.rect[3] - this.data.rect[1];
let totalWidth = this.data.rect[2] - this.data.rect[0];
if (rotation === 90 || rotation === 270) {
[totalWidth, totalHeight] = [totalHeight, totalWidth];
const lineCount = this.data.options.length;
for (let i = 0; i < lineCount; i++) {
} = this.data.options[i];
if (exportedValue.includes(exportValue)) {
if (!this._defaultAppearance) {
this.data.defaultAppearanceData = parseDefaultAppearance(this._defaultAppearance = "/Helvetica 0 Tf 0 g");
const font = await WidgetAnnotation._getFontData(evaluator, task, this.data.defaultAppearanceData, this._fieldResources.mergedResources);
} = this.data.defaultAppearanceData;
const lineHeight = (totalHeight - defaultPadding) / lineCount;
} of this.data.options) {
const width = this._getTextWidth(displayValue, font);
[defaultAppearance, fontSize] = this._computeFontSize(lineHeight, totalWidth - 2 * defaultHPadding, value, font, -1);
defaultAppearance = this._defaultAppearance;
const lineHeight = fontSize * LINE_FACTOR;
const vPadding = (lineHeight - fontSize) / 2;
const numberOfVisibleLines = Math.floor(totalHeight / lineHeight);
if (valueIndices.length > 0) {
const minIndex = Math.min(...valueIndices);
const maxIndex = Math.max(...valueIndices);
firstIndex = Math.max(0, maxIndex - numberOfVisibleLines + 1);
if (firstIndex > minIndex) {
const end = Math.min(firstIndex + numberOfVisibleLines + 1, lineCount);
const buf = ["/Tx BMC q", `1 1 ${totalWidth} ${totalHeight} re W n`];
if (valueIndices.length) {
buf.push("0.600006 0.756866 0.854904 rg");
for (const index of valueIndices) {
if (firstIndex <= index && index < end) {
buf.push(`1 ${totalHeight - (index - firstIndex + 1) * lineHeight} ${totalWidth} ${lineHeight} re f`);
buf.push("BT", defaultAppearance, `1 0 0 1 0 ${totalHeight} Tm`);
for (let i = firstIndex; i < end; i++) {
} = this.data.options[i];
const vpadding = i === firstIndex ? vPadding : 0;
buf.push(this._renderText(displayValue, font, fontSize, totalWidth, 0, prevInfo, defaultHPadding, -lineHeight + vpadding));
class SignatureWidgetAnnotation extends WidgetAnnotation {
this.data.fieldValue = null;
this.data.hasOwnCanvas = this.data.noRotate;
this.data.noHTML = !this.data.hasOwnCanvas;
page: this.data.pageIndex,
class TextAnnotation extends MarkupAnnotation {
const DEFAULT_ICON_SIZE = 22;
this.data.noRotate = true;
this.data.hasOwnCanvas = this.data.noRotate;
this.data.noHTML = false;
this.data.annotationType = AnnotationType.TEXT;
if (this.data.hasAppearance) {
this.data.name = "NoIcon";
this.data.rect[1] = this.data.rect[3] - DEFAULT_ICON_SIZE;
this.data.rect[2] = this.data.rect[0] + DEFAULT_ICON_SIZE;
this.data.name = dict.has("Name") ? dict.get("Name").name : "Note";
this.data.state = dict.get("State") || null;
this.data.stateModel = dict.get("StateModel") || null;
this.data.stateModel = null;
class LinkAnnotation extends Annotation {
this.data.annotationType = AnnotationType.LINK;
this.data.noHTML = false;
const quadPoints = getQuadPoints(dict, this.rectangle);
this.data.quadPoints = quadPoints;
this.data.borderColor ||= this.data.color;
Catalog.parseDestDictionary({
docBaseUrl: annotationGlobals.baseUrl,
docAttachments: annotationGlobals.attachments
class PopupAnnotation extends Annotation {
this.data.annotationType = AnnotationType.POPUP;
this.data.noHTML = false;
if (this.data.rect[0] === this.data.rect[2] || this.data.rect[1] === this.data.rect[3]) {
let parentItem = dict.get("Parent");
warn("Popup annotation has a missing or invalid parent annotation.");
this.data.parentRect = lookupNormalRect(parentItem.getArray("Rect"), null);
const rt = parentItem.get("RT");
if (isName(rt, AnnotationReplyType.GROUP)) {
parentItem = parentItem.get("IRT");
if (!parentItem.has("M")) {
this.data.modificationDate = null;
this.setModificationDate(parentItem.get("M"));
this.data.modificationDate = this.modificationDate;
if (!parentItem.has("C")) {
this.setColor(parentItem.getArray("C"));
this.data.color = this.color;
const parentFlags = parentItem.get("F");
if (this._isViewable(parentFlags)) {
this.setFlags(parentFlags);
this.setTitle(parentItem.get("T"));
this.data.titleObj = this._title;
this.setContents(parentItem.get("Contents"));
this.data.contentsObj = this._contents;
if (parentItem.has("RC")) {
this.data.richText = XFAFactory.getRichTextAsHtml(parentItem.get("RC"));
this.data.open = !!dict.get("Open");
class FreeTextAnnotation extends MarkupAnnotation {
this.data.hasOwnCanvas = !this.data.noHTML;
this.data.noHTML = false;
this.data.annotationType = AnnotationType.FREETEXT;
this.setDefaultAppearance(params);
this._hasAppearance = !!this.appearance;
if (this._hasAppearance) {
} = parseAppearanceStream(this.appearance, evaluatorOptions, xref);
this.data.defaultAppearanceData.fontColor = fontColor;
this.data.defaultAppearanceData.fontSize = fontSize || 10;
this.data.defaultAppearanceData.fontSize ||= 10;
} = this.data.defaultAppearanceData;
if (this._contents.str) {
this.data.textContent = this._contents.str.split(/\r\n?|\n/).map(line => line.trimEnd());
} = FakeUnicodeFont.getFirstPositionInfo(this.rectangle, this.rotation, fontSize);
this.data.textPosition = this._transformPoint(coords, bbox, matrix);
if (this._isOffscreenCanvasSupported) {
const strokeAlpha = params.dict.get("CA");
const fakeUnicodeFont = new FakeUnicodeFont(xref, "sans-serif");
this.appearance = fakeUnicodeFont.createAppearance(this._contents.str, this.rectangle, this.rotation, fontSize, fontColor, strokeAlpha);
this._streams.push(this.appearance);
warn("FreeTextAnnotation: OffscreenCanvas is not supported, annotation may not render correctly.");
return this._hasAppearance;
static createNewDict(annotation, xref, {
const freetext = new Dict(xref);
freetext.set("Type", Name.get("Annot"));
freetext.set("Subtype", Name.get("FreeText"));
freetext.set("CreationDate", `D:${getModificationDate()}`);
freetext.set("Rect", rect);
const da = `/Helv ${fontSize} Tf ${getPdfColor(color, true)}`;
freetext.set("Contents", isAscii(value) ? value : stringToUTF16String(value, true));
freetext.set("Border", [0, 0, 0]);
freetext.set("Rotate", rotation);
freetext.set("T", isAscii(user) ? user : stringToUTF16String(user, true));
const n = new Dict(xref);
static async createNewAppearanceStream(annotation, xref, params) {
const resources = new Dict(xref);
const font = new Dict(xref);
font.set("Helv", baseFontRef);
const baseFont = new Dict(xref);
baseFont.set("BaseFont", Name.get("Helvetica"));
baseFont.set("Type", Name.get("Font"));
baseFont.set("Subtype", Name.get("Type1"));
baseFont.set("Encoding", Name.get("WinAnsiEncoding"));
font.set("Helv", baseFont);
resources.set("Font", font);
const helv = await WidgetAnnotation._getFontData(evaluator, task, {
const [x1, y1, x2, y2] = rect;
if (rotation % 180 !== 0) {
const lines = value.split("\n");
const scale = fontSize / 1000;
let totalWidth = -Infinity;
for (let line of lines) {
const encoded = helv.encodeString(line);
if (encoded.length > 1) {
const glyphs = helv.charsToGlyphs(line);
for (const glyph of glyphs) {
lineWidth += glyph.width * scale;
totalWidth = Math.max(totalWidth, lineWidth);
const lineHeight = LINE_FACTOR * fontSize;
const lineAscent = (LINE_FACTOR - LINE_DESCENT_FACTOR) * fontSize;
const totalHeight = lineHeight * lines.length;
vscale = h / totalHeight;
const fscale = Math.min(hscale, vscale);
const newFontSize = fontSize * fscale;
let firstPoint, clipBox, matrix;
clipBox = [rect[0], rect[1], w, h];
firstPoint = [rect[0], rect[3] - lineAscent];
clipBox = [rect[1], -rect[2], w, h];
firstPoint = [rect[1], -rect[0] - lineAscent];
clipBox = [-rect[2], -rect[3], w, h];
firstPoint = [-rect[2], -rect[1] - lineAscent];
clipBox = [-rect[3], rect[0], w, h];
firstPoint = [-rect[3], rect[2] - lineAscent];
const buffer = ["q", `${matrix.join(" ")} 0 0 cm`, `${clipBox.join(" ")} re W n`, `BT`, `${getPdfColor(color, true)}`, `0 Tc /Helv ${numberToString(newFontSize)} Tf`];
buffer.push(`${firstPoint.join(" ")} Td (${escapeString(encodedLines[0])}) Tj`);
const vShift = numberToString(lineHeight);
for (let i = 1, ii = encodedLines.length; i < ii; i++) {
const line = encodedLines[i];
buffer.push(`0 -${vShift} Td (${escapeString(line)}) Tj`);
const appearance = buffer.join("\n");
const appearanceStreamDict = new Dict(xref);
appearanceStreamDict.set("FormType", 1);
appearanceStreamDict.set("Subtype", Name.get("Form"));
appearanceStreamDict.set("Type", Name.get("XObject"));
appearanceStreamDict.set("BBox", rect);
appearanceStreamDict.set("Resources", resources);
appearanceStreamDict.set("Matrix", [1, 0, 0, 1, -rect[0], -rect[1]]);
const ap = new StringStream(appearance);
ap.dict = appearanceStreamDict;
class LineAnnotation extends MarkupAnnotation {
this.data.annotationType = AnnotationType.LINE;
this.data.hasOwnCanvas = this.data.noRotate;
this.data.noHTML = false;
const lineCoordinates = lookupRect(dict.getArray("L"), [0, 0, 0, 0]);
this.data.lineCoordinates = Util.normalizeRect(lineCoordinates);
this.setLineEndings(dict.getArray("LE"));
this.data.lineEndings = this.lineEndings;
const strokeColor = this.color ? getPdfColorArray(this.color) : [0, 0, 0];
const strokeAlpha = dict.get("CA");
const interiorColor = getRgbColor(dict.getArray("IC"), null);
const fillColor = interiorColor ? getPdfColorArray(interiorColor) : null;
const fillAlpha = fillColor ? strokeAlpha : null;
const borderWidth = this.borderStyle.width || 1,
borderAdjust = 2 * borderWidth;
const bbox = [this.data.lineCoordinates[0] - borderAdjust, this.data.lineCoordinates[1] - borderAdjust, this.data.lineCoordinates[2] + borderAdjust, this.data.lineCoordinates[3] + borderAdjust];
if (!Util.intersect(this.rectangle, bbox)) {
this._setDefaultAppearance({
extra: `${borderWidth} w`,
pointsCallback: (buffer, points) => {
buffer.push(`${lineCoordinates[0]} ${lineCoordinates[1]} m`, `${lineCoordinates[2]} ${lineCoordinates[3]} l`, "S");
return [points[0].x - borderWidth, points[1].x + borderWidth, points[3].y - borderWidth, points[1].y + borderWidth];
class SquareAnnotation extends MarkupAnnotation {
this.data.annotationType = AnnotationType.SQUARE;
this.data.hasOwnCanvas = this.data.noRotate;
this.data.noHTML = false;
const strokeColor = this.color ? getPdfColorArray(this.color) : [0, 0, 0];
const strokeAlpha = dict.get("CA");
const interiorColor = getRgbColor(dict.getArray("IC"), null);
const fillColor = interiorColor ? getPdfColorArray(interiorColor) : null;
const fillAlpha = fillColor ? strokeAlpha : null;
if (this.borderStyle.width === 0 && !fillColor) {
this._setDefaultAppearance({
extra: `${this.borderStyle.width} w`,
pointsCallback: (buffer, points) => {
const x = points[2].x + this.borderStyle.width / 2;
const y = points[2].y + this.borderStyle.width / 2;
const width = points[3].x - points[2].x - this.borderStyle.width;
const height = points[1].y - points[3].y - this.borderStyle.width;
buffer.push(`${x} ${y} ${width} ${height} re`);
return [points[0].x, points[1].x, points[3].y, points[1].y];