mirror of
https://github.com/UglyToad/PdfPig.git
synced 2025-08-20 04:31:25 +08:00
add container node support for BookmarksProvider.cs (#1133)
* add container node support for BookmarksProvider.cs * move position * fixed unittest error * revert package name * remove duplicated package info.
This commit is contained in:
parent
a43b968ea9
commit
3650e27432
@ -32,4 +32,18 @@ public class AccentedCharactersInBookmarksTests
|
|||||||
},
|
},
|
||||||
nodes);
|
nodes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void CanReadContainerBookmarksCorrectly()
|
||||||
|
{
|
||||||
|
var path = IntegrationHelpers.GetDocumentPath("dotnet-ai.pdf");
|
||||||
|
|
||||||
|
using var document = PdfDocument.Open(path);
|
||||||
|
var isFound = document.TryGetBookmarks(out var bookmarks, false);
|
||||||
|
Assert.True(isFound);
|
||||||
|
Assert.True(bookmarks.Roots.Count == 3);
|
||||||
|
isFound = document.TryGetBookmarks(out bookmarks, true);
|
||||||
|
Assert.True(isFound);
|
||||||
|
Assert.True(bookmarks.Roots.Count > 3);
|
||||||
|
}
|
||||||
}
|
}
|
BIN
src/UglyToad.PdfPig.Tests/Integration/Documents/dotnet-ai.pdf
Normal file
BIN
src/UglyToad.PdfPig.Tests/Integration/Documents/dotnet-ai.pdf
Normal file
Binary file not shown.
@ -260,6 +260,7 @@
|
|||||||
"UglyToad.PdfPig.Outline.DocumentBookmarkNode",
|
"UglyToad.PdfPig.Outline.DocumentBookmarkNode",
|
||||||
"UglyToad.PdfPig.Outline.EmbeddedBookmarkNode",
|
"UglyToad.PdfPig.Outline.EmbeddedBookmarkNode",
|
||||||
"UglyToad.PdfPig.Outline.ExternalBookmarkNode",
|
"UglyToad.PdfPig.Outline.ExternalBookmarkNode",
|
||||||
|
"UglyToad.PdfPig.Outline.ContainerBookmarkNode",
|
||||||
"UglyToad.PdfPig.Outline.UriBookmarkNode",
|
"UglyToad.PdfPig.Outline.UriBookmarkNode",
|
||||||
"UglyToad.PdfPig.Outline.Destinations.ExplicitDestination",
|
"UglyToad.PdfPig.Outline.Destinations.ExplicitDestination",
|
||||||
"UglyToad.PdfPig.Outline.Destinations.ExplicitDestinationCoordinates",
|
"UglyToad.PdfPig.Outline.Destinations.ExplicitDestinationCoordinates",
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Extract bookmarks, if any.
|
/// Extract bookmarks, if any.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Bookmarks? GetBookmarks(Catalog catalog)
|
public Bookmarks? GetBookmarks(Catalog catalog,bool allowContainerNode = false)
|
||||||
{
|
{
|
||||||
if (!catalog.CatalogDictionary.TryGet(NameToken.Outlines, pdfScanner, out DictionaryToken? outlinesDictionary))
|
if (!catalog.CatalogDictionary.TryGet(NameToken.Outlines, pdfScanner, out DictionaryToken? outlinesDictionary))
|
||||||
{
|
{
|
||||||
@ -47,7 +47,7 @@
|
|||||||
|
|
||||||
while (next != null)
|
while (next != null)
|
||||||
{
|
{
|
||||||
ReadBookmarksRecursively(next, 0, false, seen, catalog.NamedDestinations, roots);
|
ReadBookmarksRecursively(next, 0, false, seen, catalog.NamedDestinations, roots, allowContainerNode);
|
||||||
|
|
||||||
if (!next.TryGet(NameToken.Next, out IndirectReferenceToken nextReference)
|
if (!next.TryGet(NameToken.Next, out IndirectReferenceToken nextReference)
|
||||||
|| !seen.Add(nextReference.Data))
|
|| !seen.Add(nextReference.Data))
|
||||||
@ -65,8 +65,7 @@
|
|||||||
/// Extract bookmarks recursively.
|
/// Extract bookmarks recursively.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void ReadBookmarksRecursively(DictionaryToken nodeDictionary, int level, bool readSiblings, HashSet<IndirectReference> seen,
|
private void ReadBookmarksRecursively(DictionaryToken nodeDictionary, int level, bool readSiblings, HashSet<IndirectReference> seen,
|
||||||
NamedDestinations namedDestinations,
|
NamedDestinations namedDestinations, List<BookmarkNode> list, bool allowContainerNode = false)
|
||||||
List<BookmarkNode> list)
|
|
||||||
{
|
{
|
||||||
// 12.3 Document-Level Navigation
|
// 12.3 Document-Level Navigation
|
||||||
|
|
||||||
@ -80,7 +79,7 @@
|
|||||||
var children = new List<BookmarkNode>();
|
var children = new List<BookmarkNode>();
|
||||||
if (nodeDictionary.TryGet(NameToken.First, pdfScanner, out DictionaryToken? firstChild))
|
if (nodeDictionary.TryGet(NameToken.First, pdfScanner, out DictionaryToken? firstChild))
|
||||||
{
|
{
|
||||||
ReadBookmarksRecursively(firstChild, level + 1, true, seen, namedDestinations, children);
|
ReadBookmarksRecursively(firstChild, level + 1, true, seen, namedDestinations, children, allowContainerNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
BookmarkNode bookmark;
|
BookmarkNode bookmark;
|
||||||
@ -108,6 +107,11 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if(allowContainerNode)
|
||||||
|
{
|
||||||
|
bookmark = new ContainerBookmarkNode(title, level, children);
|
||||||
|
log.Warn($"No /Dest(ination) or /A(ction) entry found for bookmark node: {nodeDictionary}.");
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
log.Error($"No /Dest(ination) or /A(ction) entry found for bookmark node: {nodeDictionary}.");
|
log.Error($"No /Dest(ination) or /A(ction) entry found for bookmark node: {nodeDictionary}.");
|
||||||
@ -138,7 +142,7 @@
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReadBookmarksRecursively(current, level, false, seen, namedDestinations, list);
|
ReadBookmarksRecursively(current, level, false, seen, namedDestinations, list, allowContainerNode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
16
src/UglyToad.PdfPig/Outline/ContainerBookmarkNode.cs
Normal file
16
src/UglyToad.PdfPig/Outline/ContainerBookmarkNode.cs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
namespace UglyToad.PdfPig.Outline;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// represents a pure container bookmark node: it has a title and child nodes but no destination or action.
|
||||||
|
/// <para>This is used to handle the common "grouping" bookmarks in PDFs.</para>
|
||||||
|
/// </summary>
|
||||||
|
public class ContainerBookmarkNode : BookmarkNode
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// create a container bookmark node.
|
||||||
|
/// </summary>
|
||||||
|
public ContainerBookmarkNode(string title, int level, IReadOnlyList<BookmarkNode> children)
|
||||||
|
: base(title, level, children)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
@ -255,14 +255,14 @@
|
|||||||
/// Gets the bookmarks if this document contains some.
|
/// Gets the bookmarks if this document contains some.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>This will throw a <see cref="ObjectDisposedException"/> if called on a disposed <see cref="PdfDocument"/>.</remarks>
|
/// <remarks>This will throw a <see cref="ObjectDisposedException"/> if called on a disposed <see cref="PdfDocument"/>.</remarks>
|
||||||
public bool TryGetBookmarks([NotNullWhen(true)] out Bookmarks? bookmarks)
|
public bool TryGetBookmarks([NotNullWhen(true)] out Bookmarks? bookmarks, bool allowContainerNode = false)
|
||||||
{
|
{
|
||||||
if (isDisposed)
|
if (isDisposed)
|
||||||
{
|
{
|
||||||
throw new ObjectDisposedException("Cannot access the bookmarks after the document is disposed.");
|
throw new ObjectDisposedException("Cannot access the bookmarks after the document is disposed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
bookmarks = bookmarksProvider.GetBookmarks(Structure.Catalog);
|
bookmarks = bookmarksProvider.GetBookmarks(Structure.Catalog, allowContainerNode);
|
||||||
|
|
||||||
return bookmarks != null;
|
return bookmarks != null;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user