Reading and Exporting PDF Bookmarks with C#

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:

  1. Load the target PDF document.
  2. Access the PdfBookmarkCollection from the document.
  3. Recursively traverse each bookmark and its children to extract titles and display styles.
  4. 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 a StringBuilder, 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 text
  • Bold: Bold text
  • Italic: 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 PdfBookmark nodes using the Count property and indexer
  • Reading Title and DisplayStyle properties
  • 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.

Tags: C# PDF Bookmarks Spire.PDF Document Processing

Posted on Fri, 28 Aug 2026 16:29:38 +0000 by Secondlaw