Skip to content

Commit 68332ec

Browse files
committed
Avoid to have a white line around the canvas
The canvas must have the same dims as the page in order to avoid to see the page background.
1 parent 77c7ec6 commit 68332ec

File tree

8 files changed

+146
-7
lines changed

8 files changed

+146
-7
lines changed

src/display/display_utils.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1103,8 +1103,12 @@ function setLayerDimensions(
11031103

11041104
const w = `var(--scale-factor) * ${pageWidth}px`,
11051105
h = `var(--scale-factor) * ${pageHeight}px`;
1106-
const widthStr = useRound ? `round(${w}, 1px)` : `calc(${w})`,
1107-
heightStr = useRound ? `round(${h}, 1px)` : `calc(${h})`;
1106+
const widthStr = useRound
1107+
? `round(down, ${w}, var(--scale-round-x, 1px))`
1108+
: `calc(${w})`,
1109+
heightStr = useRound
1110+
? `round(down, ${h}, var(--scale-round-y, 1px))`
1111+
: `calc(${h})`;
11081112

11091113
if (!mustFlip || viewport.rotation % 180 === 0) {
11101114
style.width = widthStr;

test/integration/viewer_spec.mjs

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,10 @@ import {
1919
createPromise,
2020
getSpanRectFromText,
2121
loadAndWait,
22+
scrollIntoView,
23+
waitForPageRendered,
2224
} from "./test_utils.mjs";
25+
import { PNG } from "pngjs";
2326

2427
describe("PDF viewer", () => {
2528
describe("Zoom origin", () => {
@@ -365,4 +368,75 @@ describe("PDF viewer", () => {
365368
});
366369
});
367370
});
371+
372+
describe("Canvas fits the page", () => {
373+
let pages;
374+
375+
beforeAll(async () => {
376+
pages = await loadAndWait(
377+
"issue18694.pdf",
378+
".textLayer .endOfContent",
379+
"page-width"
380+
);
381+
});
382+
383+
afterAll(async () => {
384+
await closePages(pages);
385+
});
386+
387+
it("must check that canvas perfectly fits the page whatever the zoom level is", async () => {
388+
await Promise.all(
389+
pages.map(async ([browserName, page]) => {
390+
const debug = false;
391+
392+
// The pdf has a single page with a red background.
393+
// We set the viewer background to red, because when screenshoting
394+
// some part of the viewer background can be visible.
395+
// But here we don't care about the viewer background: we only
396+
// care about the page background and the canvas default color.
397+
398+
await page.evaluate(() => {
399+
document.body.style.background = "#ff0000";
400+
const toolbar = document.querySelector(".toolbar");
401+
toolbar.style.display = "none";
402+
});
403+
await page.waitForSelector(".toolbar", { visible: false });
404+
await page.evaluate(() => {
405+
const p = document.querySelector(`.page[data-page-number="1"]`);
406+
p.style.border = "none";
407+
});
408+
409+
for (let i = 0; ; i++) {
410+
const handle = await waitForPageRendered(page);
411+
await page.evaluate(() => window.PDFViewerApplication.zoomOut());
412+
await awaitPromise(handle);
413+
await scrollIntoView(page, `.page[data-page-number="1"]`);
414+
415+
const element = await page.$(`.page[data-page-number="1"]`);
416+
const png = await element.screenshot({
417+
type: "png",
418+
path: debug ? `foo${i}.png` : "",
419+
});
420+
const pageImage = PNG.sync.read(Buffer.from(png));
421+
let buffer = new Uint32Array(pageImage.data.buffer);
422+
423+
// Search for the first red pixel.
424+
const j = buffer.indexOf(0xff0000ff);
425+
buffer = buffer.slice(j);
426+
427+
expect(buffer.every(x => x === 0xff0000ff))
428+
.withContext(`In ${browserName}, in the ${i}th zoom in`)
429+
.toBe(true);
430+
431+
const currentScale = await page.evaluate(
432+
() => window.PDFViewerApplication.pdfViewer.currentScale
433+
);
434+
if (currentScale <= 0.1) {
435+
break;
436+
}
437+
}
438+
})
439+
);
440+
});
441+
});
368442
});

test/pdfs/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -665,3 +665,4 @@
665665
!highlights.pdf
666666
!highlight.pdf
667667
!bug1708040.pdf
668+
!issue18694.pdf

test/pdfs/issue18694.pdf

7.35 KB
Binary file not shown.

