mirror of
https://github.com/mozilla/pdf.js.git
synced 2025-04-22 16:18:08 +02:00
[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:
parent
56e7bb626c
commit
41efa3c071
16 changed files with 272 additions and 134 deletions
|
@ -380,7 +380,10 @@ class Page {
|
|||
// page's operator list to render them.
|
||||
return Promise.all([pageListPromise, this._parsedAnnotations]).then(
|
||||
function ([pageOpList, annotations]) {
|
||||
if (annotations.length === 0) {
|
||||
if (
|
||||
annotations.length === 0 ||
|
||||
intent & RenderingIntentFlag.ANNOTATIONS_DISABLE
|
||||
) {
|
||||
pageOpList.flush(true);
|
||||
return { length: pageOpList.totalLength };
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ const DEFAULT_TAB_INDEX = 1000;
|
|||
* @property {AnnotationStorage} [annotationStorage]
|
||||
* @property {string} [imageResourcesPath] - Path for image resources, mainly
|
||||
* for annotation icons. Include trailing slash.
|
||||
* @property {boolean} renderInteractiveForms
|
||||
* @property {boolean} renderForms
|
||||
* @property {Object} svgFactory
|
||||
* @property {boolean} [enableScripting]
|
||||
* @property {boolean} [hasJSActions]
|
||||
|
@ -154,7 +154,7 @@ class AnnotationElement {
|
|||
this.linkService = parameters.linkService;
|
||||
this.downloadManager = parameters.downloadManager;
|
||||
this.imageResourcesPath = parameters.imageResourcesPath;
|
||||
this.renderInteractiveForms = parameters.renderInteractiveForms;
|
||||
this.renderForms = parameters.renderForms;
|
||||
this.svgFactory = parameters.svgFactory;
|
||||
this.annotationStorage = parameters.annotationStorage;
|
||||
this.enableScripting = parameters.enableScripting;
|
||||
|
@ -676,7 +676,7 @@ class WidgetAnnotationElement extends AnnotationElement {
|
|||
class TextWidgetAnnotationElement extends WidgetAnnotationElement {
|
||||
constructor(parameters) {
|
||||
const isRenderable =
|
||||
parameters.renderInteractiveForms ||
|
||||
parameters.renderForms ||
|
||||
(!parameters.data.hasAppearance && !!parameters.data.fieldValue);
|
||||
super(parameters, { isRenderable });
|
||||
}
|
||||
|
@ -700,7 +700,7 @@ class TextWidgetAnnotationElement extends WidgetAnnotationElement {
|
|||
this.container.className = "textWidgetAnnotation";
|
||||
|
||||
let element = null;
|
||||
if (this.renderInteractiveForms) {
|
||||
if (this.renderForms) {
|
||||
// NOTE: We cannot set the values using `element.value` below, since it
|
||||
// prevents the AnnotationLayer rasterizer in `test/driver.js`
|
||||
// from parsing the elements correctly for the reference tests.
|
||||
|
@ -952,7 +952,7 @@ class TextWidgetAnnotationElement extends WidgetAnnotationElement {
|
|||
|
||||
class CheckboxWidgetAnnotationElement extends WidgetAnnotationElement {
|
||||
constructor(parameters) {
|
||||
super(parameters, { isRenderable: parameters.renderInteractiveForms });
|
||||
super(parameters, { isRenderable: parameters.renderForms });
|
||||
}
|
||||
|
||||
render() {
|
||||
|
@ -1031,7 +1031,7 @@ class CheckboxWidgetAnnotationElement extends WidgetAnnotationElement {
|
|||
|
||||
class RadioButtonWidgetAnnotationElement extends WidgetAnnotationElement {
|
||||
constructor(parameters) {
|
||||
super(parameters, { isRenderable: parameters.renderInteractiveForms });
|
||||
super(parameters, { isRenderable: parameters.renderForms });
|
||||
}
|
||||
|
||||
render() {
|
||||
|
@ -1123,7 +1123,7 @@ class PushButtonWidgetAnnotationElement extends LinkAnnotationElement {
|
|||
|
||||
class ChoiceWidgetAnnotationElement extends WidgetAnnotationElement {
|
||||
constructor(parameters) {
|
||||
super(parameters, { isRenderable: parameters.renderInteractiveForms });
|
||||
super(parameters, { isRenderable: parameters.renderForms });
|
||||
}
|
||||
|
||||
render() {
|
||||
|
@ -2033,7 +2033,7 @@ class FileAttachmentAnnotationElement extends AnnotationElement {
|
|||
* @property {DownloadManager} downloadManager
|
||||
* @property {string} [imageResourcesPath] - Path for image resources, mainly
|
||||
* for annotation icons. Include trailing slash.
|
||||
* @property {boolean} renderInteractiveForms
|
||||
* @property {boolean} renderForms
|
||||
* @property {boolean} [enableScripting] - Enable embedded script execution.
|
||||
* @property {boolean} [hasJSActions] - Some fields have JS actions.
|
||||
* The default value is `false`.
|
||||
|
@ -2076,7 +2076,7 @@ class AnnotationLayer {
|
|||
linkService: parameters.linkService,
|
||||
downloadManager: parameters.downloadManager,
|
||||
imageResourcesPath: parameters.imageResourcesPath || "",
|
||||
renderInteractiveForms: parameters.renderInteractiveForms !== false,
|
||||
renderForms: parameters.renderForms !== false,
|
||||
svgFactory: new DOMSVGFactory(),
|
||||
annotationStorage:
|
||||
parameters.annotationStorage || new AnnotationStorage(),
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
import {
|
||||
AbortException,
|
||||
AnnotationMode,
|
||||
assert,
|
||||
createPromiseCapability,
|
||||
getVerbosityLevel,
|
||||
|
@ -1135,9 +1136,18 @@ class PDFDocumentProxy {
|
|||
* the `PDFPageProxy.getViewport` method.
|
||||
* @property {string} [intent] - Rendering intent, can be 'display', 'print',
|
||||
* or 'any'. The default value is 'display'.
|
||||
* @property {boolean} [renderInteractiveForms] - Whether or not interactive
|
||||
* form elements are rendered in the display layer. If so, we do not render
|
||||
* them on the canvas as well. The default value is `false`.
|
||||
* @property {number} [annotationMode] Controls which annotations are rendered
|
||||
* onto the canvas, 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`.
|
||||
* @property {Array<any>} [transform] - Additional transform, applied just
|
||||
* before viewport transform.
|
||||
* @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
|
||||
* a `CanvasPattern` object (a repetitive image). The default value is
|
||||
* '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] -
|
||||
* A promise that should resolve with an {@link OptionalContentConfig}
|
||||
* created from `PDFDocumentProxy.getOptionalContentConfig`. If `null`,
|
||||
|
@ -1165,6 +1172,18 @@ class PDFDocumentProxy {
|
|||
* @typedef {Object} GetOperatorListParameters
|
||||
* @property {string} [intent] - Rendering intent, can be 'display', 'print',
|
||||
* 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.
|
||||
*/
|
||||
getAnnotations({ intent = "display" } = {}) {
|
||||
const intentArgs = this._transport.getRenderingIntent(intent, {});
|
||||
const intentArgs = this._transport.getRenderingIntent(intent);
|
||||
|
||||
let promise = this._annotationPromises.get(intentArgs.cacheKey);
|
||||
if (!promise) {
|
||||
|
@ -1324,22 +1343,21 @@ class PDFPageProxy {
|
|||
canvasContext,
|
||||
viewport,
|
||||
intent = "display",
|
||||
renderInteractiveForms = false,
|
||||
annotationMode = AnnotationMode.ENABLE,
|
||||
transform = null,
|
||||
imageLayer = null,
|
||||
canvasFactory = null,
|
||||
background = null,
|
||||
includeAnnotationStorage = false,
|
||||
optionalContentConfigPromise = null,
|
||||
}) {
|
||||
if (this._stats) {
|
||||
this._stats.time("Overall");
|
||||
}
|
||||
|
||||
const intentArgs = this._transport.getRenderingIntent(intent, {
|
||||
renderForms: renderInteractiveForms === true,
|
||||
includeAnnotationStorage: includeAnnotationStorage === true,
|
||||
});
|
||||
const intentArgs = this._transport.getRenderingIntent(
|
||||
intent,
|
||||
annotationMode
|
||||
);
|
||||
// If there was a pending destroy, cancel it so no cleanup happens during
|
||||
// this call to render.
|
||||
this.pendingCleanup = false;
|
||||
|
@ -1460,7 +1478,10 @@ class PDFPageProxy {
|
|||
* @returns {Promise<PDFOperatorList>} A promise resolved with an
|
||||
* {@link PDFOperatorList} object that represents the page's operator list.
|
||||
*/
|
||||
getOperatorList({ intent = "display" } = {}) {
|
||||
getOperatorList({
|
||||
intent = "display",
|
||||
annotationMode = AnnotationMode.ENABLE,
|
||||
} = {}) {
|
||||
function operatorListChanged() {
|
||||
if (intentState.operatorList.lastChunk) {
|
||||
intentState.opListReadCapability.resolve(intentState.operatorList);
|
||||
|
@ -1469,9 +1490,11 @@ class PDFPageProxy {
|
|||
}
|
||||
}
|
||||
|
||||
const intentArgs = this._transport.getRenderingIntent(intent, {
|
||||
isOpList: true,
|
||||
});
|
||||
const intentArgs = this._transport.getRenderingIntent(
|
||||
intent,
|
||||
annotationMode,
|
||||
/* isOpList = */ true
|
||||
);
|
||||
let intentState = this._intentStates.get(intentArgs.cacheKey);
|
||||
if (!intentState) {
|
||||
intentState = Object.create(null);
|
||||
|
@ -1792,7 +1815,7 @@ class PDFPageProxy {
|
|||
}
|
||||
}
|
||||
intentState.streamReader
|
||||
.cancel(new AbortException(reason?.message))
|
||||
.cancel(new AbortException(reason.message))
|
||||
.catch(() => {
|
||||
// Avoid "Uncaught promise" messages in the console.
|
||||
});
|
||||
|
@ -2351,7 +2374,8 @@ class WorkerTransport {
|
|||
|
||||
getRenderingIntent(
|
||||
intent,
|
||||
{ renderForms = false, includeAnnotationStorage = false, isOpList = false }
|
||||
annotationMode = AnnotationMode.ENABLE,
|
||||
isOpList = false
|
||||
) {
|
||||
let renderingIntent = RenderingIntentFlag.DISPLAY; // Default value.
|
||||
let lastModified = "";
|
||||
|
@ -2369,13 +2393,22 @@ class WorkerTransport {
|
|||
warn(`getRenderingIntent - invalid intent: ${intent}`);
|
||||
}
|
||||
|
||||
if (renderForms) {
|
||||
renderingIntent += RenderingIntentFlag.ANNOTATIONS_FORMS;
|
||||
}
|
||||
if (includeAnnotationStorage) {
|
||||
renderingIntent += RenderingIntentFlag.ANNOTATIONS_STORAGE;
|
||||
switch (annotationMode) {
|
||||
case AnnotationMode.DISABLE:
|
||||
renderingIntent += RenderingIntentFlag.ANNOTATIONS_DISABLE;
|
||||
break;
|
||||
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) {
|
||||
|
|
34
src/pdf.js
34
src/pdf.js
|
@ -27,15 +27,7 @@ import {
|
|||
RenderingCancelledException,
|
||||
} from "./display/display_utils.js";
|
||||
import {
|
||||
build,
|
||||
getDocument,
|
||||
LoopbackPort,
|
||||
PDFDataRangeTransport,
|
||||
PDFWorker,
|
||||
setPDFNetworkStreamFactory,
|
||||
version,
|
||||
} from "./display/api.js";
|
||||
import {
|
||||
AnnotationMode,
|
||||
CMapCompressionType,
|
||||
createObjectURL,
|
||||
createPromiseCapability,
|
||||
|
@ -52,6 +44,15 @@ import {
|
|||
Util,
|
||||
VerbosityLevel,
|
||||
} from "./shared/util.js";
|
||||
import {
|
||||
build,
|
||||
getDocument,
|
||||
LoopbackPort,
|
||||
PDFDataRangeTransport,
|
||||
PDFWorker,
|
||||
setPDFNetworkStreamFactory,
|
||||
version,
|
||||
} from "./display/api.js";
|
||||
import { AnnotationLayer } from "./display/annotation_layer.js";
|
||||
import { GlobalWorkerOptions } from "./display/worker_options.js";
|
||||
import { isNodeJS } from "./shared/is_node.js";
|
||||
|
@ -110,14 +111,8 @@ export {
|
|||
PDFDateString,
|
||||
RenderingCancelledException,
|
||||
getXfaPageViewport,
|
||||
// From "./display/api.js":
|
||||
build,
|
||||
getDocument,
|
||||
LoopbackPort,
|
||||
PDFDataRangeTransport,
|
||||
PDFWorker,
|
||||
version,
|
||||
// From "./shared/util.js":
|
||||
AnnotationMode,
|
||||
CMapCompressionType,
|
||||
createObjectURL,
|
||||
createPromiseCapability,
|
||||
|
@ -133,6 +128,13 @@ export {
|
|||
UNSUPPORTED_FEATURES,
|
||||
Util,
|
||||
VerbosityLevel,
|
||||
// From "./display/api.js":
|
||||
build,
|
||||
getDocument,
|
||||
LoopbackPort,
|
||||
PDFDataRangeTransport,
|
||||
PDFWorker,
|
||||
version,
|
||||
// From "./display/annotation_layer.js":
|
||||
AnnotationLayer,
|
||||
// From "./display/worker_options.js":
|
||||
|
|
|
@ -23,9 +23,10 @@ const FONT_IDENTITY_MATRIX = [0.001, 0, 0, 0.001, 0, 0];
|
|||
* how these flags are being used:
|
||||
* - ANY, DISPLAY, and PRINT are the normal rendering intents, note the
|
||||
* `PDFPageProxy.{render, getOperatorList, getAnnotations}`-methods.
|
||||
* - ANNOTATIONS_FORMS, and ANNOTATIONS_STORAGE controls which annotations are
|
||||
* rendered onto the canvas, note the `renderInteractiveForms`- respectively
|
||||
* `includeAnnotationStorage`-options in the `PDFPageProxy.render`-method.
|
||||
* - ANNOTATIONS_FORMS, ANNOTATIONS_STORAGE, ANNOTATIONS_DISABLE control which
|
||||
* annotations are rendered onto the canvas (i.e. by being included in the
|
||||
* operatorList), note the `PDFPageProxy.{render, getOperatorList}`-methods
|
||||
* and their `annotationMode`-option.
|
||||
* - OPLIST is used with the `PDFPageProxy.getOperatorList`-method, note the
|
||||
* `OperatorList`-constructor (on the worker-thread).
|
||||
*/
|
||||
|
@ -35,9 +36,17 @@ const RenderingIntentFlag = {
|
|||
PRINT: 0x04,
|
||||
ANNOTATIONS_FORMS: 0x10,
|
||||
ANNOTATIONS_STORAGE: 0x20,
|
||||
ANNOTATIONS_DISABLE: 0x40,
|
||||
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.
|
||||
const PermissionFlag = {
|
||||
PRINT: 0x04,
|
||||
|
@ -1027,6 +1036,7 @@ export {
|
|||
AnnotationFieldFlag,
|
||||
AnnotationFlag,
|
||||
AnnotationMarkedState,
|
||||
AnnotationMode,
|
||||
AnnotationReplyType,
|
||||
AnnotationReviewState,
|
||||
AnnotationStateModelType,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue