PDF bookmarks (outlines) serve as essantial navigation elements within documents, particularly for lengthy technical manuals. Extracting bookmark metadata enables applications to generate table of contents, build indexes, or perform structural analysis on documents. This guide demonstrates how to leverage the Free Spire.PDF for .NET library to read all bookmarks—including nested multi-level structures—and export title and display style information to a text file.
Environment Setup
Installing the Free Library
Install the Free Spire.PDF package via NuGet Package Manager in Visual Studio:
Install-Package FreeSpire.PDF
The free edition supports fundamental operations like reading PDF bookmarks without requiring additional license files, though it has a 10-page limit per document.
Required Namespace Imports
Include the following namespaces in your code:
using System;
using System.IO;
using System.Text;
using Spire.Pdf;
using Spire.Pdf.Bookmarks;
Core Implementation
The implementation follows a four-step approach:
- Load the target PDF document.
- Access the
PdfBookmarkCollectionfrom the document. - Recursively traverse each bookmark and its children to extract titles and display styles.
- Write the extracted data to a text file.
Loading Document and Accessing Bookmarks
PdfDocument pdf = new PdfDocument();
pdf.LoadFromFile(@"D:\test.pdf");
PdfBookmarkCollection bookmarks = pdf.Bookmarks;
The Bookmarks property returns a collection containing top-level bookmarks. If the document contains no bookmarks, the Count property returns 0.
Recursive Bookmark Traversal
Bookmark structures follow a tree hierarchy: each bookmark node may contain child bookmarks accessible via the Count property and indexer. The solution implements two methods:
ExtractBookmarks: Processes top-level bookmarks, initializes aStringBuilder, and initiates recursion.ProcessChildBookmarks: Recursively handles child bookmarks.
public static void ExtractBookmarks(PdfBookmarkCollection bookmarks, string outputPath)
{
StringBuilder builder = new StringBuilder();
if (bookmarks.Count > 0)
{
builder.AppendLine("PDF Bookmarks:");
foreach (PdfBookmark rootItem in bookmarks)
{
builder.AppendLine(rootItem.Title);
builder.AppendLine(rootItem.DisplayStyle.ToString());
ProcessChildBookmarks(rootItem, builder);
}
}
File.WriteAllText(outputPath, builder.ToString());
}
Recursive method:
public static void ProcessChildBookmarks(PdfBookmark parentItem, StringBuilder builder)
{
if (parentItem.Count > 0)
{
foreach (PdfBookmark childItem in parentItem)
{
builder.AppendLine(childItem.Title);
builder.AppendLine(childItem.DisplayStyle.ToString());
ProcessChildBookmarks(childItem, builder);
}
}
}
Complete Code Example
The following console application implementation exports bookmark information to BookmarkOutput.txt:
using System;
using System.IO;
using System.Text;
using Spire.Pdf;
using Spire.Pdf.Bookmarks;
namespace BookmarkExporter
{
internal class Program
{
static void Main(string[] args)
{
PdfDocument pdf = new PdfDocument();
pdf.LoadFromFile(@"D:\testp\test.pdf");
PdfBookmarkCollection bookmarks = pdf.Bookmarks;
string outputFile = "BookmarkOutput.txt";
ExtractBookmarks(bookmarks, outputFile);
Console.WriteLine("Bookmark extraction completed. Output saved to: " + outputFile);
}
public static void ExtractBookmarks(PdfBookmarkCollection bookmarks, string outputPath)
{
StringBuilder builder = new StringBuilder();
if (bookmarks.Count > 0)
{
builder.AppendLine("PDF Bookmarks:");
foreach (PdfBookmark rootItem in bookmarks)
{
builder.AppendLine(rootItem.Title);
builder.AppendLine(rootItem.DisplayStyle.ToString());
ProcessChildBookmarks(rootItem, builder);
}
}
else
{
builder.AppendLine("This PDF document contains no bookmarks.");
}
File.WriteAllText(outputPath, builder.ToString());
}
public static void ProcessChildBookmarks(PdfBookmark parentItem, StringBuilder builder)
{
if (parentItem.Count > 0)
{
foreach (PdfBookmark childItem in parentItem)
{
builder.AppendLine(childItem.Title);
builder.AppendLine(childItem.DisplayStyle.ToString());
ProcessChildBookmarks(childItem, builder);
}
}
}
}
}
Output Format
The generated text file uses a two-line format per bookmark: the first line contains the title, and the second line contains the display style. For example:
PDF Bookmarks:
Chapter 1 Introduction
Regular
1.1 Background
Bold
1.2 Objectives
Italic
Chapter 2 Implementation
Regular
2.1 Environment Setup
Regular
DisplayStyle is an enum with the following possible values:
Regular: Normal textBold: Bold textItalic: Italic text
The output varies according to the actual bookmark styles in the PDF file.
Important Notes and Extensions
Empty Bookmark Handling
If the PDF contains no bookmarks, bookmarks.Count equals 0, and the code writes a notification message to prevent generating an empty file.
Retrieving Target Pages and Actions
The examples above extract only titles and styles. To obtain the target page a bookmark links to, use the PdfBookmark.Action property (action type checking required):
if (parentItem.Action is PdfGoToAction gotoAction)
{
int pageIndex = pdf.Pages.IndexOf(gotoAction.Destination.Page);
builder.AppendLine($"Navigate to page {pageIndex + 1}");
}
Since Free Spire.PDF provides comprehensive Action support, this can be extended based on specific requirements.
Performance Considerations
Recursive traversal poses no significant performance issues for PDFs containing thousands of bookmarks. However, for frequent extraction scenarios, consider replacing StringBuilder with StreamWriter for streaming writes to reduce memory consumption.
Encoding Handling
File.WriteAllText uses UTF-8 encoding by default. To specify a different encoding (such as GB2312), use StreamWriter instead.
Key Technical Points
The approach demonstrates complete extraction of multi-level bookmark information from PDF documents using a free .NET library. Core technical aspects include:
- Accessing the root bookamrk collection via
PdfDocument.Bookmarks - Recursively traversing
PdfBookmarknodes using theCountproperty and indexer - Reading
TitleandDisplayStyleproperties - Writing structured data to text files
This method integrates seamlessly into backend services or document processing pipelines without depending on Adobe Acrobat or other GUI tools.