test/unit/ui_utils_spec.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import {
1717
backtrackBeforeAllVisibleElements,
1818
binarySearchFirstItem,
19+
calcRound,
1920
getPageSizeInches,
2021
getVisibleElements,
2122
isPortraitOrientation,
@@ -627,4 +628,17 @@ describe("ui_utils", function () {
627628
});
628629
});
629630
});
631+
632+
describe("calcRound", function () {
633+
it("should handle different browsers/environments correctly", function () {
634+
if (
635+
typeof window !== "undefined" &&
636+
window.navigator?.userAgent?.includes("Firefox")
637+
) {
638+
expect(calcRound(1.6)).not.toEqual(1.6);
639+
} else {
640+
expect(calcRound(1.6)).toEqual(1.6);
641+
}
642+
});
643+
});
630644
});

web/pdf_page_view.js

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import {
3333
} from "pdfjs-lib";
3434
import {
3535
approximateFraction,
36+
calcRound,
3637
DEFAULT_SCALE,
3738
floorToDivide,
3839
OutputScale,
@@ -127,6 +128,10 @@ class PDFPageView {
127128

128129
#previousRotation = null;
129130

131+
#scaleRoundX = 1;
132+
133+
#scaleRoundY = 1;
134+
130135
#renderError = null;
131136

132137
#renderingState = RenderingStates.INITIAL;
@@ -1039,11 +1044,27 @@ class PDFPageView {
10391044
const sfx = approximateFraction(outputScale.sx);
10401045
const sfy = approximateFraction(outputScale.sy);
10411046

1042-
canvas.width = floorToDivide(width * outputScale.sx, sfx[0]);
1043-
canvas.height = floorToDivide(height * outputScale.sy, sfy[0]);
1044-
const { style } = canvas;
1045-
style.width = floorToDivide(width, sfx[1]) + "px";
1046-
style.height = floorToDivide(height, sfy[1]) + "px";
1047+
const canvasWidth = (canvas.width = floorToDivide(
1048+
calcRound(width * outputScale.sx),
1049+
sfx[0]
1050+
));
1051+
const canvasHeight = (canvas.height = floorToDivide(
1052+
calcRound(height * outputScale.sy),
1053+
sfy[0]
1054+
));
1055+
const pageWidth = floorToDivide(calcRound(width), sfx[1]);
1056+
const pageHeight = floorToDivide(calcRound(height), sfy[1]);
1057+
outputScale.sx = canvasWidth / pageWidth;
1058+
outputScale.sy = canvasHeight / pageHeight;
1059+
1060+
if (this.#scaleRoundX !== sfx[1]) {
1061+
div.style.setProperty("--scale-round-x", `${sfx[1]}px`);
1062+
this.#scaleRoundX = sfx[1];
1063+
}
1064+
if (this.#scaleRoundY !== sfy[1]) {
1065+
div.style.setProperty("--scale-round-y", `${sfy[1]}px`);
1066+
this.#scaleRoundY = sfy[1];
1067+
}
10471068

10481069
// Add the viewport so it's known what it was originally drawn with.
10491070
this.#viewportMap.set(canvas, viewport);

web/pdf_viewer.css

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@
8383
canvas {
8484
margin: 0;
8585
display: block;
86+
width: 100%;
87+
height: 100%;
8688

8789
&[hidden] {
8890
display: none;
@@ -101,6 +103,9 @@
101103
}
102104

103105
.pdfViewer .page {
106+
--scale-round-x: 1px;
107+
--scale-round-y: 1px;
108+
104109
direction: ltr;
105110
width: 816px;
106111
height: 1056px;

web/ui_utils.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -862,6 +862,25 @@ function toggleExpandedBtn(button, toggle, view = null) {
862862
view?.classList.toggle("hidden", !toggle);
863863
}
864864

865+
// In Firefox, the css calc function uses f32 precision but the Chrome or Safari
866+
// are using f64 one. So in order to have the same rendering in all browsers, we
867+
// need to use the right precision in order to have correct dimensions.
868+
const calcRound =
869+
typeof PDFJSDev !== "undefined" && PDFJSDev.test("MOZCENTRAL")
870+
? Math.fround
871+
: (function () {
872+
if (
873+
typeof PDFJSDev !== "undefined" &&
874+
PDFJSDev.test("LIB") &&
875+
typeof document === "undefined"
876+
) {
877+
return x => x;
878+
}
879+
const e = document.createElement("div");
880+
e.style.width = "round(down, calc(1.6666666666666665 * 792px), 1px)";
881+
return e.style.width === "calc(1320px)" ? Math.fround : x => x;
882+
})();
883+
865884
export {
866885
animationStarted,
867886
apiPageLayoutToViewerModes,
@@ -870,6 +889,7 @@ export {
870889
AutoPrintRegExp,
871890
backtrackBeforeAllVisibleElements, // only exported for testing
872891
binarySearchFirstItem,
892+
calcRound,
873893
CursorTool,
874894
DEFAULT_SCALE,
875895
DEFAULT_SCALE_DELTA,

0 commit comments

Comments
 (0)