[api-minor] Introduce a new annotationMode-option, in PDFPageProxy.{render, getOperatorList}

*This is a follow-up to PRs 13867 and 13899.*

This patch is tagged `api-minor` for the following reasons:
 - It replaces the `renderInteractiveForms`/`includeAnnotationStorage`-options, in the `PDFPageProxy.render`-method, with the single `annotationMode`-option that controls which annotations are being rendered and how. Note that the old options were mutually exclusive, and setting both to `true` would result in undefined behaviour.

 - For improved consistency in the API, the `annotationMode`-option will also work together with the `PDFPageProxy.getOperatorList`-method.

 - It's now also possible to disable *all* annotation rendering in both the API and the Viewer, since the other changes meant that this could now be supported with a single added line on the worker-thread[1]; fixes 7282.

---
[1] Please note that in order to simplify the overall implementation, we'll purposely only support disabling of *all* annotations and that the option is being shared between the API and the Viewer. For any more "specialized" use-cases, where e.g. only some annotation-types are being rendered and/or the API and Viewer render different sets of annotations, that'll have to be handled in third-party implementations/forks of the PDF.js code-base.
This commit is contained in:
Jonas Jenwald 2021-08-08 14:36:28 +02:00
parent 56e7bb626c
commit 41efa3c071
16 changed files with 272 additions and 134 deletions

View File

