Add a unit-test for the Catalog.#getDestFromStructElement method

This code already has an integration-test, however also having a unit-test shouldn't hurt since those are often easier to run and debug (and it nicely complements the existing `outline` unit-tests).

The patch also makes the following smaller changes to the method itself:
 - Avoid creating and parsing an empty Array, when doing the `pageRef` search.
 - Use `XRef.prototype.fetch` directly, when walking the parent chain, since the check just above ensures that the value is a Reference.
 - Use the `lookupRect` helper when parsing the /BBox entry.
This commit is contained in:
Jonas Jenwald 2026-03-29 13:52:58 +02:00
parent a9e439bce1
commit d1f15fe352
2 changed files with 66 additions and 6 deletions

View File

@ -29,6 +29,7 @@ import {
import {
collectActions,
isNumberArray,
lookupRect,
MissingDataException,
PDF_VERSION_REGEXP,
recoverJsURL,
@ -1597,7 +1598,7 @@ class Catalog {
} else if (kids) {
kidsArr = [kids];
} else {
kidsArr = [];
continue;
}
for (const kid of kidsArr) {
const kidObj = xref.fetchIfRef(kid);
@ -1623,7 +1624,7 @@ class Catalog {
if (!(parentRaw instanceof Ref)) {
break;
}
const parentDict = xref.fetchIfRef(parentRaw);
const parentDict = xref.fetch(parentRaw);
if (!(parentDict instanceof Dict)) {
break;
}
@ -1648,10 +1649,10 @@ class Catalog {
y = null;
const attrs = seDict.get("A");
if (attrs instanceof Dict) {
const bboxArr = attrs.getArray("BBox");
if (isNumberArray(bboxArr, 4)) {
x = bboxArr[0];
y = bboxArr[3]; // top of the bbox in PDF page coordinates
const bbox = lookupRect(attrs.getArray("BBox"), null);
if (bbox) {
x = bbox[0];
y = bbox[3]; // top of the bbox in PDF page coordinates
}
}

View File

@ -2167,6 +2167,65 @@ describe("api", function () {
await loadingTask.destroy();
});
it("gets outline, with SE (Structure Element) entries", async function () {
const loadingTask = getDocument(
buildGetDocumentParams("outlines_se.pdf")
);
const pdfDoc = await loadingTask.promise;
const outline = await pdfDoc.getOutline();
expect(outline).toEqual([
{
action: null,
attachment: undefined,
dest: null,
url: null,
unsafeUrl: undefined,
newWindow: undefined,
setOCGState: undefined,
title: "P tags",
color: new Uint8ClampedArray([0, 0, 0]),
count: 2,
bold: false,
italic: false,
items: [
{
action: null,
attachment: undefined,
dest: [{ num: 37, gen: 0 }, { name: "XYZ" }, null, null, null],
url: null,
unsafeUrl: undefined,
newWindow: undefined,
setOCGState: undefined,
title: "Hello ",
color: new Uint8ClampedArray([0, 0, 0]),
count: undefined,
bold: false,
italic: false,
items: [],
},
{
action: null,
attachment: undefined,
dest: [{ num: 36, gen: 0 }, { name: "XYZ" }, null, null, null],
url: null,
unsafeUrl: undefined,
newWindow: undefined,
setOCGState: undefined,
title: "World ",
color: new Uint8ClampedArray([0, 0, 0]),
count: undefined,
bold: false,
italic: false,
items: [],
},
],
},
]);
await loadingTask.destroy();
});
it("gets non-existent permissions", async function () {
const permissions = await pdfDocument.getPermissions();
expect(permissions).toEqual(null);