Merge pull request #19635 from Snuffleupagus/thumbnails-maxCanvasPixels
Support the `maxCanvasPixels` option in the thumbnails code
This commit is contained in:
commit
4152eae3fb
@ -640,9 +640,39 @@ class OutputScale {
|
|||||||
return this.sx !== 1 || this.sy !== 1;
|
return this.sx !== 1 || this.sy !== 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {boolean} Returns `true` when scaling is symmetric,
|
||||||
|
* `false` otherwise.
|
||||||
|
*/
|
||||||
get symmetric() {
|
get symmetric() {
|
||||||
return this.sx === this.sy;
|
return this.sx === this.sy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {boolean} Returns `true` if scaling was limited,
|
||||||
|
* `false` otherwise.
|
||||||
|
*/
|
||||||
|
limitCanvas(width, height, maxPixels, maxDim) {
|
||||||
|
let maxAreaScale = Infinity,
|
||||||
|
maxWidthScale = Infinity,
|
||||||
|
maxHeightScale = Infinity;
|
||||||
|
|
||||||
|
if (maxPixels > 0) {
|
||||||
|
maxAreaScale = Math.sqrt(maxPixels / (width * height));
|
||||||
|
}
|
||||||
|
if (maxDim !== -1) {
|
||||||
|
maxWidthScale = maxDim / width;
|
||||||
|
maxHeightScale = maxDim / height;
|
||||||
|
}
|
||||||
|
const maxScale = Math.min(maxAreaScale, maxWidthScale, maxHeightScale);
|
||||||
|
|
||||||
|
if (this.sx > maxScale || this.sy > maxScale) {
|
||||||
|
this.sx = maxScale;
|
||||||
|
this.sy = maxScale;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// See https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Image_types
|
// See https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Image_types
|
||||||
|
|||||||
@ -478,6 +478,7 @@ const PDFViewerApplication = {
|
|||||||
: null;
|
: null;
|
||||||
|
|
||||||
const enableHWA = AppOptions.get("enableHWA"),
|
const enableHWA = AppOptions.get("enableHWA"),
|
||||||
|
maxCanvasPixels = AppOptions.get("maxCanvasPixels"),
|
||||||
maxCanvasDim = AppOptions.get("maxCanvasDim");
|
maxCanvasDim = AppOptions.get("maxCanvasDim");
|
||||||
const pdfViewer = new PDFViewer({
|
const pdfViewer = new PDFViewer({
|
||||||
container,
|
container,
|
||||||
@ -506,7 +507,7 @@ const PDFViewerApplication = {
|
|||||||
),
|
),
|
||||||
imageResourcesPath: AppOptions.get("imageResourcesPath"),
|
imageResourcesPath: AppOptions.get("imageResourcesPath"),
|
||||||
enablePrintAutoRotate: AppOptions.get("enablePrintAutoRotate"),
|
enablePrintAutoRotate: AppOptions.get("enablePrintAutoRotate"),
|
||||||
maxCanvasPixels: AppOptions.get("maxCanvasPixels"),
|
maxCanvasPixels,
|
||||||
maxCanvasDim,
|
maxCanvasDim,
|
||||||
enableDetailCanvas: AppOptions.get("enableDetailCanvas"),
|
enableDetailCanvas: AppOptions.get("enableDetailCanvas"),
|
||||||
enablePermissions: AppOptions.get("enablePermissions"),
|
enablePermissions: AppOptions.get("enablePermissions"),
|
||||||
@ -529,6 +530,7 @@ const PDFViewerApplication = {
|
|||||||
eventBus,
|
eventBus,
|
||||||
renderingQueue: pdfRenderingQueue,
|
renderingQueue: pdfRenderingQueue,
|
||||||
linkService: pdfLinkService,
|
linkService: pdfLinkService,
|
||||||
|
maxCanvasPixels,
|
||||||
maxCanvasDim,
|
maxCanvasDim,
|
||||||
pageColors,
|
pageColors,
|
||||||
abortSignal,
|
abortSignal,
|
||||||
|
|||||||
@ -775,28 +775,13 @@ class PDFPageView extends BasePDFPageView {
|
|||||||
outputScale.sx *= invScale;
|
outputScale.sx *= invScale;
|
||||||
outputScale.sy *= invScale;
|
outputScale.sy *= invScale;
|
||||||
this.#needsRestrictedScaling = true;
|
this.#needsRestrictedScaling = true;
|
||||||
} else if (this.maxCanvasPixels > 0 || this.maxCanvasDim !== -1) {
|
} else {
|
||||||
let maxAreaScale = Infinity,
|
this.#needsRestrictedScaling = outputScale.limitCanvas(
|
||||||
maxWidthScale = Infinity,
|
width,
|
||||||
maxHeightScale = Infinity;
|
height,
|
||||||
|
this.maxCanvasPixels,
|
||||||
if (this.maxCanvasPixels > 0) {
|
this.maxCanvasDim
|
||||||
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;
|
|
||||||
this.#needsRestrictedScaling = true;
|
|
||||||
} else {
|
|
||||||
this.#needsRestrictedScaling = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -42,6 +42,9 @@ const THUMBNAIL_WIDTH = 98; // px
|
|||||||
* The default value is `null`.
|
* The default value is `null`.
|
||||||
* @property {IPDFLinkService} linkService - The navigation/linking service.
|
* @property {IPDFLinkService} linkService - The navigation/linking service.
|
||||||
* @property {PDFRenderingQueue} renderingQueue - The rendering queue object.
|
* @property {PDFRenderingQueue} renderingQueue - The rendering queue object.
|
||||||
|
* @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,
|
* @property {number} [maxCanvasDim] - The maximum supported canvas dimension,
|
||||||
* in either width or height. Use `-1` for no limit.
|
* in either width or height. Use `-1` for no limit.
|
||||||
* The default value is 32767.
|
* The default value is 32767.
|
||||||
@ -97,6 +100,7 @@ class PDFThumbnailView {
|
|||||||
optionalContentConfigPromise,
|
optionalContentConfigPromise,
|
||||||
linkService,
|
linkService,
|
||||||
renderingQueue,
|
renderingQueue,
|
||||||
|
maxCanvasPixels,
|
||||||
maxCanvasDim,
|
maxCanvasDim,
|
||||||
pageColors,
|
pageColors,
|
||||||
enableHWA,
|
enableHWA,
|
||||||
@ -110,6 +114,7 @@ class PDFThumbnailView {
|
|||||||
this.viewport = defaultViewport;
|
this.viewport = defaultViewport;
|
||||||
this.pdfPageRotate = defaultViewport.rotation;
|
this.pdfPageRotate = defaultViewport.rotation;
|
||||||
this._optionalContentConfigPromise = optionalContentConfigPromise || null;
|
this._optionalContentConfigPromise = optionalContentConfigPromise || null;
|
||||||
|
this.maxCanvasPixels = maxCanvasPixels ?? AppOptions.get("maxCanvasPixels");
|
||||||
this.maxCanvasDim = maxCanvasDim || AppOptions.get("maxCanvasDim");
|
this.maxCanvasDim = maxCanvasDim || AppOptions.get("maxCanvasDim");
|
||||||
this.pageColors = pageColors || null;
|
this.pageColors = pageColors || null;
|
||||||
this.enableHWA = enableHWA || false;
|
this.enableHWA = enableHWA || false;
|
||||||
@ -218,16 +223,12 @@ class PDFThumbnailView {
|
|||||||
const width = upscaleFactor * this.canvasWidth,
|
const width = upscaleFactor * this.canvasWidth,
|
||||||
height = upscaleFactor * this.canvasHeight;
|
height = upscaleFactor * this.canvasHeight;
|
||||||
|
|
||||||
if (this.maxCanvasDim !== -1) {
|
outputScale.limitCanvas(
|
||||||
const maxScale = Math.min(
|
width,
|
||||||
this.maxCanvasDim / width,
|
height,
|
||||||
this.maxCanvasDim / height
|
this.maxCanvasPixels,
|
||||||
);
|
this.maxCanvasDim
|
||||||
if (outputScale.sx > maxScale || outputScale.sy > maxScale) {
|
);
|
||||||
outputScale.sx = maxScale;
|
|
||||||
outputScale.sy = maxScale;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
canvas.width = (width * outputScale.sx) | 0;
|
canvas.width = (width * outputScale.sx) | 0;
|
||||||
canvas.height = (height * outputScale.sy) | 0;
|
canvas.height = (height * outputScale.sy) | 0;
|
||||||
|
|
||||||
@ -364,6 +365,27 @@ class PDFThumbnailView {
|
|||||||
this.#convertCanvasToImage(canvas);
|
this.#convertCanvasToImage(canvas);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#getReducedImageDims(canvas) {
|
||||||
|
let reducedWidth = canvas.width << MAX_NUM_SCALING_STEPS,
|
||||||
|
reducedHeight = canvas.height << MAX_NUM_SCALING_STEPS;
|
||||||
|
|
||||||
|
const outputScale = new OutputScale();
|
||||||
|
// Here we're not actually "rendering" to the canvas and the `OutputScale`
|
||||||
|
// is thus only used to limit the canvas size, hence the identity scale.
|
||||||
|
outputScale.sx = outputScale.sy = 1;
|
||||||
|
|
||||||
|
outputScale.limitCanvas(
|
||||||
|
reducedWidth,
|
||||||
|
reducedHeight,
|
||||||
|
this.maxCanvasPixels,
|
||||||
|
this.maxCanvasDim
|
||||||
|
);
|
||||||
|
reducedWidth = (reducedWidth * outputScale.sx) | 0;
|
||||||
|
reducedHeight = (reducedHeight * outputScale.sy) | 0;
|
||||||
|
|
||||||
|
return [reducedWidth, reducedHeight];
|
||||||
|
}
|
||||||
|
|
||||||
#reduceImage(img) {
|
#reduceImage(img) {
|
||||||
const { ctx, canvas } = this.#getPageDrawContext(1, true);
|
const { ctx, canvas } = this.#getPageDrawContext(1, true);
|
||||||
|
|
||||||
@ -381,24 +403,8 @@ class PDFThumbnailView {
|
|||||||
);
|
);
|
||||||
return canvas;
|
return canvas;
|
||||||
}
|
}
|
||||||
const { maxCanvasDim } = this;
|
|
||||||
|
|
||||||
// drawImage does an awful job of rescaling the image, doing it gradually.
|
// drawImage does an awful job of rescaling the image, doing it gradually.
|
||||||
let reducedWidth = canvas.width << MAX_NUM_SCALING_STEPS;
|
let [reducedWidth, reducedHeight] = this.#getReducedImageDims(canvas);
|
||||||
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(
|
const [reducedImage, reducedImageCtx] = TempImageFactory.getCanvas(
|
||||||
reducedWidth,
|
reducedWidth,
|
||||||
reducedHeight
|
reducedHeight
|
||||||
|
|||||||
@ -39,6 +39,9 @@ const THUMBNAIL_SELECTED_CLASS = "selected";
|
|||||||
* @property {EventBus} eventBus - The application event bus.
|
* @property {EventBus} eventBus - The application event bus.
|
||||||
* @property {IPDFLinkService} linkService - The navigation/linking service.
|
* @property {IPDFLinkService} linkService - The navigation/linking service.
|
||||||
* @property {PDFRenderingQueue} renderingQueue - The rendering queue object.
|
* @property {PDFRenderingQueue} renderingQueue - The rendering queue object.
|
||||||
|
* @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,
|
* @property {number} [maxCanvasDim] - The maximum supported canvas dimension,
|
||||||
* in either width or height. Use `-1` for no limit.
|
* in either width or height. Use `-1` for no limit.
|
||||||
* The default value is 32767.
|
* The default value is 32767.
|
||||||
@ -63,6 +66,7 @@ class PDFThumbnailViewer {
|
|||||||
eventBus,
|
eventBus,
|
||||||
linkService,
|
linkService,
|
||||||
renderingQueue,
|
renderingQueue,
|
||||||
|
maxCanvasPixels,
|
||||||
maxCanvasDim,
|
maxCanvasDim,
|
||||||
pageColors,
|
pageColors,
|
||||||
abortSignal,
|
abortSignal,
|
||||||
@ -72,6 +76,7 @@ class PDFThumbnailViewer {
|
|||||||
this.eventBus = eventBus;
|
this.eventBus = eventBus;
|
||||||
this.linkService = linkService;
|
this.linkService = linkService;
|
||||||
this.renderingQueue = renderingQueue;
|
this.renderingQueue = renderingQueue;
|
||||||
|
this.maxCanvasPixels = maxCanvasPixels;
|
||||||
this.maxCanvasDim = maxCanvasDim;
|
this.maxCanvasDim = maxCanvasDim;
|
||||||
this.pageColors = pageColors || null;
|
this.pageColors = pageColors || null;
|
||||||
this.enableHWA = enableHWA || false;
|
this.enableHWA = enableHWA || false;
|
||||||
@ -214,6 +219,7 @@ class PDFThumbnailViewer {
|
|||||||
optionalContentConfigPromise,
|
optionalContentConfigPromise,
|
||||||
linkService: this.linkService,
|
linkService: this.linkService,
|
||||||
renderingQueue: this.renderingQueue,
|
renderingQueue: this.renderingQueue,
|
||||||
|
maxCanvasPixels: this.maxCanvasPixels,
|
||||||
maxCanvasDim: this.maxCanvasDim,
|
maxCanvasDim: this.maxCanvasDim,
|
||||||
pageColors: this.pageColors,
|
pageColors: this.pageColors,
|
||||||
enableHWA: this.enableHWA,
|
enableHWA: this.enableHWA,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user