@ -144,9 +144,15 @@
"description": "Whether to prevent the extension from reporting the extension and browser version to the extension developers.", "description": "Whether to prevent the extension from reporting the extension and browser version to the extension developers.",
"default": false "default": false
}, },
"renderInteractiveForms": { "annotationMode": {
"type": "boolean", "type": "integer",
"default": true "enum": [
0,
1,
2,
3
],
"default": 2
}, },
"enableScripting": { "enableScripting": {
"type": "boolean", "type": "boolean",

View File

@ -380,7 +380,10 @@ class Page {
// page's operator list to render them. // page's operator list to render them.
return Promise.all([pageListPromise, this._parsedAnnotations]).then( return Promise.all([pageListPromise, this._parsedAnnotations]).then(
function ([pageOpList, annotations]) { function ([pageOpList, annotations]) {
if (annotations.length === 0) { if (
annotations.length === 0 ||
intent & RenderingIntentFlag.ANNOTATIONS_DISABLE
) {
pageOpList.flush(true); pageOpList.flush(true);
return { length: pageOpList.totalLength }; return { length: pageOpList.totalLength };
} }

View File

@ -46,7 +46,7 @@ const DEFAULT_TAB_INDEX = 1000;
* @property {AnnotationStorage} [annotationStorage] * @property {AnnotationStorage} [annotationStorage]
* @property {string} [imageResourcesPath] - Path for image resources, mainly * @property {string} [imageResourcesPath] - Path for image resources, mainly
* for annotation icons. Include trailing slash. * for annotation icons. Include trailing slash.
* @property {boolean} renderInteractiveForms * @property {boolean} renderForms
* @property {Object} svgFactory * @property {Object} svgFactory
* @property {boolean} [enableScripting] * @property {boolean} [enableScripting]
* @property {boolean} [hasJSActions] * @property {boolean} [hasJSActions]
@ -154,7 +154,7 @@ class AnnotationElement {
this.linkService = parameters.linkService; this.linkService = parameters.linkService;
this.downloadManager = parameters.downloadManager; this.downloadManager = parameters.downloadManager;
this.imageResourcesPath = parameters.imageResourcesPath; this.imageResourcesPath = parameters.imageResourcesPath;
this.renderInteractiveForms = parameters.renderInteractiveForms; this.renderForms = parameters.renderForms;
this.svgFactory = parameters.svgFactory; this.svgFactory = parameters.svgFactory;
this.annotationStorage = parameters.annotationStorage; this.annotationStorage = parameters.annotationStorage;
this.enableScripting = parameters.enableScripting; this.enableScripting = parameters.enableScripting;
@ -676,7 +676,7 @@ class WidgetAnnotationElement extends AnnotationElement {
class TextWidgetAnnotationElement extends WidgetAnnotationElement { class TextWidgetAnnotationElement extends WidgetAnnotationElement {
constructor(parameters) { constructor(parameters) {
const isRenderable = const isRenderable =
parameters.renderInteractiveForms || parameters.renderForms ||
(!parameters.data.hasAppearance && !!parameters.data.fieldValue); (!parameters.data.hasAppearance && !!parameters.data.fieldValue);
super(parameters, { isRenderable }); super(parameters, { isRenderable });
} }
@ -700,7 +700,7 @@ class TextWidgetAnnotationElement extends WidgetAnnotationElement {
this.container.className = "textWidgetAnnotation"; this.container.className = "textWidgetAnnotation";
let element = null; let element = null;
if (this.renderInteractiveForms) { if (this.renderForms) {
// NOTE: We cannot set the values using `element.value` below, since it // NOTE: We cannot set the values using `element.value` below, since it
// prevents the AnnotationLayer rasterizer in `test/driver.js` // prevents the AnnotationLayer rasterizer in `test/driver.js`
// from parsing the elements correctly for the reference tests. // from parsing the elements correctly for the reference tests.
@ -952,7 +952,7 @@ class TextWidgetAnnotationElement extends WidgetAnnotationElement {
class CheckboxWidgetAnnotationElement extends WidgetAnnotationElement { class CheckboxWidgetAnnotationElement extends WidgetAnnotationElement {
constructor(parameters) { constructor(parameters) {
super(parameters, { isRenderable: parameters.renderInteractiveForms }); super(parameters, { isRenderable: parameters.renderForms });
} }
render() { render() {
@ -1031,7 +1031,7 @@ class CheckboxWidgetAnnotationElement extends WidgetAnnotationElement {
class RadioButtonWidgetAnnotationElement extends WidgetAnnotationElement { class RadioButtonWidgetAnnotationElement extends WidgetAnnotationElement {
constructor(parameters) { constructor(parameters) {
super(parameters, { isRenderable: parameters.renderInteractiveForms }); super(parameters, { isRenderable: parameters.renderForms });
} }
render() { render() {
@ -1123,7 +1123,7 @@ class PushButtonWidgetAnnotationElement extends LinkAnnotationElement {
class ChoiceWidgetAnnotationElement extends WidgetAnnotationElement { class ChoiceWidgetAnnotationElement extends WidgetAnnotationElement {
constructor(parameters) { constructor(parameters) {
super(parameters, { isRenderable: parameters.renderInteractiveForms }); super(parameters, { isRenderable: parameters.renderForms });
} }
render() { render() {
@ -2033,7 +2033,7 @@ class FileAttachmentAnnotationElement extends AnnotationElement {
* @property {DownloadManager} downloadManager * @property {DownloadManager} downloadManager
* @property {string} [imageResourcesPath] - Path for image resources, mainly * @property {string} [imageResourcesPath] - Path for image resources, mainly
* for annotation icons. Include trailing slash. * for annotation icons. Include trailing slash.
* @property {boolean} renderInteractiveForms * @property {boolean} renderForms
* @property {boolean} [enableScripting] - Enable embedded script execution. * @property {boolean} [enableScripting] - Enable embedded script execution.
* @property {boolean} [hasJSActions] - Some fields have JS actions. * @property {boolean} [hasJSActions] - Some fields have JS actions.
* The default value is `false`. * The default value is `false`.
@ -2076,7 +2076,7 @@ class AnnotationLayer {
linkService: parameters.linkService, linkService: parameters.linkService,
downloadManager: parameters.downloadManager, downloadManager: parameters.downloadManager,
imageResourcesPath: parameters.imageResourcesPath || "", imageResourcesPath: parameters.imageResourcesPath || "",
renderInteractiveForms: parameters.renderInteractiveForms !== false, renderForms: parameters.renderForms !== false,
svgFactory: new DOMSVGFactory(), svgFactory: new DOMSVGFactory(),
annotationStorage: annotationStorage:
parameters.annotationStorage || new AnnotationStorage(), parameters.annotationStorage || new AnnotationStorage(),

View File

@ -19,6 +19,7 @@
import { import {
AbortException, AbortException,
AnnotationMode,
assert, assert,
createPromiseCapability, createPromiseCapability,
getVerbosityLevel, getVerbosityLevel,
@ -1135,9 +1136,18 @@ class PDFDocumentProxy {
* the `PDFPageProxy.getViewport` method. * the `PDFPageProxy.getViewport` method.
* @property {string} [intent] - Rendering intent, can be 'display', 'print', * @property {string} [intent] - Rendering intent, can be 'display', 'print',
* or 'any'. The default value is 'display'. * or 'any'. The default value is 'display'.
* @property {boolean} [renderInteractiveForms] - Whether or not interactive * @property {number} [annotationMode] Controls which annotations are rendered
* form elements are rendered in the display layer. If so, we do not render * onto the canvas, for annotations with appearance-data; the values from
* them on the canvas as well. The default value is `false`. * {@link AnnotationMode} should be used. The following values are supported:
* - `AnnotationMode.DISABLE`, which disables all annotations.
* - `AnnotationMode.ENABLE`, which includes all possible annotations (thus
* it also depends on the `intent`-option, see above).
* - `AnnotationMode.ENABLE_FORMS`, which excludes annotations that contain
* interactive form elements (those will be rendered in the display layer).
* - `AnnotationMode.ENABLE_STORAGE`, which includes all possible annotations
* (as above) but where interactive form elements are updated with data
* from the {@link AnnotationStorage}-instance; useful e.g. for printing.
* The default value is `AnnotationMode.ENABLE`.
* @property {Array<any>} [transform] - Additional transform, applied just * @property {Array<any>} [transform] - Additional transform, applied just
* before viewport transform. * before viewport transform.
* @property {Object} [imageLayer] - An object that has `beginLayout`, * @property {Object} [imageLayer] - An object that has `beginLayout`,
@ -1149,9 +1159,6 @@ class PDFDocumentProxy {
* <color> value, a `CanvasGradient` object (a linear or radial gradient) or * <color> value, a `CanvasGradient` object (a linear or radial gradient) or
* a `CanvasPattern` object (a repetitive image). The default value is * a `CanvasPattern` object (a repetitive image). The default value is
* 'rgb(255,255,255)'. * 'rgb(255,255,255)'.
* @property {boolean} [includeAnnotationStorage] - Render stored interactive
* form element data, from the {@link AnnotationStorage}-instance, onto the
* canvas itself; useful e.g. for printing. The default value is `false`.
* @property {Promise<OptionalContentConfig>} [optionalContentConfigPromise] - * @property {Promise<OptionalContentConfig>} [optionalContentConfigPromise] -
* A promise that should resolve with an {@link OptionalContentConfig} * A promise that should resolve with an {@link OptionalContentConfig}
* created from `PDFDocumentProxy.getOptionalContentConfig`. If `null`, * created from `PDFDocumentProxy.getOptionalContentConfig`. If `null`,
@ -1165,6 +1172,18 @@ class PDFDocumentProxy {
* @typedef {Object} GetOperatorListParameters * @typedef {Object} GetOperatorListParameters
* @property {string} [intent] - Rendering intent, can be 'display', 'print', * @property {string} [intent] - Rendering intent, can be 'display', 'print',
* or 'any'. The default value is 'display'. * or 'any'. The default value is 'display'.
* @property {number} [annotationMode] Controls which annotations are included
* in the operatorList, for annotations with appearance-data; the values from
* {@link AnnotationMode} should be used. The following values are supported:
* - `AnnotationMode.DISABLE`, which disables all annotations.
* - `AnnotationMode.ENABLE`, which includes all possible annotations (thus
* it also depends on the `intent`-option, see above).
* - `AnnotationMode.ENABLE_FORMS`, which excludes annotations that contain
* interactive form elements (those will be rendered in the display layer).
* - `AnnotationMode.ENABLE_STORAGE`, which includes all possible annotations
* (as above) but where interactive form elements are updated with data
* from the {@link AnnotationStorage}-instance; useful e.g. for printing.
* The default value is `AnnotationMode.ENABLE`.
*/ */
/** /**
@ -1280,7 +1299,7 @@ class PDFPageProxy {
* {Array} of the annotation objects. * {Array} of the annotation objects.
*/ */
getAnnotations({ intent = "display" } = {}) { getAnnotations({ intent = "display" } = {}) {
const intentArgs = this._transport.getRenderingIntent(intent, {}); const intentArgs = this._transport.getRenderingIntent(intent);
let promise = this._annotationPromises.get(intentArgs.cacheKey); let promise = this._annotationPromises.get(intentArgs.cacheKey);
if (!promise) { if (!promise) {
@ -1324,22 +1343,21 @@ class PDFPageProxy {
canvasContext, canvasContext,
viewport, viewport,
intent = "display", intent = "display",
renderInteractiveForms = false, annotationMode = AnnotationMode.ENABLE,
transform = null, transform = null,
imageLayer = null, imageLayer = null,
canvasFactory = null, canvasFactory = null,
background = null, background = null,
includeAnnotationStorage = false,
optionalContentConfigPromise = null, optionalContentConfigPromise = null,
}) { }) {
if (this._stats) { if (this._stats) {
this._stats.time("Overall"); this._stats.time("Overall");
} }
const intentArgs = this._transport.getRenderingIntent(intent, { const intentArgs = this._transport.getRenderingIntent(
renderForms: renderInteractiveForms === true, intent,
includeAnnotationStorage: includeAnnotationStorage === true, annotationMode
}); );
// If there was a pending destroy, cancel it so no cleanup happens during // If there was a pending destroy, cancel it so no cleanup happens during
// this call to render. // this call to render.
this.pendingCleanup = false; this.pendingCleanup = false;
@ -1460,7 +1478,10 @@ class PDFPageProxy {
* @returns {Promise<PDFOperatorList>} A promise resolved with an * @returns {Promise<PDFOperatorList>} A promise resolved with an
* {@link PDFOperatorList} object that represents the page's operator list. * {@link PDFOperatorList} object that represents the page's operator list.
*/ */
getOperatorList({ intent = "display" } = {}) { getOperatorList({
intent = "display",
annotationMode = AnnotationMode.ENABLE,
} = {}) {
function operatorListChanged() { function operatorListChanged() {
if (intentState.operatorList.lastChunk) { if (intentState.operatorList.lastChunk) {
intentState.opListReadCapability.resolve(intentState.operatorList); intentState.opListReadCapability.resolve(intentState.operatorList);
@ -1469,9 +1490,11 @@ class PDFPageProxy {
} }
} }
const intentArgs = this._transport.getRenderingIntent(intent, { const intentArgs = this._transport.getRenderingIntent(
isOpList: true, intent,
}); annotationMode,
/* isOpList = */ true
);
let intentState = this._intentStates.get(intentArgs.cacheKey); let intentState = this._intentStates.get(intentArgs.cacheKey);
if (!intentState) { if (!intentState) {
intentState = Object.create(null); intentState = Object.create(null);
@ -1792,7 +1815,7 @@ class PDFPageProxy {
} }
} }
intentState.streamReader intentState.streamReader
.cancel(new AbortException(reason?.message)) .cancel(new AbortException(reason.message))
.catch(() => { .catch(() => {
// Avoid "Uncaught promise" messages in the console. // Avoid "Uncaught promise" messages in the console.
}); });
@ -2351,7 +2374,8 @@ class WorkerTransport {
getRenderingIntent( getRenderingIntent(
intent, intent,
{ renderForms = false, includeAnnotationStorage = false, isOpList = false } annotationMode = AnnotationMode.ENABLE,
isOpList = false
) { ) {
let renderingIntent = RenderingIntentFlag.DISPLAY; // Default value. let renderingIntent = RenderingIntentFlag.DISPLAY; // Default value.
let lastModified = ""; let lastModified = "";
@ -2369,13 +2393,22 @@ class WorkerTransport {
warn(`getRenderingIntent - invalid intent: ${intent}`); warn(`getRenderingIntent - invalid intent: ${intent}`);
} }
if (renderForms) { switch (annotationMode) {
renderingIntent += RenderingIntentFlag.ANNOTATIONS_FORMS; case AnnotationMode.DISABLE:
} renderingIntent += RenderingIntentFlag.ANNOTATIONS_DISABLE;
if (includeAnnotationStorage) { break;
renderingIntent += RenderingIntentFlag.ANNOTATIONS_STORAGE; case AnnotationMode.ENABLE:
break;
case AnnotationMode.ENABLE_FORMS:
renderingIntent += RenderingIntentFlag.ANNOTATIONS_FORMS;
break;
case AnnotationMode.ENABLE_STORAGE:
renderingIntent += RenderingIntentFlag.ANNOTATIONS_STORAGE;
lastModified = this.annotationStorage.lastModified; lastModified = this.annotationStorage.lastModified;
break;
default:
warn(`getRenderingIntent - invalid annotationMode: ${annotationMode}`);
} }
if (isOpList) { if (isOpList) {

View File

@ -27,15 +27,7 @@ import {
RenderingCancelledException, RenderingCancelledException,
} from "./display/display_utils.js"; } from "./display/display_utils.js";
import { import {
build, AnnotationMode,
getDocument,
LoopbackPort,
PDFDataRangeTransport,
PDFWorker,
setPDFNetworkStreamFactory,
version,
} from "./display/api.js";
import {
CMapCompressionType, CMapCompressionType,
createObjectURL, createObjectURL,
createPromiseCapability, createPromiseCapability,
@ -52,6 +44,15 @@ import {
Util, Util,
VerbosityLevel, VerbosityLevel,
} from "./shared/util.js"; } from "./shared/util.js";
import {
build,
getDocument,
LoopbackPort,
PDFDataRangeTransport,
PDFWorker,
setPDFNetworkStreamFactory,
version,
} from "./display/api.js";
import { AnnotationLayer } from "./display/annotation_layer.js"; import { AnnotationLayer } from "./display/annotation_layer.js";
import { GlobalWorkerOptions } from "./display/worker_options.js"; import { GlobalWorkerOptions } from "./display/worker_options.js";
import { isNodeJS } from "./shared/is_node.js"; import { isNodeJS } from "./shared/is_node.js";
@ -110,14 +111,8 @@ export {
PDFDateString, PDFDateString,
RenderingCancelledException, RenderingCancelledException,
getXfaPageViewport, getXfaPageViewport,
// From "./display/api.js":
build,
getDocument,
LoopbackPort,
PDFDataRangeTransport,
PDFWorker,
version,
// From "./shared/util.js": // From "./shared/util.js":
AnnotationMode,
CMapCompressionType, CMapCompressionType,
createObjectURL, createObjectURL,
createPromiseCapability, createPromiseCapability,
@ -133,6 +128,13 @@ export {
UNSUPPORTED_FEATURES, UNSUPPORTED_FEATURES,
Util, Util,
VerbosityLevel, VerbosityLevel,
// From "./display/api.js":
build,
getDocument,
LoopbackPort,
PDFDataRangeTransport,
PDFWorker,
version,
// From "./display/annotation_layer.js": // From "./display/annotation_layer.js":
AnnotationLayer, AnnotationLayer,
// From "./display/worker_options.js": // From "./display/worker_options.js":

View File

@ -23,9 +23,10 @@ const FONT_IDENTITY_MATRIX = [0.001, 0, 0, 0.001, 0, 0];
* how these flags are being used: * how these flags are being used:
* - ANY, DISPLAY, and PRINT are the normal rendering intents, note the * - ANY, DISPLAY, and PRINT are the normal rendering intents, note the
* `PDFPageProxy.{render, getOperatorList, getAnnotations}`-methods. * `PDFPageProxy.{render, getOperatorList, getAnnotations}`-methods.
* - ANNOTATIONS_FORMS, and ANNOTATIONS_STORAGE controls which annotations are * - ANNOTATIONS_FORMS, ANNOTATIONS_STORAGE, ANNOTATIONS_DISABLE control which
* rendered onto the canvas, note the `renderInteractiveForms`- respectively * annotations are rendered onto the canvas (i.e. by being included in the
* `includeAnnotationStorage`-options in the `PDFPageProxy.render`-method. * operatorList), note the `PDFPageProxy.{render, getOperatorList}`-methods
* and their `annotationMode`-option.
* - OPLIST is used with the `PDFPageProxy.getOperatorList`-method, note the * - OPLIST is used with the `PDFPageProxy.getOperatorList`-method, note the
* `OperatorList`-constructor (on the worker-thread). * `OperatorList`-constructor (on the worker-thread).
*/ */
@ -35,9 +36,17 @@ const RenderingIntentFlag = {
PRINT: 0x04, PRINT: 0x04,
ANNOTATIONS_FORMS: 0x10, ANNOTATIONS_FORMS: 0x10,
ANNOTATIONS_STORAGE: 0x20, ANNOTATIONS_STORAGE: 0x20,
ANNOTATIONS_DISABLE: 0x40,
OPLIST: 0x100, OPLIST: 0x100,
}; };
const AnnotationMode = {
DISABLE: 0,
ENABLE: 1,
ENABLE_FORMS: 2,
ENABLE_STORAGE: 3,
};
// Permission flags from Table 22, Section 7.6.3.2 of the PDF specification. // Permission flags from Table 22, Section 7.6.3.2 of the PDF specification.
const PermissionFlag = { const PermissionFlag = {
PRINT: 0x04, PRINT: 0x04,
@ -1027,6 +1036,7 @@ export {
AnnotationFieldFlag, AnnotationFieldFlag,
AnnotationFlag, AnnotationFlag,
AnnotationMarkedState, AnnotationMarkedState,
AnnotationMode,
AnnotationReplyType, AnnotationReplyType,
AnnotationReviewState, AnnotationReviewState,
AnnotationStateModelType, AnnotationStateModelType,

View File

@ -17,6 +17,16 @@
"use strict"; "use strict";
const {
AnnotationLayer,
AnnotationMode,
getDocument,
GlobalWorkerOptions,
renderTextLayer,
XfaLayer,
} = pdfjsLib;
const { SimpleLinkService } = pdfjsViewer;
const WAITING_TIME = 100; // ms const WAITING_TIME = 100; // ms
const PDF_TO_CSS_UNITS = 96.0 / 72.0; const PDF_TO_CSS_UNITS = 96.0 / 72.0;
const CMAP_URL = "/build/generic/web/cmaps/"; const CMAP_URL = "/build/generic/web/cmaps/";
@ -162,7 +172,7 @@ var rasterizeTextLayer = (function rasterizeTextLayerClosure() {
style.textContent = cssRules; style.textContent = cssRules;
// Rendering text layer as HTML. // Rendering text layer as HTML.
var task = pdfjsLib.renderTextLayer({ var task = renderTextLayer({
textContent, textContent,
container: div, container: div,
viewport, viewport,
@ -219,7 +229,7 @@ var rasterizeAnnotationLayer = (function rasterizeAnnotationLayerClosure() {
annotations, annotations,
page, page,
imageResourcesPath, imageResourcesPath,
renderInteractiveForms renderForms = false
) { ) {
return new Promise(function (resolve, reject) { return new Promise(function (resolve, reject) {
// Building SVG with size of the viewport. // Building SVG with size of the viewport.
@ -250,11 +260,11 @@ var rasterizeAnnotationLayer = (function rasterizeAnnotationLayerClosure() {
div, div,
annotations, annotations,
page, page,
linkService: new pdfjsViewer.SimpleLinkService(), linkService: new SimpleLinkService(),
imageResourcesPath, imageResourcesPath,
renderInteractiveForms, renderForms,
}; };
pdfjsLib.AnnotationLayer.render(parameters); AnnotationLayer.render(parameters);
// Inline SVG images from text annotations. // Inline SVG images from text annotations.
await resolveImages(div); await resolveImages(div);
@ -319,7 +329,7 @@ var rasterizeXfaLayer = (function rasterizeXfaLayerClosure() {
.then(async cssRules => { .then(async cssRules => {
style.textContent = fontRules + "\n" + cssRules; style.textContent = fontRules + "\n" + cssRules;
pdfjsLib.XfaLayer.render({ XfaLayer.render({
xfa, xfa,
div, div,
viewport: viewport.clone({ dontFlip: true }), viewport: viewport.clone({ dontFlip: true }),
@ -365,7 +375,7 @@ var Driver = (function DriverClosure() {
// eslint-disable-next-line no-shadow // eslint-disable-next-line no-shadow
function Driver(options) { function Driver(options) {
// Configure the global worker options. // Configure the global worker options.
pdfjsLib.GlobalWorkerOptions.workerSrc = WORKER_SRC; GlobalWorkerOptions.workerSrc = WORKER_SRC;
// Set the passed options // Set the passed options
this.inflight = options.inflight; this.inflight = options.inflight;
@ -494,7 +504,7 @@ var Driver = (function DriverClosure() {
.appendChild(xfaStyleElement); .appendChild(xfaStyleElement);
} }
const loadingTask = pdfjsLib.getDocument({ const loadingTask = getDocument({
url: absoluteUrl, url: absoluteUrl,
password: task.password, password: task.password,
cMapUrl: CMAP_URL, cMapUrl: CMAP_URL,
@ -752,12 +762,13 @@ var Driver = (function DriverClosure() {
var renderContext = { var renderContext = {
canvasContext: ctx, canvasContext: ctx,
viewport, viewport,
renderInteractiveForms: renderForms,
optionalContentConfigPromise: task.optionalContentConfigPromise, optionalContentConfigPromise: task.optionalContentConfigPromise,
}; };
if (renderPrint) { if (renderForms) {
renderContext.annotationMode = AnnotationMode.ENABLE_FORMS;
} else if (renderPrint) {
if (task.annotationStorage) { if (task.annotationStorage) {
renderContext.includeAnnotationStorage = true; renderContext.annotationMode = AnnotationMode.ENABLE_STORAGE;
} }
renderContext.intent = "print"; renderContext.intent = "print";
} }

View File

@ -14,11 +14,7 @@
*/ */
import { import {
buildGetDocumentParams, AnnotationMode,
DefaultFileReaderFactory,
TEST_PDFS_PATH,
} from "./test_utils.js";
import {
createPromiseCapability, createPromiseCapability,
FontType, FontType,
ImageKind, ImageKind,
@ -30,6 +26,11 @@ import {
PermissionFlag, PermissionFlag,
StreamType, StreamType,
} from "../../src/shared/util.js"; } from "../../src/shared/util.js";
import {
buildGetDocumentParams,
DefaultFileReaderFactory,
TEST_PDFS_PATH,
} from "./test_utils.js";
import { import {
DefaultCanvasFactory, DefaultCanvasFactory,
getDocument, getDocument,
@ -1739,6 +1740,56 @@ describe("api", function () {
await loadingTask.destroy(); await loadingTask.destroy();
}); });
it("gets operator list, with `annotationMode`-option", async function () {
const loadingTask = getDocument(buildGetDocumentParams("evaljs.pdf"));
const pdfDoc = await loadingTask.promise;
const pdfPage = await pdfDoc.getPage(2);
pdfDoc.annotationStorage.setValue("30R", { value: "test" });
pdfDoc.annotationStorage.setValue("31R", { value: true });
const opListAnnotDisable = await pdfPage.getOperatorList({
annotationMode: AnnotationMode.DISABLE,
});
expect(opListAnnotDisable.fnArray.length).toEqual(0);
expect(opListAnnotDisable.argsArray.length).toEqual(0);
expect(opListAnnotDisable.lastChunk).toEqual(true);
const opListAnnotEnable = await pdfPage.getOperatorList({
annotationMode: AnnotationMode.ENABLE,
});
expect(opListAnnotEnable.fnArray.length).toBeGreaterThan(150);
expect(opListAnnotEnable.argsArray.length).toBeGreaterThan(150);
expect(opListAnnotEnable.lastChunk).toEqual(true);
const opListAnnotEnableForms = await pdfPage.getOperatorList({
annotationMode: AnnotationMode.ENABLE_FORMS,
});
expect(opListAnnotEnableForms.fnArray.length).toBeGreaterThan(40);
expect(opListAnnotEnableForms.argsArray.length).toBeGreaterThan(40);
expect(opListAnnotEnableForms.lastChunk).toEqual(true);
const opListAnnotEnableStorage = await pdfPage.getOperatorList({
annotationMode: AnnotationMode.ENABLE_STORAGE,
});
expect(opListAnnotEnableStorage.fnArray.length).toBeGreaterThan(170);
expect(opListAnnotEnableStorage.argsArray.length).toBeGreaterThan(170);
expect(opListAnnotEnableStorage.lastChunk).toEqual(true);
// Sanity check to ensure that the `annotationMode` is correctly applied.
expect(opListAnnotDisable.fnArray.length).toBeLessThan(
opListAnnotEnableForms.fnArray.length
);
expect(opListAnnotEnableForms.fnArray.length).toBeLessThan(
opListAnnotEnable.fnArray.length
);
expect(opListAnnotEnable.fnArray.length).toBeLessThan(
opListAnnotEnableStorage.fnArray.length
);
await loadingTask.destroy();
});
it("gets document stats after parsing page", async function () { it("gets document stats after parsing page", async function () {
const stats = await page.getOperatorList().then(function () { const stats = await page.getOperatorList().then(function () {
return pdfDocument.getStats(); return pdfDocument.getStats();

View File

@ -24,7 +24,7 @@ import { SimpleLinkService } from "./pdf_link_service.js";
* @property {AnnotationStorage} [annotationStorage] * @property {AnnotationStorage} [annotationStorage]
* @property {string} [imageResourcesPath] - Path for image resources, mainly * @property {string} [imageResourcesPath] - Path for image resources, mainly
* for annotation icons. Include trailing slash. * for annotation icons. Include trailing slash.
* @property {boolean} renderInteractiveForms * @property {boolean} renderForms
* @property {IPDFLinkService} linkService * @property {IPDFLinkService} linkService
* @property {DownloadManager} downloadManager * @property {DownloadManager} downloadManager
* @property {IL10n} l10n - Localization service. * @property {IL10n} l10n - Localization service.
@ -44,7 +44,7 @@ class AnnotationLayerBuilder {
downloadManager, downloadManager,
annotationStorage = null, annotationStorage = null,
imageResourcesPath = "", imageResourcesPath = "",
renderInteractiveForms = true, renderForms = true,
l10n = NullL10n, l10n = NullL10n,
enableScripting = false, enableScripting = false,
hasJSActionsPromise = null, hasJSActionsPromise = null,
@ -55,7 +55,7 @@ class AnnotationLayerBuilder {
this.linkService = linkService; this.linkService = linkService;
this.downloadManager = downloadManager; this.downloadManager = downloadManager;
this.imageResourcesPath = imageResourcesPath; this.imageResourcesPath = imageResourcesPath;
this.renderInteractiveForms = renderInteractiveForms; this.renderForms = renderForms;
this.l10n = l10n; this.l10n = l10n;
this.annotationStorage = annotationStorage; this.annotationStorage = annotationStorage;
this.enableScripting = enableScripting; this.enableScripting = enableScripting;
@ -90,7 +90,7 @@ class AnnotationLayerBuilder {
annotations, annotations,
page: this.pdfPage, page: this.pdfPage,
imageResourcesPath: this.imageResourcesPath, imageResourcesPath: this.imageResourcesPath,
renderInteractiveForms: this.renderInteractiveForms, renderForms: this.renderForms,
linkService: this.linkService, linkService: this.linkService,
downloadManager: this.downloadManager, downloadManager: this.downloadManager,
annotationStorage: this.annotationStorage, annotationStorage: this.annotationStorage,
@ -139,7 +139,7 @@ class DefaultAnnotationLayerFactory {
* @param {AnnotationStorage} [annotationStorage] * @param {AnnotationStorage} [annotationStorage]
* @param {string} [imageResourcesPath] - Path for image resources, mainly * @param {string} [imageResourcesPath] - Path for image resources, mainly
* for annotation icons. Include trailing slash. * for annotation icons. Include trailing slash.
* @param {boolean} renderInteractiveForms * @param {boolean} renderForms
* @param {IL10n} l10n * @param {IL10n} l10n
* @param {boolean} [enableScripting] * @param {boolean} [enableScripting]
* @param {Promise<boolean>} [hasJSActionsPromise] * @param {Promise<boolean>} [hasJSActionsPromise]
@ -151,7 +151,7 @@ class DefaultAnnotationLayerFactory {
pdfPage, pdfPage,
annotationStorage = null, annotationStorage = null,
imageResourcesPath = "", imageResourcesPath = "",
renderInteractiveForms = true, renderForms = true,
l10n = NullL10n, l10n = NullL10n,
enableScripting = false, enableScripting = false,
hasJSActionsPromise = null, hasJSActionsPromise = null,
@ -161,7 +161,7 @@ class DefaultAnnotationLayerFactory {
pageDiv, pageDiv,
pdfPage, pdfPage,
imageResourcesPath, imageResourcesPath,
renderInteractiveForms, renderForms,
linkService: new SimpleLinkService(), linkService: new SimpleLinkService(),
l10n, l10n,
annotationStorage, annotationStorage,

View File

@ -515,8 +515,8 @@ const PDFViewerApplication = {
renderer: AppOptions.get("renderer"), renderer: AppOptions.get("renderer"),
l10n: this.l10n, l10n: this.l10n,
textLayerMode: AppOptions.get("textLayerMode"), textLayerMode: AppOptions.get("textLayerMode"),
annotationMode: AppOptions.get("annotationMode"),
imageResourcesPath: AppOptions.get("imageResourcesPath"), imageResourcesPath: AppOptions.get("imageResourcesPath"),
renderInteractiveForms: AppOptions.get("renderInteractiveForms"),
enablePrintAutoRotate: AppOptions.get("enablePrintAutoRotate"), enablePrintAutoRotate: AppOptions.get("enablePrintAutoRotate"),
useOnlyCssZoom: AppOptions.get("useOnlyCssZoom"), useOnlyCssZoom: AppOptions.get("useOnlyCssZoom"),
maxCanvasPixels: AppOptions.get("maxCanvasPixels"), maxCanvasPixels: AppOptions.get("maxCanvasPixels"),
@ -1555,7 +1555,7 @@ const PDFViewerApplication = {
this.fallback(UNSUPPORTED_FEATURES.forms); this.fallback(UNSUPPORTED_FEATURES.forms);
} else if ( } else if (
(info.IsAcroFormPresent || info.IsXFAPresent) && (info.IsAcroFormPresent || info.IsXFAPresent) &&
!this.pdfViewer.renderInteractiveForms !this.pdfViewer.renderForms
) { ) {
console.warn("Warning: Interactive form support is not enabled"); console.warn("Warning: Interactive form support is not enabled");
this.fallback(UNSUPPORTED_FEATURES.forms); this.fallback(UNSUPPORTED_FEATURES.forms);

View File

@ -59,6 +59,11 @@ const OptionKind = {
* values below *explicitly* rather than relying on imported types. * values below *explicitly* rather than relying on imported types.
*/ */
const defaultOptions = { const defaultOptions = {
annotationMode: {
/** @type {number} */
value: 2,
kind: OptionKind.VIEWER + OptionKind.PREFERENCE,
},
cursorToolOnLoad: { cursorToolOnLoad: {
/** @type {number} */ /** @type {number} */
value: 0, value: 0,
@ -145,11 +150,6 @@ const defaultOptions = {
value: "canvas", value: "canvas",
kind: OptionKind.VIEWER, kind: OptionKind.VIEWER,
}, },
renderInteractiveForms: {
/** @type {boolean} */
value: true,
kind: OptionKind.VIEWER + OptionKind.PREFERENCE,
},
sidebarViewOnLoad: { sidebarViewOnLoad: {
/** @type {number} */ /** @type {number} */
value: -1, value: -1,

View File

@ -13,7 +13,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { createPromiseCapability, version } from "pdfjs-lib"; import { AnnotationMode, createPromiseCapability, version } from "pdfjs-lib";
import { import {
CSS_UNITS, CSS_UNITS,
DEFAULT_SCALE, DEFAULT_SCALE,
@ -67,10 +67,13 @@ const DEFAULT_CACHE_SIZE = 10;
* selection and searching is created, and if the improved text selection * selection and searching is created, and if the improved text selection
* behaviour is enabled. The constants from {TextLayerMode} should be used. * behaviour is enabled. The constants from {TextLayerMode} should be used.
* The default value is `TextLayerMode.ENABLE`. * The default value is `TextLayerMode.ENABLE`.
* @property {number} [annotationMode] - Controls if the annotation layer is
* created, and if interactive form elements or `AnnotationStorage`-data are
* being rendered. The constants from {@link AnnotationMode} should be used;
* see also {@link RenderParameters} and {@link GetOperatorListParameters}.
* The default value is `AnnotationMode.ENABLE_FORMS`.
* @property {string} [imageResourcesPath] - Path for image resources, mainly * @property {string} [imageResourcesPath] - Path for image resources, mainly
* mainly for annotation icons. Include trailing slash. * mainly for annotation icons. Include trailing slash.
* @property {boolean} [renderInteractiveForms] - Enables rendering of
* interactive form elements. The default value is `true`.
* @property {boolean} [enablePrintAutoRotate] - Enables automatic rotation of * @property {boolean} [enablePrintAutoRotate] - Enables automatic rotation of
* landscape pages upon printing. The default is `false`. * landscape pages upon printing. The default is `false`.
* @property {string} renderer - 'canvas' or 'svg'. The default is 'canvas'. * @property {string} renderer - 'canvas' or 'svg'. The default is 'canvas'.
@ -182,11 +185,10 @@ class BaseViewer {
this.findController = options.findController || null; this.findController = options.findController || null;
this._scriptingManager = options.scriptingManager || null; this._scriptingManager = options.scriptingManager || null;
this.removePageBorders = options.removePageBorders || false; this.removePageBorders = options.removePageBorders || false;
this.textLayerMode = Number.isInteger(options.textLayerMode) this.textLayerMode = options.textLayerMode ?? TextLayerMode.ENABLE;
? options.textLayerMode this._annotationMode =
: TextLayerMode.ENABLE; options.annotationMode ?? AnnotationMode.ENABLE_FORMS;
this.imageResourcesPath = options.imageResourcesPath || ""; this.imageResourcesPath = options.imageResourcesPath || "";
this.renderInteractiveForms = options.renderInteractiveForms !== false;
this.enablePrintAutoRotate = options.enablePrintAutoRotate || false; this.enablePrintAutoRotate = options.enablePrintAutoRotate || false;
this.renderer = options.renderer || RendererType.CANVAS; this.renderer = options.renderer || RendererType.CANVAS;
this.useOnlyCssZoom = options.useOnlyCssZoom || false; this.useOnlyCssZoom = options.useOnlyCssZoom || false;
@ -240,6 +242,13 @@ class BaseViewer {
}); });
} }
/**
* @type {boolean}
*/
get renderForms() {
return this._annotationMode === AnnotationMode.ENABLE_FORMS;
}
/** /**
* @type {boolean} * @type {boolean}
*/ */
@ -529,6 +538,8 @@ class BaseViewer {
this.textLayerMode !== TextLayerMode.DISABLE && !isPureXfa this.textLayerMode !== TextLayerMode.DISABLE && !isPureXfa
? this ? this
: null; : null;
const annotationLayerFactory =
this._annotationMode !== AnnotationMode.DISABLE ? this : null;
const xfaLayerFactory = isPureXfa ? this : null; const xfaLayerFactory = isPureXfa ? this : null;
for (let pageNum = 1; pageNum <= pagesCount; ++pageNum) { for (let pageNum = 1; pageNum <= pagesCount; ++pageNum) {
@ -542,12 +553,12 @@ class BaseViewer {
renderingQueue: this.renderingQueue, renderingQueue: this.renderingQueue,
textLayerFactory, textLayerFactory,
textLayerMode: this.textLayerMode, textLayerMode: this.textLayerMode,
annotationLayerFactory: this, annotationLayerFactory,
annotationMode: this._annotationMode,
xfaLayerFactory, xfaLayerFactory,
textHighlighterFactory: this, textHighlighterFactory: this,
structTreeLayerFactory: this, structTreeLayerFactory: this,
imageResourcesPath: this.imageResourcesPath, imageResourcesPath: this.imageResourcesPath,
renderInteractiveForms: this.renderInteractiveForms,
renderer: this.renderer, renderer: this.renderer,
useOnlyCssZoom: this.useOnlyCssZoom, useOnlyCssZoom: this.useOnlyCssZoom,
maxCanvasPixels: this.maxCanvasPixels, maxCanvasPixels: this.maxCanvasPixels,
@ -1289,7 +1300,7 @@ class BaseViewer {
* data in forms. * data in forms.
* @param {string} [imageResourcesPath] - Path for image resources, mainly * @param {string} [imageResourcesPath] - Path for image resources, mainly
* for annotation icons. Include trailing slash. * for annotation icons. Include trailing slash.
* @param {boolean} renderInteractiveForms * @param {boolean} renderForms
* @param {IL10n} l10n * @param {IL10n} l10n
* @param {boolean} [enableScripting] * @param {boolean} [enableScripting]
* @param {Promise<boolean>} [hasJSActionsPromise] * @param {Promise<boolean>} [hasJSActionsPromise]
@ -1301,7 +1312,7 @@ class BaseViewer {
pdfPage, pdfPage,
annotationStorage = null, annotationStorage = null,
imageResourcesPath = "", imageResourcesPath = "",
renderInteractiveForms = false, renderForms = true,
l10n = NullL10n, l10n = NullL10n,
enableScripting = null, enableScripting = null,
hasJSActionsPromise = null, hasJSActionsPromise = null,
@ -1313,7 +1324,7 @@ class BaseViewer {
annotationStorage: annotationStorage:
annotationStorage || this.pdfDocument?.annotationStorage, annotationStorage || this.pdfDocument?.annotationStorage,
imageResourcesPath, imageResourcesPath,
renderInteractiveForms, renderForms,
linkService: this.linkService, linkService: this.linkService,
downloadManager: this.downloadManager, downloadManager: this.downloadManager,
l10n, l10n,

View File

@ -13,7 +13,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { RenderingCancelledException, shadow } from "pdfjs-lib"; import { AnnotationMode, RenderingCancelledException, shadow } from "pdfjs-lib";
import { getXfaHtmlForPrinting } from "./print_utils.js"; import { getXfaHtmlForPrinting } from "./print_utils.js";
import { PDFPrintServiceFactory } from "./app.js"; import { PDFPrintServiceFactory } from "./app.js";
@ -68,7 +68,7 @@ function composePage(
transform: [PRINT_UNITS, 0, 0, PRINT_UNITS, 0, 0], transform: [PRINT_UNITS, 0, 0, PRINT_UNITS, 0, 0],
viewport: pdfPage.getViewport({ scale: 1, rotation: size.rotation }), viewport: pdfPage.getViewport({ scale: 1, rotation: size.rotation }),
intent: "print", intent: "print",
includeAnnotationStorage: true, annotationMode: AnnotationMode.ENABLE_STORAGE,
optionalContentConfigPromise, optionalContentConfigPromise,
}; };
currentRenderTask = thisRenderTask = pdfPage.render(renderContext); currentRenderTask = thisRenderTask = pdfPage.render(renderContext);

View File

@ -186,7 +186,7 @@ class IPDFAnnotationLayerFactory {
* data in forms. * data in forms.
* @param {string} [imageResourcesPath] - Path for image resources, mainly * @param {string} [imageResourcesPath] - Path for image resources, mainly
* for annotation icons. Include trailing slash. * for annotation icons. Include trailing slash.
* @param {boolean} renderInteractiveForms * @param {boolean} renderForms
* @param {IL10n} l10n * @param {IL10n} l10n
* @param {boolean} [enableScripting] * @param {boolean} [enableScripting]
* @param {Promise<boolean>} [hasJSActionsPromise] * @param {Promise<boolean>} [hasJSActionsPromise]
@ -198,7 +198,7 @@ class IPDFAnnotationLayerFactory {
pdfPage, pdfPage,
annotationStorage = null, annotationStorage = null,
imageResourcesPath = "", imageResourcesPath = "",
renderInteractiveForms = true, renderForms = true,
l10n = undefined, l10n = undefined,
enableScripting = false, enableScripting = false,
hasJSActionsPromise = null, hasJSActionsPromise = null,

View File

@ -13,6 +13,12 @@
* limitations under the License. * limitations under the License.
*/ */
import {
AnnotationMode,
createPromiseCapability,
RenderingCancelledException,
SVGGraphics,
} from "pdfjs-lib";
import { import {
approximateFraction, approximateFraction,
CSS_UNITS, CSS_UNITS,
@ -22,11 +28,6 @@ import {
roundToDivide, roundToDivide,
TextLayerMode, TextLayerMode,
} from "./ui_utils.js"; } from "./ui_utils.js";
import {
createPromiseCapability,
RenderingCancelledException,
SVGGraphics,
} from "pdfjs-lib";
import { compatibilityParams } from "./app_options.js"; import { compatibilityParams } from "./app_options.js";
import { NullL10n } from "./l10n_utils.js"; import { NullL10n } from "./l10n_utils.js";
import { RenderingStates } from "./pdf_rendering_queue.js"; import { RenderingStates } from "./pdf_rendering_queue.js";
@ -47,13 +48,16 @@ import { RenderingStates } from "./pdf_rendering_queue.js";
* selection and searching is created, and if the improved text selection * selection and searching is created, and if the improved text selection
* behaviour is enabled. The constants from {TextLayerMode} should be used. * behaviour is enabled. The constants from {TextLayerMode} should be used.
* The default value is `TextLayerMode.ENABLE`. * The default value is `TextLayerMode.ENABLE`.
* @property {number} [annotationMode] - Controls if the annotation layer is
* created, and if interactive form elements or `AnnotationStorage`-data are
* being rendered. The constants from {@link AnnotationMode} should be used;
* see also {@link RenderParameters} and {@link GetOperatorListParameters}.
* The default value is `AnnotationMode.ENABLE_FORMS`.
* @property {IPDFAnnotationLayerFactory} annotationLayerFactory * @property {IPDFAnnotationLayerFactory} annotationLayerFactory
* @property {IPDFXfaLayerFactory} xfaLayerFactory * @property {IPDFXfaLayerFactory} xfaLayerFactory
* @property {IPDFStructTreeLayerFactory} structTreeLayerFactory * @property {IPDFStructTreeLayerFactory} structTreeLayerFactory
* @property {string} [imageResourcesPath] - Path for image resources, mainly * @property {string} [imageResourcesPath] - Path for image resources, mainly
* for annotation icons. Include trailing slash. * for annotation icons. Include trailing slash.
* @property {boolean} renderInteractiveForms - Turns on rendering of
* interactive form elements. The default value is `true`.
* @property {string} renderer - 'canvas' or 'svg'. The default is 'canvas'. * @property {string} renderer - 'canvas' or 'svg'. The default is 'canvas'.
* @property {boolean} [useOnlyCssZoom] - Enables CSS only zooming. The default * @property {boolean} [useOnlyCssZoom] - Enables CSS only zooming. The default
* value is `false`. * value is `false`.
@ -88,11 +92,10 @@ class PDFPageView {
this._optionalContentConfigPromise = this._optionalContentConfigPromise =
options.optionalContentConfigPromise || null; options.optionalContentConfigPromise || null;
this.hasRestrictedScaling = false; this.hasRestrictedScaling = false;
this.textLayerMode = Number.isInteger(options.textLayerMode) this.textLayerMode = options.textLayerMode ?? TextLayerMode.ENABLE;
? options.textLayerMode this._annotationMode =
: TextLayerMode.ENABLE; options.annotationMode ?? AnnotationMode.ENABLE_FORMS;
this.imageResourcesPath = options.imageResourcesPath || ""; this.imageResourcesPath = options.imageResourcesPath || "";
this.renderInteractiveForms = options.renderInteractiveForms !== false;
this.useOnlyCssZoom = options.useOnlyCssZoom || false; this.useOnlyCssZoom = options.useOnlyCssZoom || false;
this.maxCanvasPixels = options.maxCanvasPixels || MAX_CANVAS_PIXELS; this.maxCanvasPixels = options.maxCanvasPixels || MAX_CANVAS_PIXELS;
@ -638,7 +641,10 @@ class PDFPageView {
} }
); );
if (this.annotationLayerFactory) { if (
this._annotationMode !== AnnotationMode.DISABLE &&
this.annotationLayerFactory
) {
if (!this.annotationLayer) { if (!this.annotationLayer) {
this.annotationLayer = this.annotationLayer =
this.annotationLayerFactory.createAnnotationLayerBuilder( this.annotationLayerFactory.createAnnotationLayerBuilder(
@ -646,9 +652,9 @@ class PDFPageView {
pdfPage, pdfPage,
/* annotationStorage = */ null, /* annotationStorage = */ null,
this.imageResourcesPath, this.imageResourcesPath,
this.renderInteractiveForms, this._annotationMode === AnnotationMode.ENABLE_FORMS,
this.l10n, this.l10n,
/* enableScripting */ null, /* enableScripting = */ null,
/* hasJSActionsPromise = */ null, /* hasJSActionsPromise = */ null,
/* mouseState = */ null /* mouseState = */ null
); );
@ -787,7 +793,7 @@ class PDFPageView {
canvasContext: ctx, canvasContext: ctx,
transform, transform,
viewport: this.viewport, viewport: this.viewport,
renderInteractiveForms: this.renderInteractiveForms, annotationMode: this._annotationMode,
optionalContentConfigPromise: this._optionalContentConfigPromise, optionalContentConfigPromise: this._optionalContentConfigPromise,
}; };
const renderTask = this.pdfPage.render(renderContext); const renderTask = this.pdfPage.render(renderContext);
@ -839,24 +845,28 @@ class PDFPageView {
const pdfPage = this.pdfPage; const pdfPage = this.pdfPage;
const actualSizeViewport = this.viewport.clone({ scale: CSS_UNITS }); const actualSizeViewport = this.viewport.clone({ scale: CSS_UNITS });
const promise = pdfPage.getOperatorList().then(opList => { const promise = pdfPage
ensureNotCancelled(); .getOperatorList({
const svgGfx = new SVGGraphics( annotationMode: this._annotatationMode,
pdfPage.commonObjs, })
pdfPage.objs, .then(opList => {
/* forceDataSchema = */ compatibilityParams.disableCreateObjectURL
);
return svgGfx.getSVG(opList, actualSizeViewport).then(svg => {
ensureNotCancelled(); ensureNotCancelled();
this.svg = svg; const svgGfx = new SVGGraphics(
this.paintedViewportMap.set(svg, actualSizeViewport); pdfPage.commonObjs,
pdfPage.objs,
/* forceDataSchema = */ compatibilityParams.disableCreateObjectURL
);
return svgGfx.getSVG(opList, actualSizeViewport).then(svg => {
ensureNotCancelled();
this.svg = svg;
this.paintedViewportMap.set(svg, actualSizeViewport);
svg.style.width = wrapper.style.width; svg.style.width = wrapper.style.width;
svg.style.height = wrapper.style.height; svg.style.height = wrapper.style.height;
this.renderingState = RenderingStates.FINISHED; this.renderingState = RenderingStates.FINISHED;
wrapper.appendChild(svg); wrapper.appendChild(svg);
});
}); });
});
return { return {
promise, promise,

View File

@ -14,6 +14,7 @@
*/ */
import { PDFPrintServiceFactory, PDFViewerApplication } from "./app.js"; import { PDFPrintServiceFactory, PDFViewerApplication } from "./app.js";
import { AnnotationMode } from "pdfjs-lib";
import { compatibilityParams } from "./app_options.js"; import { compatibilityParams } from "./app_options.js";
import { getXfaHtmlForPrinting } from "./print_utils.js"; import { getXfaHtmlForPrinting } from "./print_utils.js";
@ -49,7 +50,7 @@ function renderPage(
transform: [PRINT_UNITS, 0, 0, PRINT_UNITS, 0, 0], transform: [PRINT_UNITS, 0, 0, PRINT_UNITS, 0, 0],
viewport: pdfPage.getViewport({ scale: 1, rotation: size.rotation }), viewport: pdfPage.getViewport({ scale: 1, rotation: size.rotation }),
intent: "print", intent: "print",
includeAnnotationStorage: true, annotationMode: AnnotationMode.ENABLE_STORAGE,
optionalContentConfigPromise, optionalContentConfigPromise,
}; };
return pdfPage.render(renderContext).promise; return pdfPage.render(renderContext).promise;