Search for destinations in both /Names and /Dests dictionaries (issue 19474)
Currently we only use either one of them, preferring the NameTree when it's available.
This commit is contained in:
parent
c69282a64f
commit
33cba30bdb
@ -707,20 +707,23 @@ class Catalog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get destinations() {
|
get destinations() {
|
||||||
const obj = this._readDests(),
|
const rawDests = this.#readDests(),
|
||||||
dests = Object.create(null);
|
dests = Object.create(null);
|
||||||
if (obj instanceof NameTree) {
|
for (const obj of rawDests) {
|
||||||
for (const [key, value] of obj.getAll()) {
|
if (obj instanceof NameTree) {
|
||||||
const dest = fetchDest(value);
|
for (const [key, value] of obj.getAll()) {
|
||||||
if (dest) {
|
const dest = fetchDest(value);
|
||||||
dests[stringToPDFString(key)] = dest;
|
if (dest) {
|
||||||
|
dests[stringToPDFString(key)] = dest;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
} else if (obj instanceof Dict) {
|
||||||
} else if (obj instanceof Dict) {
|
for (const [key, value] of obj) {
|
||||||
for (const [key, value] of obj) {
|
const dest = fetchDest(value);
|
||||||
const dest = fetchDest(value);
|
if (dest) {
|
||||||
if (dest) {
|
// Always let the NameTree take precedence.
|
||||||
dests[key] = dest;
|
dests[key] ||= dest;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -728,40 +731,39 @@ class Catalog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getDestination(id) {
|
getDestination(id) {
|
||||||
const obj = this._readDests();
|
const rawDests = this.#readDests();
|
||||||
if (obj instanceof NameTree) {
|
for (const obj of rawDests) {
|
||||||
const dest = fetchDest(obj.get(id));
|
if (obj instanceof NameTree || obj instanceof Dict) {
|
||||||
if (dest) {
|
const dest = fetchDest(obj.get(id));
|
||||||
return dest;
|
if (dest) {
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rawDests[0] instanceof NameTree) {
|
||||||
// Fallback to checking the *entire* NameTree, in an attempt to handle
|
// Fallback to checking the *entire* NameTree, in an attempt to handle
|
||||||
// corrupt PDF documents with out-of-order NameTrees (fixes issue 10272).
|
// corrupt PDF documents with out-of-order NameTrees (fixes issue 10272).
|
||||||
const allDest = this.destinations[id];
|
const dest = this.destinations[id];
|
||||||
if (allDest) {
|
|
||||||
warn(`Found "${id}" at an incorrect position in the NameTree.`);
|
|
||||||
return allDest;
|
|
||||||
}
|
|
||||||
} else if (obj instanceof Dict) {
|
|
||||||
const dest = fetchDest(obj.get(id));
|
|
||||||
if (dest) {
|
if (dest) {
|
||||||
|
warn(`Found "${id}" at an incorrect position in the NameTree.`);
|
||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
#readDests() {
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
_readDests() {
|
|
||||||
const obj = this._catDict.get("Names");
|
const obj = this._catDict.get("Names");
|
||||||
|
const rawDests = [];
|
||||||
if (obj?.has("Dests")) {
|
if (obj?.has("Dests")) {
|
||||||
return new NameTree(obj.getRaw("Dests"), this.xref);
|
rawDests.push(new NameTree(obj.getRaw("Dests"), this.xref));
|
||||||
} else if (this._catDict.has("Dests")) {
|
|
||||||
// Simple destination dictionary.
|
|
||||||
return this._catDict.get("Dests");
|
|
||||||
}
|
}
|
||||||
return undefined;
|
if (this._catDict.has("Dests")) {
|
||||||
|
// Simple destination dictionary.
|
||||||
|
rawDests.push(this._catDict.get("Dests"));
|
||||||
|
}
|
||||||
|
return rawDests;
|
||||||
}
|
}
|
||||||
|
|
||||||
get pageLabels() {
|
get pageLabels() {
|
||||||
|
|||||||
1
test/pdfs/.gitignore
vendored
1
test/pdfs/.gitignore
vendored
@ -533,6 +533,7 @@
|
|||||||
!transparent.pdf
|
!transparent.pdf
|
||||||
!issue19326.pdf
|
!issue19326.pdf
|
||||||
!issue13931.pdf
|
!issue13931.pdf
|
||||||
|
!issue19474.pdf
|
||||||
!xobject-image.pdf
|
!xobject-image.pdf
|
||||||
!issue15441.pdf
|
!issue15441.pdf
|
||||||
!issue6605.pdf
|
!issue6605.pdf
|
||||||
|
|||||||
BIN
test/pdfs/issue19474.pdf
Normal file
BIN
test/pdfs/issue19474.pdf
Normal file
Binary file not shown.
@ -1261,6 +1261,19 @@ describe("api", function () {
|
|||||||
await loadingTask.destroy();
|
await loadingTask.destroy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("gets destinations, from /Names (NameTree) respectively /Dests dictionary", async function () {
|
||||||
|
const loadingTask = getDocument(buildGetDocumentParams("issue19474.pdf"));
|
||||||
|
const pdfDoc = await loadingTask.promise;
|
||||||
|
const destinations = await pdfDoc.getDestinations();
|
||||||
|
expect(destinations).toEqual({
|
||||||
|
A: [{ num: 1, gen: 0 }, { name: "Fit" }],
|
||||||
|
B: [{ num: 4, gen: 0 }, { name: "Fit" }],
|
||||||
|
C: [{ num: 5, gen: 0 }, { name: "Fit" }],
|
||||||
|
});
|
||||||
|
|
||||||
|
await loadingTask.destroy();
|
||||||
|
});
|
||||||
|
|
||||||
it("gets a destination, from /Names (NameTree) dictionary", async function () {
|
it("gets a destination, from /Names (NameTree) dictionary", async function () {
|
||||||
const loadingTask = getDocument(buildGetDocumentParams("issue6204.pdf"));
|
const loadingTask = getDocument(buildGetDocumentParams("issue6204.pdf"));
|
||||||
const pdfDoc = await loadingTask.promise;
|
const pdfDoc = await loadingTask.promise;
|
||||||
@ -1320,6 +1333,22 @@ describe("api", function () {
|
|||||||
await loadingTask.destroy();
|
await loadingTask.destroy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("gets a destination, from /Names (NameTree) respectively /Dests dictionary", async function () {
|
||||||
|
const loadingTask = getDocument(buildGetDocumentParams("issue19474.pdf"));
|
||||||
|
const pdfDoc = await loadingTask.promise;
|
||||||
|
|
||||||
|
const destA = await pdfDoc.getDestination("A");
|
||||||
|
expect(destA).toEqual([{ num: 1, gen: 0 }, { name: "Fit" }]);
|
||||||
|
|
||||||
|
const destB = await pdfDoc.getDestination("B");
|
||||||
|
expect(destB).toEqual([{ num: 4, gen: 0 }, { name: "Fit" }]);
|
||||||
|
|
||||||
|
const destC = await pdfDoc.getDestination("C");
|
||||||
|
expect(destC).toEqual([{ num: 5, gen: 0 }, { name: "Fit" }]);
|
||||||
|
|
||||||
|
await loadingTask.destroy();
|
||||||
|
});
|
||||||
|
|
||||||
it("gets non-string destination", async function () {
|
it("gets non-string destination", async function () {
|
||||||
let numberPromise = pdfDocument.getDestination(4.3);
|
let numberPromise = pdfDocument.getDestination(4.3);
|
||||||
let booleanPromise = pdfDocument.getDestination(true);
|
let booleanPromise = pdfDocument.getDestination(true);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user