Skip to content

[api-minor] Limit the maximum canvas width/height, in addition to its total area (bug 1943094) #19604

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 4, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion web/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -477,7 +477,8 @@ const PDFViewerApplication = {
)
: null;

const enableHWA = AppOptions.get("enableHWA");
const enableHWA = AppOptions.get("enableHWA"),
maxCanvasDim = AppOptions.get("maxCanvasDim");
const pdfViewer = new PDFViewer({
container,
viewer,
Expand Down Expand Up @@ -506,6 +507,7 @@ const PDFViewerApplication = {
imageResourcesPath: AppOptions.get("imageResourcesPath"),
enablePrintAutoRotate: AppOptions.get("enablePrintAutoRotate"),
maxCanvasPixels: AppOptions.get("maxCanvasPixels"),
maxCanvasDim,
enableDetailCanvas: AppOptions.get("enableDetailCanvas"),
enablePermissions: AppOptions.get("enablePermissions"),
pageColors,
Expand All @@ -527,6 +529,7 @@ const PDFViewerApplication = {
eventBus,
renderingQueue: pdfRenderingQueue,
linkService: pdfLinkService,
maxCanvasDim,
pageColors,
abortSignal,
enableHWA,
Expand Down
5 changes: 5 additions & 0 deletions web/app_options.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,11 @@ const defaultOptions = {
: null,
kind: OptionKind.BROWSER,
},
maxCanvasDim: {
/** @type {number} */
value: 32767,
kind: OptionKind.BROWSER + OptionKind.VIEWER,
},
nimbusDataStr: {
/** @type {string} */
value: "",
Expand Down
31 changes: 23 additions & 8 deletions web/pdf_page_view.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,14 @@ import { XfaLayerBuilder } from "./xfa_layer_builder.js";
* @property {number} [maxCanvasPixels] - The maximum supported canvas size in
* total pixels, i.e. width * height. Use `-1` for no limit, or `0` for
* CSS-only zooming. The default value is 4096 * 8192 (32 mega-pixels).
* @property {number} [maxCanvasDim] - The maximum supported canvas dimension,
* in either width or height. Use `-1` for no limit.
* The default value is 32767.
* @property {boolean} [enableDetailCanvas] - When enabled, if the rendered
* pages would need a canvas that is larger than `maxCanvasPixels`, it will
* draw a second canvas on top of the CSS-zoomed one, that only renders the
* part of the page that is close to the viewport. The default value is
* `true`.

* pages would need a canvas that is larger than `maxCanvasPixels` or
* `maxCanvasDim`, it will draw a second canvas on top of the CSS-zoomed one,
* that only renders the part of the page that is close to the viewport.
* The default value is `true`.
* @property {Object} [pageColors] - Overwrites background and foreground colors
* with user defined ones in order to improve readability in high contrast
* mode.
Expand Down Expand Up @@ -185,6 +187,7 @@ class PDFPageView extends BasePDFPageView {
this.enableDetailCanvas = options.enableDetailCanvas ?? true;
this.maxCanvasPixels =
options.maxCanvasPixels ?? AppOptions.get("maxCanvasPixels");
this.maxCanvasDim = options.maxCanvasDim || AppOptions.get("maxCanvasDim");
this.#enableAutoLinking = options.enableAutoLinking || false;

this.l10n = options.l10n;
Expand Down Expand Up @@ -772,9 +775,21 @@ class PDFPageView extends BasePDFPageView {
outputScale.sx *= invScale;
outputScale.sy *= invScale;
this.#needsRestrictedScaling = true;
} else if (this.maxCanvasPixels > 0) {
const pixelsInViewport = width * height;
const maxScale = Math.sqrt(this.maxCanvasPixels / pixelsInViewport);
} else if (this.maxCanvasPixels > 0 || this.maxCanvasDim !== -1) {
let maxAreaScale = Infinity,
maxWidthScale = Infinity,
maxHeightScale = Infinity;

if (this.maxCanvasPixels > 0) {
const pixelsInViewport = width * height;
maxAreaScale = Math.sqrt(this.maxCanvasPixels / pixelsInViewport);
}
if (this.maxCanvasDim !== -1) {
maxWidthScale = this.maxCanvasDim / width;
maxHeightScale = this.maxCanvasDim / height;
}
const maxScale = Math.min(maxAreaScale, maxWidthScale, maxHeightScale);

if (outputScale.sx > maxScale || outputScale.sy > maxScale) {
outputScale.sx = maxScale;
outputScale.sy = maxScale;
Expand Down
21 changes: 21 additions & 0 deletions web/pdf_thumbnail_view.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
/** @typedef {import("./pdf_rendering_queue").PDFRenderingQueue} PDFRenderingQueue */

import { OutputScale, RenderingCancelledException } from "pdfjs-lib";
import { AppOptions } from "./app_options.js";
import { RenderingStates } from "./ui_utils.js";

const DRAW_UPSCALE_FACTOR = 2; // See comment in `PDFThumbnailView.draw` below.
Expand All @@ -41,6 +42,9 @@ const THUMBNAIL_WIDTH = 98; // px
* The default value is `null`.
* @property {IPDFLinkService} linkService - The navigation/linking service.
* @property {PDFRenderingQueue} renderingQueue - The rendering queue object.
* @property {number} [maxCanvasDim] - The maximum supported canvas dimension,
* in either width or height. Use `-1` for no limit.
* The default value is 32767.
* @property {Object} [pageColors] - Overwrites background and foreground colors
* with user defined ones in order to improve readability in high contrast
* mode.
Expand Down Expand Up @@ -93,6 +97,7 @@ class PDFThumbnailView {
optionalContentConfigPromise,
linkService,
renderingQueue,
maxCanvasDim,
pageColors,
enableHWA,
}) {
Expand All @@ -105,6 +110,7 @@ class PDFThumbnailView {
this.viewport = defaultViewport;
this.pdfPageRotate = defaultViewport.rotation;
this._optionalContentConfigPromise = optionalContentConfigPromise || null;
this.maxCanvasDim = maxCanvasDim || AppOptions.get("maxCanvasDim");
this.pageColors = pageColors || null;
this.enableHWA = enableHWA || false;

Expand Down Expand Up @@ -363,9 +369,24 @@ class PDFThumbnailView {
);
return canvas;
}
const { maxCanvasDim } = this;

// drawImage does an awful job of rescaling the image, doing it gradually.
let reducedWidth = canvas.width << MAX_NUM_SCALING_STEPS;
let reducedHeight = canvas.height << MAX_NUM_SCALING_STEPS;

if (maxCanvasDim !== -1) {
const maxWidthScale = maxCanvasDim / reducedWidth,
maxHeightScale = maxCanvasDim / reducedHeight;

if (maxWidthScale < 1) {
reducedWidth = maxCanvasDim;
reducedHeight = (reducedHeight * maxWidthScale) | 0;
} else if (maxHeightScale < 1) {
reducedWidth = (reducedWidth * maxHeightScale) | 0;
reducedHeight = maxCanvasDim;
}
}
const [reducedImage, reducedImageCtx] = TempImageFactory.getCanvas(
reducedWidth,
reducedHeight
Expand Down
6 changes: 6 additions & 0 deletions web/pdf_thumbnail_viewer.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ const THUMBNAIL_SELECTED_CLASS = "selected";
* @property {EventBus} eventBus - The application event bus.
* @property {IPDFLinkService} linkService - The navigation/linking service.
* @property {PDFRenderingQueue} renderingQueue - The rendering queue object.
* @property {number} [maxCanvasDim] - The maximum supported canvas dimension,
* in either width or height. Use `-1` for no limit.
* The default value is 32767.
* @property {Object} [pageColors] - Overwrites background and foreground colors
* with user defined ones in order to improve readability in high contrast
* mode.
Expand All @@ -60,6 +63,7 @@ class PDFThumbnailViewer {
eventBus,
linkService,
renderingQueue,
maxCanvasDim,
pageColors,
abortSignal,
enableHWA,
Expand All @@ -68,6 +72,7 @@ class PDFThumbnailViewer {
this.eventBus = eventBus;
this.linkService = linkService;
this.renderingQueue = renderingQueue;
this.maxCanvasDim = maxCanvasDim;
this.pageColors = pageColors || null;
this.enableHWA = enableHWA || false;

Expand Down Expand Up @@ -209,6 +214,7 @@ class PDFThumbnailViewer {
optionalContentConfigPromise,
linkService: this.linkService,
renderingQueue: this.renderingQueue,
maxCanvasDim: this.maxCanvasDim,
pageColors: this.pageColors,
enableHWA: this.enableHWA,
});
Expand Down
13 changes: 9 additions & 4 deletions web/pdf_viewer.js
Original file line number Diff line number Diff line change
Expand Up @@ -118,11 +118,14 @@ function isValidAnnotationEditorMode(mode) {
* @property {number} [maxCanvasPixels] - The maximum supported canvas size in
* total pixels, i.e. width * height. Use `-1` for no limit, or `0` for
* CSS-only zooming. The default value is 4096 * 8192 (32 mega-pixels).
* @property {number} [maxCanvasDim] - The maximum supported canvas dimension,
* in either width or height. Use `-1` for no limit.
* The default value is 32767.
* @property {boolean} [enableDetailCanvas] - When enabled, if the rendered
* pages would need a canvas that is larger than `maxCanvasPixels`, it will
* draw a second canvas on top of the CSS-zoomed one, that only renders the
* part of the page that is close to the viewport. The default value is
* `true`.
* pages would need a canvas that is larger than `maxCanvasPixels` or
* `maxCanvasDim`, it will draw a second canvas on top of the CSS-zoomed one,
* that only renders the part of the page that is close to the viewport.
* The default value is `true`.
* @property {IL10n} [l10n] - Localization service.
* @property {boolean} [enablePermissions] - Enables PDF document permissions,
* when they exist. The default value is `false`.
Expand Down Expand Up @@ -326,6 +329,7 @@ class PDFViewer {
this.removePageBorders = options.removePageBorders || false;
}
this.maxCanvasPixels = options.maxCanvasPixels;
this.maxCanvasDim = options.maxCanvasDim;
this.enableDetailCanvas = options.enableDetailCanvas ?? true;
this.l10n = options.l10n;
if (typeof PDFJSDev === "undefined" || PDFJSDev.test("GENERIC")) {
Expand Down Expand Up @@ -1001,6 +1005,7 @@ class PDFViewer {
annotationMode,
imageResourcesPath: this.imageResourcesPath,
maxCanvasPixels: this.maxCanvasPixels,
maxCanvasDim: this.maxCanvasDim,
enableDetailCanvas: this.enableDetailCanvas,
pageColors,
l10n: this.l10n,
Expand Down