mirror of
https://github.com/mozilla/pdf.js.git
synced 2026-06-28 11:15:49 +02:00
Compare commits
8 Commits
81baa16c8b
...
4152eae3fb
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4152eae3fb | ||
|
|
26b5c8f821 | ||
|
|
0edfd29a3e | ||
|
|
b9e8844541 | ||
|
|
fc22d3afc7 | ||
|
|
10a99ea0a7 | ||
|
|
1bc98dfbd9 | ||
|
|
eef15a30cd |
@ -4679,8 +4679,15 @@ class TranslatedFont {
|
||||
// not execute any operators that set the colour (or other
|
||||
// colour-related parameters) in the graphics state;
|
||||
// any use of such operators shall be ignored."
|
||||
if (operatorList.fnArray[0] === OPS.setCharWidthAndBounds) {
|
||||
this.#removeType3ColorOperators(operatorList, fontBBoxSize);
|
||||
switch (operatorList.fnArray[0]) {
|
||||
case OPS.setCharWidthAndBounds:
|
||||
this.#removeType3ColorOperators(operatorList, fontBBoxSize);
|
||||
break;
|
||||
case OPS.setCharWidth:
|
||||
if (!fontBBoxSize) {
|
||||
this.#guessType3FontBBox(operatorList);
|
||||
}
|
||||
break;
|
||||
}
|
||||
charProcOperatorList[key] = operatorList.getIR();
|
||||
|
||||
@ -4728,13 +4735,7 @@ class TranslatedFont {
|
||||
// Override the fontBBox when it's undefined/empty, or when it's at least
|
||||
// (approximately) one order of magnitude smaller than the charBBox
|
||||
// (fixes issue14999_reduced.pdf).
|
||||
if (!this._bbox) {
|
||||
this._bbox = [Infinity, Infinity, -Infinity, -Infinity];
|
||||
}
|
||||
this._bbox[0] = Math.min(this._bbox[0], charBBox[0]);
|
||||
this._bbox[1] = Math.min(this._bbox[1], charBBox[1]);
|
||||
this._bbox[2] = Math.max(this._bbox[2], charBBox[2]);
|
||||
this._bbox[3] = Math.max(this._bbox[3], charBBox[3]);
|
||||
this.#computeCharBBox(charBBox);
|
||||
}
|
||||
|
||||
let i = 0,
|
||||
@ -4787,6 +4788,37 @@ class TranslatedFont {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
#guessType3FontBBox(operatorList) {
|
||||
if (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) {
|
||||
assert(
|
||||
operatorList.fnArray[0] === OPS.setCharWidth,
|
||||
"Type3 glyph shall start with the d0 operator."
|
||||
);
|
||||
}
|
||||
|
||||
let i = 1;
|
||||
const ii = operatorList.length;
|
||||
while (i < ii) {
|
||||
switch (operatorList.fnArray[i]) {
|
||||
case OPS.constructPath:
|
||||
const minMax = operatorList.argsArray[i][2];
|
||||
// Override the fontBBox when it's undefined/empty (fixes 19624.pdf).
|
||||
this.#computeCharBBox(minMax);
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
#computeCharBBox(bbox) {
|
||||
this._bbox ||= [Infinity, Infinity, -Infinity, -Infinity];
|
||||
|
||||
this._bbox[0] = Math.min(this._bbox[0], bbox[0]);
|
||||
this._bbox[1] = Math.min(this._bbox[1], bbox[1]);
|
||||
this._bbox[2] = Math.max(this._bbox[2], bbox[2]);
|
||||
this._bbox[3] = Math.max(this._bbox[3], bbox[3]);
|
||||
}
|
||||
}
|
||||
|
||||
class StateManager {
|
||||
|
||||
@ -140,11 +140,26 @@ class PDFImage {
|
||||
);
|
||||
width = image.width;
|
||||
height = image.height;
|
||||
}
|
||||
if (width < 1 || height < 1) {
|
||||
throw new FormatError(
|
||||
`Invalid image width: ${width} or height: ${height}`
|
||||
);
|
||||
} else {
|
||||
const validWidth = typeof width === "number" && width > 0,
|
||||
validHeight = typeof height === "number" && height > 0;
|
||||
|
||||
if (!validWidth || !validHeight) {
|
||||
if (!image.fallbackDims) {
|
||||
throw new FormatError(
|
||||
`Invalid image width: ${width} or height: ${height}`
|
||||
);
|
||||
}
|
||||
warn(
|
||||
"PDFImage - using the Width/Height of the parent image, for SMask/Mask data."
|
||||
);
|
||||
if (!validWidth) {
|
||||
width = image.fallbackDims.width;
|
||||
}
|
||||
if (!validHeight) {
|
||||
height = image.fallbackDims.height;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
@ -244,6 +259,10 @@ class PDFImage {
|
||||
}
|
||||
|
||||
if (smask) {
|
||||
// Provide fallback width/height values for corrupt SMask images
|
||||
// (see issue19611.pdf).
|
||||
smask.fallbackDims ??= { width, height };
|
||||
|
||||
this.smask = new PDFImage({
|
||||
xref,
|
||||
res,
|
||||
@ -260,6 +279,10 @@ class PDFImage {
|
||||
if (!imageMask) {
|
||||
warn("Ignoring /Mask in image without /ImageMask.");
|
||||
} else {
|
||||
// Provide fallback width/height values for corrupt Mask images
|
||||
// (see issue19611.pdf).
|
||||
mask.fallbackDims ??= { width, height };
|
||||
|
||||
this.mask = new PDFImage({
|
||||
xref,
|
||||
res,
|
||||
|
||||
@ -640,9 +640,39 @@ class OutputScale {
|
||||
return this.sx !== 1 || this.sy !== 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {boolean} Returns `true` when scaling is symmetric,
|
||||
* `false` otherwise.
|
||||
*/
|
||||
get symmetric() {
|
||||
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
|
||||
|
||||
1
test/pdfs/issue19611.pdf.link
Normal file
1
test/pdfs/issue19611.pdf.link
Normal file
@ -0,0 +1 @@
|
||||
https://github.com/user-attachments/files/19102190/test.pdf
|
||||
1
test/pdfs/issue19624.pdf.link
Normal file
1
test/pdfs/issue19624.pdf.link
Normal file
@ -0,0 +1 @@
|
||||
https://github.com/user-attachments/files/19126771/okm2500682934750615600.pdf
|
||||
@ -3913,6 +3913,23 @@
|
||||
"rounds": 1,
|
||||
"type": "eq"
|
||||
},
|
||||
{
|
||||
"id": "issue19611",
|
||||
"file": "pdfs/issue19611.pdf",
|
||||
"md5": "169dc6df1c43dcb4659b2ddb6a4b39e4",
|
||||
"rounds": 1,
|
||||
"link": true,
|
||||
"type": "eq"
|
||||
},
|
||||
{
|
||||
"id": "issue19624-text",
|
||||
"file": "pdfs/issue19624.pdf",
|
||||
"md5": "087ac2141dbfa218be833efcc143925a",
|
||||
"rounds": 1,
|
||||
"link": true,
|
||||
"firstPage": 2,
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"id": "issue1127-text",
|
||||
"file": "pdfs/issue1127.pdf",
|
||||
|
||||
@ -478,6 +478,7 @@ const PDFViewerApplication = {
|
||||
: null;
|
||||
|
||||
const enableHWA = AppOptions.get("enableHWA"),
|
||||
maxCanvasPixels = AppOptions.get("maxCanvasPixels"),
|
||||
maxCanvasDim = AppOptions.get("maxCanvasDim");
|
||||
const pdfViewer = new PDFViewer({
|
||||
container,
|
||||
@ -506,7 +507,7 @@ const PDFViewerApplication = {
|
||||
),
|
||||
imageResourcesPath: AppOptions.get("imageResourcesPath"),
|
||||
enablePrintAutoRotate: AppOptions.get("enablePrintAutoRotate"),
|
||||
maxCanvasPixels: AppOptions.get("maxCanvasPixels"),
|
||||
maxCanvasPixels,
|
||||
maxCanvasDim,
|
||||
enableDetailCanvas: AppOptions.get("enableDetailCanvas"),
|
||||
enablePermissions: AppOptions.get("enablePermissions"),
|
||||
@ -529,6 +530,7 @@ const PDFViewerApplication = {
|
||||
eventBus,
|
||||
renderingQueue: pdfRenderingQueue,
|
||||
linkService: pdfLinkService,
|
||||
maxCanvasPixels,
|
||||
maxCanvasDim,
|
||||
pageColors,
|
||||
abortSignal,
|
||||
|
||||
@ -775,28 +775,13 @@ class PDFPageView extends BasePDFPageView {
|
||||
outputScale.sx *= invScale;
|
||||
outputScale.sy *= invScale;
|
||||
this.#needsRestrictedScaling = true;
|
||||
} 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;
|
||||
this.#needsRestrictedScaling = true;
|
||||
} else {
|
||||
this.#needsRestrictedScaling = false;
|
||||
}
|
||||
} else {
|
||||
this.#needsRestrictedScaling = outputScale.limitCanvas(
|
||||
width,
|
||||
height,
|
||||
this.maxCanvasPixels,
|
||||
this.maxCanvasDim
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -42,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} [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.
|
||||
@ -97,6 +100,7 @@ class PDFThumbnailView {
|
||||
optionalContentConfigPromise,
|
||||
linkService,
|
||||
renderingQueue,
|
||||
maxCanvasPixels,
|
||||
maxCanvasDim,
|
||||
pageColors,
|
||||
enableHWA,
|
||||
@ -110,6 +114,7 @@ class PDFThumbnailView {
|
||||
this.viewport = defaultViewport;
|
||||
this.pdfPageRotate = defaultViewport.rotation;
|
||||
this._optionalContentConfigPromise = optionalContentConfigPromise || null;
|
||||
this.maxCanvasPixels = maxCanvasPixels ?? AppOptions.get("maxCanvasPixels");
|
||||
this.maxCanvasDim = maxCanvasDim || AppOptions.get("maxCanvasDim");
|
||||
this.pageColors = pageColors || null;
|
||||
this.enableHWA = enableHWA || false;
|
||||
@ -215,9 +220,17 @@ class PDFThumbnailView {
|
||||
willReadFrequently: !enableHWA,
|
||||
});
|
||||
const outputScale = new OutputScale();
|
||||
const width = upscaleFactor * this.canvasWidth,
|
||||
height = upscaleFactor * this.canvasHeight;
|
||||
|
||||
canvas.width = (upscaleFactor * this.canvasWidth * outputScale.sx) | 0;
|
||||
canvas.height = (upscaleFactor * this.canvasHeight * outputScale.sy) | 0;
|
||||
outputScale.limitCanvas(
|
||||
width,
|
||||
height,
|
||||
this.maxCanvasPixels,
|
||||
this.maxCanvasDim
|
||||
);
|
||||
canvas.width = (width * outputScale.sx) | 0;
|
||||
canvas.height = (height * outputScale.sy) | 0;
|
||||
|
||||
const transform = outputScale.scaled
|
||||
? [outputScale.sx, 0, 0, outputScale.sy, 0, 0]
|
||||
@ -352,6 +365,27 @@ class PDFThumbnailView {
|
||||
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) {
|
||||
const { ctx, canvas } = this.#getPageDrawContext(1, true);
|
||||
|
||||
@ -369,24 +403,8 @@ 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;
|
||||
}
|
||||
}
|
||||
let [reducedWidth, reducedHeight] = this.#getReducedImageDims(canvas);
|
||||
const [reducedImage, reducedImageCtx] = TempImageFactory.getCanvas(
|
||||
reducedWidth,
|
||||
reducedHeight
|
||||
|
||||
@ -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} [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.
|
||||
@ -63,6 +66,7 @@ class PDFThumbnailViewer {
|
||||
eventBus,
|
||||
linkService,
|
||||
renderingQueue,
|
||||
maxCanvasPixels,
|
||||
maxCanvasDim,
|
||||
pageColors,
|
||||
abortSignal,
|
||||
@ -72,6 +76,7 @@ class PDFThumbnailViewer {
|
||||
this.eventBus = eventBus;
|
||||
this.linkService = linkService;
|
||||
this.renderingQueue = renderingQueue;
|
||||
this.maxCanvasPixels = maxCanvasPixels;
|
||||
this.maxCanvasDim = maxCanvasDim;
|
||||
this.pageColors = pageColors || null;
|
||||
this.enableHWA = enableHWA || false;
|
||||
@ -214,6 +219,7 @@ class PDFThumbnailViewer {
|
||||
optionalContentConfigPromise,
|
||||
linkService: this.linkService,
|
||||
renderingQueue: this.renderingQueue,
|
||||
maxCanvasPixels: this.maxCanvasPixels,
|
||||
maxCanvasDim: this.maxCanvasDim,
|
||||
pageColors: this.pageColors,
|
||||
enableHWA: this.enableHWA,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user