: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
intentState.renderTasks.delete(internalRenderTask);
if (this._maybeCleanupAfterRender || intentPrint) {
this.#pendingCleanup = true;
this.#tryCleanup(!intentPrint);
internalRenderTask.capability.reject(error);
this._abortOperatorList({
reason: error instanceof Error ? error : new Error(error)
internalRenderTask.capability.resolve();
this._stats.timeEnd("Rendering");
this._stats.timeEnd("Overall");
if (globalThis.Stats?.enabled) {
globalThis.Stats.add(this.pageNumber, this._stats);
const internalRenderTask = new InternalRenderTask({
commonObjs: this.commonObjs,
operatorList: intentState.operatorList,
pageIndex: this._pageIndex,
canvasFactory: this._transport.canvasFactory,
filterFactory: this._transport.filterFactory,
useRequestAnimationFrame: !intentPrint,
(intentState.renderTasks ||= new Set()).add(internalRenderTask);
const renderTask = internalRenderTask.task;
Promise.all([intentState.displayReadyCapability.promise, optionalContentConfigPromise]).then(([transparency, optionalContentConfig]) => {
this._stats?.time("Rendering");
if (!(optionalContentConfig.renderingIntent & renderingIntent)) {
throw new Error("Must use the same `intent`-argument when calling the `PDFPageProxy.render` " + "and `PDFDocumentProxy.getOptionalContentConfig` methods.");
internalRenderTask.initializeGraphics({
internalRenderTask.operatorListChanged();
annotationMode = AnnotationMode.ENABLE,
printAnnotationStorage = null
function operatorListChanged() {
if (intentState.operatorList.lastChunk) {
intentState.opListReadCapability.resolve(intentState.operatorList);
intentState.renderTasks.delete(opListTask);
const intentArgs = this._transport.getRenderingIntent(intent, annotationMode, printAnnotationStorage, true);
let intentState = this._intentStates.get(intentArgs.cacheKey);
intentState = Object.create(null);
this._intentStates.set(intentArgs.cacheKey, intentState);
if (!intentState.opListReadCapability) {
opListTask = Object.create(null);
opListTask.operatorListChanged = operatorListChanged;
intentState.opListReadCapability = Promise.withResolvers();
(intentState.renderTasks ||= new Set()).add(opListTask);
intentState.operatorList = {
this._stats?.time("Page Request");
this._pumpOperatorList(intentArgs);
return intentState.opListReadCapability.promise;
includeMarkedContent = false,
disableNormalization = false
const TEXT_CONTENT_CHUNK_SIZE = 100;
return this._transport.messageHandler.sendWithStream("GetTextContent", {
pageIndex: this._pageIndex,
includeMarkedContent: includeMarkedContent === true,
disableNormalization: disableNormalization === true
highWaterMark: TEXT_CONTENT_CHUNK_SIZE,
return textContent.items.length;
getTextContent(params = {}) {
if (this._transport._htmlForXfa) {
return this.getXfa().then(xfa => XfaText.textContent(xfa));
const readableStream = this.streamTextContent(params);
return new Promise(function (resolve, reject) {
reader.read().then(function ({
textContent.lang ??= value.lang;
Object.assign(textContent.styles, value.styles);
textContent.items.push(...value.items);
const reader = readableStream.getReader();
styles: Object.create(null),
return this._transport.getStructTree(this._pageIndex);
for (const intentState of this._intentStates.values()) {
this._abortOperatorList({
reason: new Error("Page was destroyed."),
if (intentState.opListReadCapability) {
for (const internalRenderTask of intentState.renderTasks) {
waitOn.push(internalRenderTask.completed);
internalRenderTask.cancel();
this.#pendingCleanup = false;
this.#abortDelayedCleanup();
return Promise.all(waitOn);
cleanup(resetStats = false) {
this.#pendingCleanup = true;
const success = this.#tryCleanup(false);
if (resetStats && success) {
this._stats &&= new StatTimer();
#tryCleanup(delayed = false) {
this.#abortDelayedCleanup();
if (!this.#pendingCleanup || this.destroyed) {
this.#delayedCleanupTimeout = setTimeout(() => {
this.#delayedCleanupTimeout = null;
}, DELAYED_CLEANUP_TIMEOUT);
} of this._intentStates.values()) {
if (renderTasks.size > 0 || !operatorList.lastChunk) {
this._intentStates.clear();
this.#pendingCleanup = false;
if (this.#delayedCleanupTimeout) {
clearTimeout(this.#delayedCleanupTimeout);
this.#delayedCleanupTimeout = null;
_startRenderPage(transparency, cacheKey) {
const intentState = this._intentStates.get(cacheKey);
this._stats?.timeEnd("Page Request");
intentState.displayReadyCapability?.resolve(transparency);
_renderPageChunk(operatorListChunk, intentState) {
for (let i = 0, ii = operatorListChunk.length; i < ii; i++) {
intentState.operatorList.fnArray.push(operatorListChunk.fnArray[i]);
intentState.operatorList.argsArray.push(operatorListChunk.argsArray[i]);
intentState.operatorList.lastChunk = operatorListChunk.lastChunk;
intentState.operatorList.separateAnnots = operatorListChunk.separateAnnots;
for (const internalRenderTask of intentState.renderTasks) {
internalRenderTask.operatorListChanged();
if (operatorListChunk.lastChunk) {
annotationStorageSerializable
} = annotationStorageSerializable;
const readableStream = this._transport.messageHandler.sendWithStream("GetOperatorList", {
pageIndex: this._pageIndex,
const reader = readableStream.getReader();
const intentState = this._intentStates.get(cacheKey);
intentState.streamReader = reader;
intentState.streamReader = null;
if (this._transport.destroyed) {
this._renderPageChunk(value, intentState);
intentState.streamReader = null;
if (this._transport.destroyed) {
if (intentState.operatorList) {
intentState.operatorList.lastChunk = true;
for (const internalRenderTask of intentState.renderTasks) {
internalRenderTask.operatorListChanged();
if (intentState.displayReadyCapability) {
intentState.displayReadyCapability.reject(reason);
} else if (intentState.opListReadCapability) {
intentState.opListReadCapability.reject(reason);
if (!intentState.streamReader) {
if (intentState.streamReaderCancelTimeout) {
clearTimeout(intentState.streamReaderCancelTimeout);
intentState.streamReaderCancelTimeout = null;
if (intentState.renderTasks.size > 0) {
if (reason instanceof RenderingCancelledException) {
let delay = RENDERING_CANCELLED_TIMEOUT;
if (reason.extraDelay > 0 && reason.extraDelay < 1000) {
delay += reason.extraDelay;
intentState.streamReaderCancelTimeout = setTimeout(() => {
intentState.streamReaderCancelTimeout = null;
this._abortOperatorList({
intentState.streamReader.cancel(new AbortException(reason.message)).catch(() => {});
intentState.streamReader = null;
if (this._transport.destroyed) {
for (const [curCacheKey, curIntentState] of this._intentStates) {
if (curIntentState === intentState) {
this._intentStates.delete(curCacheKey);
#deferred = Promise.resolve();
postMessage(obj, transfer) {
data: structuredClone(obj, transfer ? {
this.#deferred.then(() => {
for (const listener of this.#listeners) {
listener.call(this, event);
addEventListener(name, listener) {
this.#listeners.add(listener);
removeEventListener(name, listener) {
this.#listeners.delete(listener);
PDFWorkerUtil.isWorkerDisabled = true;
GlobalWorkerOptions.workerSrc ||= "./pdf.worker.js";
PDFWorkerUtil.isSameOrigin = function (baseUrl, otherUrl) {
if (!base.origin || base.origin === "null") {
const other = new URL(otherUrl, base);
return base.origin === other.origin;
PDFWorkerUtil.createCDNWrapper = function (url) {
const wrapper = `await import("${url}");`;
return URL.createObjectURL(new Blob([wrapper], {
verbosity = getVerbosityLevel()
this.verbosity = verbosity;
this._readyCapability = Promise.withResolvers();
this._messageHandler = null;
if (PDFWorker.#workerPorts?.has(port)) {
throw new Error("Cannot use more than one PDFWorker per port.");
(PDFWorker.#workerPorts ||= new WeakMap()).set(port, this);
this._initializeFromPort(port);
return Promise.all([NodePackages.promise, this._readyCapability.promise]);
return this._readyCapability.promise;
return this._messageHandler;
_initializeFromPort(port) {
this._messageHandler = new MessageHandler("main", "worker", port);
this._messageHandler.on("ready", function () {});
this._readyCapability.resolve();
this._messageHandler.send("configure", {
verbosity: this.verbosity
if (!PDFWorkerUtil.isWorkerDisabled && !PDFWorker.#mainThreadWorkerMessageHandler) {
if (!PDFWorkerUtil.isSameOrigin(window.location.href, workerSrc)) {
workerSrc = PDFWorkerUtil.createCDNWrapper(new URL(workerSrc, window.location).href);
const worker = new Worker(workerSrc, {
const messageHandler = new MessageHandler("main", "worker", worker);
const terminateEarly = () => {
worker.removeEventListener("error", onWorkerError);
messageHandler.destroy();
this._readyCapability.reject(new Error("Worker was destroyed"));
const onWorkerError = () => {
worker.addEventListener("error", onWorkerError);
messageHandler.on("test", data => {
worker.removeEventListener("error", onWorkerError);
this._messageHandler = messageHandler;
this._webWorker = worker;
this._readyCapability.resolve();
messageHandler.send("configure", {
verbosity: this.verbosity
messageHandler.destroy();
messageHandler.on("ready", data => {
worker.removeEventListener("error", onWorkerError);
const testObj = new Uint8Array();
messageHandler.send("test", testObj, [testObj.buffer]);
info("The worker has been disabled.");