Skip to content

Commit

Permalink
Merge pull request #19604 from Snuffleupagus/bug-1943094
Browse files Browse the repository at this point in the history
[api-minor] Limit the maximum canvas width/height, in addition to its total area (bug 1943094)
  • Loading branch information
Snuffleupagus authored Mar 4, 2025
2 parents 5e6cfbe + 9f9de45 commit ab8ebc9
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 13 deletions.
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

0 comments on commit ab8ebc9

Please sign in to comment.