From 0d039937f94d63cc32a58cbd68aa6d6463bf9089 Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Tue, 26 Mar 2024 20:07:23 +0100 Subject: [PATCH] Add better support for /Launch actions with /FileSpec dictionaries (issue 17846) --- src/core/catalog.js | 10 +++++++--- src/core/file_spec.js | 16 ++++++++++------ test/pdfs/.gitignore | 1 + test/pdfs/issue17846.pdf | Bin 0 -> 14935 bytes test/unit/api_spec.js | 20 ++++++++++++++++++++ 5 files changed, 38 insertions(+), 9 deletions(-) create mode 100644 test/pdfs/issue17846.pdf diff --git a/src/core/catalog.js b/src/core/catalog.js index 7081d1c53..55d0e13c5 100644 --- a/src/core/catalog.js +++ b/src/core/catalog.js @@ -1568,9 +1568,13 @@ class Catalog { case "GoToR": const urlDict = action.get("F"); if (urlDict instanceof Dict) { - // We assume that we found a FileSpec dictionary - // and fetch the URL without checking any further. - url = urlDict.get("F") || null; + const fs = new FileSpec( + urlDict, + /* xref = */ null, + /* skipContent = */ true + ); + const { filename } = fs.serializable; + url = filename; } else if (typeof urlDict === "string") { url = urlDict; } diff --git a/src/core/file_spec.js b/src/core/file_spec.js index da85e9046..8ce91c352 100644 --- a/src/core/file_spec.js +++ b/src/core/file_spec.js @@ -42,7 +42,9 @@ function pickPlatformItem(dict) { * collections attributes and related files (/RF) */ class FileSpec { - constructor(root, xref) { + #contentAvailable = false; + + constructor(root, xref, skipContent = false) { if (!(root instanceof Dict)) { return; } @@ -57,10 +59,12 @@ class FileSpec { if (root.has("RF")) { warn("Related file specifications are not supported"); } - this.contentAvailable = true; - if (!root.has("EF")) { - this.contentAvailable = false; - warn("Non-embedded file specifications are not supported"); + if (!skipContent) { + if (root.has("EF")) { + this.#contentAvailable = true; + } else { + warn("Non-embedded file specifications are not supported"); + } } } @@ -76,7 +80,7 @@ class FileSpec { } get content() { - if (!this.contentAvailable) { + if (!this.#contentAvailable) { return null; } if (!this.contentRef && this.root) { diff --git a/test/pdfs/.gitignore b/test/pdfs/.gitignore index be38029c5..29b737b57 100644 --- a/test/pdfs/.gitignore +++ b/test/pdfs/.gitignore @@ -63,6 +63,7 @@ !issue7507.pdf !issue6931_reduced.pdf !issue14847.pdf +!issue17846.pdf !doc_actions.pdf !issue7580.pdf !issue7598.pdf diff --git a/test/pdfs/issue17846.pdf b/test/pdfs/issue17846.pdf new file mode 100644 index 0000000000000000000000000000000000000000..407a3ee6a8bf6a1cd7569b10e8200447c07ce352 GIT binary patch literal 14935 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 literal 0 HcmV?d00001 diff --git a/test/unit/api_spec.js b/test/unit/api_spec.js index 6870ddb8b..d9cbdfa46 100644 --- a/test/unit/api_spec.js +++ b/test/unit/api_spec.js @@ -2926,6 +2926,26 @@ describe("api", function () { await loadingTask.destroy(); }); + it("gets annotations containing /Launch action with /FileSpec dictionary (issue 17846)", async function () { + const loadingTask = getDocument(buildGetDocumentParams("issue17846.pdf")); + const pdfDoc = await loadingTask.promise; + const pdfPage = await pdfDoc.getPage(1); + + const annotations = await pdfPage.getAnnotations(); + expect(annotations.length).toEqual(1); + + const { annotationType, url, unsafeUrl, newWindow } = annotations[0]; + expect(annotationType).toEqual(AnnotationType.LINK); + + expect(url).toBeUndefined(); + expect(unsafeUrl).toEqual( + "对不起/没关系/1_1_模块1行政文件和药品信息目录.pdf" + ); + expect(newWindow).toEqual(true); + + await loadingTask.destroy(); + }); + it("gets text content", async function () { const { items, styles } = await page.getTextContent();