From c6e3fc4fe688165bd9f7d6223d3ef55d935f78c1 Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Sun, 8 Dec 2024 14:45:54 +0100 Subject: [PATCH] Take the `userUnit` into account in the `PageViewport` class (issue 19176) --- src/display/api.js | 1 + src/display/display_utils.js | 19 ++++++++++++++----- test/pdfs/.gitignore | 1 + test/pdfs/issue19176.pdf | 28 ++++++++++++++++++++++++++++ test/test_manifest.json | 7 +++++++ test/unit/api_spec.js | 34 +++++++++++++++++++++++++++++++++- 6 files changed, 84 insertions(+), 6 deletions(-) create mode 100644 test/pdfs/issue19176.pdf diff --git a/src/display/api.js b/src/display/api.js index 91cf928d1..e3cb683f7 100644 --- a/src/display/api.js +++ b/src/display/api.js @@ -1408,6 +1408,7 @@ class PDFPageProxy { } = {}) { return new PageViewport({ viewBox: this.view, + userUnit: this.userUnit, scale, rotation, offsetX, diff --git a/src/display/display_utils.js b/src/display/display_utils.js index 3a0b653b7..5d40e2349 100644 --- a/src/display/display_utils.js +++ b/src/display/display_utils.js @@ -83,6 +83,7 @@ async function fetchData(url, type = "text") { * @typedef {Object} PageViewportParameters * @property {Array} viewBox - The xMin, yMin, xMax and * yMax coordinates. + * @property {number} userUnit - The size of units. * @property {number} scale - The scale of the viewport. * @property {number} rotation - The rotation, in degrees, of the viewport. * @property {number} [offsetX] - The horizontal, i.e. x-axis, offset. The @@ -116,6 +117,7 @@ class PageViewport { */ constructor({ viewBox, + userUnit, scale, rotation, offsetX = 0, @@ -123,11 +125,14 @@ class PageViewport { dontFlip = false, }) { this.viewBox = viewBox; + this.userUnit = userUnit; this.scale = scale; this.rotation = rotation; this.offsetX = offsetX; this.offsetY = offsetY; + scale *= userUnit; // Take the userUnit into account. + // creating transform to convert pdf coordinate system to the normal // canvas like coordinates taking in account scale and rotation const centerX = (viewBox[2] + viewBox[0]) / 2; @@ -208,12 +213,14 @@ class PageViewport { * @type {Object} */ get rawDims() { - const { viewBox } = this; + const { userUnit, viewBox } = this; + const dims = viewBox.map(x => x * userUnit); + return shadow(this, "rawDims", { - pageWidth: viewBox[2] - viewBox[0], - pageHeight: viewBox[3] - viewBox[1], - pageX: viewBox[0], - pageY: viewBox[1], + pageWidth: dims[2] - dims[0], + pageHeight: dims[3] - dims[1], + pageX: dims[0], + pageY: dims[1], }); } @@ -231,6 +238,7 @@ class PageViewport { } = {}) { return new PageViewport({ viewBox: this.viewBox.slice(), + userUnit: this.userUnit, scale, rotation, offsetX, @@ -514,6 +522,7 @@ function getXfaPageViewport(xfaPage, { scale = 1, rotation = 0 }) { return new PageViewport({ viewBox, + userUnit: 1, scale, rotation, }); diff --git a/test/pdfs/.gitignore b/test/pdfs/.gitignore index fc38de944..5608e0df9 100644 --- a/test/pdfs/.gitignore +++ b/test/pdfs/.gitignore @@ -553,6 +553,7 @@ !poppler-67295-0.pdf !poppler-85140-0.pdf !issue15012.pdf +!issue19176.pdf !issue15150.pdf !poppler-395-0-fuzzed.pdf !issue14165.pdf diff --git a/test/pdfs/issue19176.pdf b/test/pdfs/issue19176.pdf new file mode 100644 index 000000000..7bf465aee --- /dev/null +++ b/test/pdfs/issue19176.pdf @@ -0,0 +1,28 @@ +%PDF-2.0 +%¿÷¢þ +1 0 obj +<< /Pages 2 0 R /Type /Catalog >> +endobj +2 0 obj +<< /Count 1 /Kids [ 3 0 R ] /Type /Pages >> +endobj +3 0 obj +<< /Type /Page /Parent 2 0 R /Resources << >> /MediaBox [0 0 8.5 11] /UserUnit 72 /Contents 4 0 R >> +endobj +4 0 obj +<< /Length 15 >> +stream +1 1 6.5 9 re f +endstream +endobj +xref +0 5 +0000000000 65535 f +0000000015 00000 n +0000000064 00000 n +0000000123 00000 n +0000000239 00000 n +trailer << /Root 1 0 R /Size 5 >> +startxref +303 +%%EOF diff --git a/test/test_manifest.json b/test/test_manifest.json index 30dffed82..fcf74bc76 100644 --- a/test/test_manifest.json +++ b/test/test_manifest.json @@ -2734,6 +2734,13 @@ "type": "eq", "about": "TrueType font with (0, 1) cmap." }, + { + "id": "issue19176", + "file": "pdfs/issue19176.pdf", + "md5": "c307418412a72997671518fa978439e0", + "rounds": 1, + "type": "eq" + }, { "id": "issue4801", "file": "pdfs/issue4801.pdf", diff --git a/test/unit/api_spec.js b/test/unit/api_spec.js index 58cb5215b..2abced6f3 100644 --- a/test/unit/api_spec.js +++ b/test/unit/api_spec.js @@ -3081,10 +3081,21 @@ describe("api", function () { expect(page.ref).toEqual({ num: 15, gen: 0 }); }); - it("gets userUnit", function () { + it("gets default userUnit", function () { expect(page.userUnit).toEqual(1.0); }); + it("gets non-default userUnit", async function () { + const loadingTask = getDocument(buildGetDocumentParams("issue19176.pdf")); + + const pdfDoc = await loadingTask.promise; + const pdfPage = await pdfDoc.getPage(1); + + expect(pdfPage.userUnit).toEqual(72); + + await loadingTask.destroy(); + }); + it("gets view", function () { expect(page.view).toEqual([0, 0, 595.28, 841.89]); }); @@ -3116,6 +3127,7 @@ describe("api", function () { expect(viewport instanceof PageViewport).toEqual(true); expect(viewport.viewBox).toEqual(page.view); + expect(viewport.userUnit).toEqual(page.userUnit); expect(viewport.scale).toEqual(1.5); expect(viewport.rotation).toEqual(90); expect(viewport.transform).toEqual([0, 1.5, 1.5, 0, 0, 0]); @@ -3123,6 +3135,26 @@ describe("api", function () { expect(viewport.height).toEqual(892.92); }); + it("gets viewport with non-default userUnit", async function () { + const loadingTask = getDocument(buildGetDocumentParams("issue19176.pdf")); + + const pdfDoc = await loadingTask.promise; + const pdfPage = await pdfDoc.getPage(1); + + const viewport = pdfPage.getViewport({ scale: 1 }); + expect(viewport instanceof PageViewport).toEqual(true); + + expect(viewport.viewBox).toEqual(pdfPage.view); + expect(viewport.userUnit).toEqual(pdfPage.userUnit); + expect(viewport.scale).toEqual(1); + expect(viewport.rotation).toEqual(0); + expect(viewport.transform).toEqual([72, 0, 0, -72, 0, 792]); + expect(viewport.width).toEqual(612); + expect(viewport.height).toEqual(792); + + await loadingTask.destroy(); + }); + it('gets viewport with "offsetX/offsetY" arguments', function () { const viewport = page.getViewport({ scale: 1,