Creating an Automatic Table of Contents

Arina Ostanina
April 20, 2021

In this article, I will show how to create a complex document using the PDFFlow library. We’ll go over the library capabilities and follow a step-by-step process to create a multipage document with an automatic table of contents.

Why use the PDFFlow library?

The PDFFlow library is a .NET C# library that allows developers to generate PDF documents with custom precise designs and layouting fast and efficiently. Some of the special features of the library are:

  • Repeating areas
  • Automatic table of contents
  • Support of Asian languages
  • Multi-page spread tables
  • A rich set of tutorials and examples

Along with the listed features that let you create complicated documents, the library provides a wide range of tools to make elementary documents:

  • Tables of all kinds
  • Images with configurable size and scaling
  • Lines, both vertical and horizontal
  • Multilevel lists

But enough of talking about the features of the library, let’s see them in action by building a complex real-world document with a table of contents.

Creating a multipage document

When creating a multipage document, we often need to generate a table of contents (TOC), and it’s not always trivial. Fortunately, the PDFFlow library takes care of all the heavy lifting and allows us to generate a TOC easily and with very little code. That is one of the key benefits of using the library — simply put, it allows you to write less code to achieve the same results.

To illustrate this, we will use Tutorial C, which is an example of а programming tutorial book. It is a multi-page text document with mixed content. The document includes several sections and a repeating footer with automatic page numeration.

The complete example source is available in the open-source PDFFlow.Examples repo along with many more examples, such as airplane ticket, boarding pass, real-estate contracts, agreements, medical forms, lab reports.

To understand how it works, go through the full document code availiable in the repo and explore our library with this article.

Storing data

We store a part of data for our document in a standard JSON file Content/tutorialc_keywords.json. The file contains descriptions of C keywords. Later we will use this data to build a table.

    "Id": "1",
    "Keyword": "auto",
    "Description": "The auto keyword declares automatic variables"
    "Id": "2",
    "Keyword": "break",
    "Description": "The break statement makes program jump out of the innermost enclosing loop (while, do, for or switch statements) explicitly."

Output file

The code we write builds the document and creates the file TutorialC.pdf in the output bin/(debug|release)/netcoreapp2.1 folder.

Creating a project

1. Create a new console application.

1.1. Run Visual Studio.

1.2. Go to File -> Create -> Console Application (.Net Core).

2. Modify the class Program.

2.1. In the function Main() set the path to the output PDF file, call the Run() method to continue the generation, and call the Build() method for building the document into the output PDF:

namespace TutorialC
    internal class Program
        private static void Main(string[] args)
            Console.WriteLine("C TUTORIAL");
            Console.WriteLine("Press any key for exit...");
        private static void GenerateExample() => TutorialCRunner.Run().Build("TutorialC.pdf");

Sources structure

As our document consists of a few logical parts, we use the following Create methods to generate each of the parts:

  • AddBookCoverSection() — to create the cover section for the tutorial.
  • AddFirstSection() — to create the first section of the tutorial.
  • AddSecondSection() — to create the second section of the tutorial.
  • AddThirdSection() — to create the third section of the tutorial.
  • AddOutlineSection() — to add a table of contents to the tutorial.

Global definitions

Then we define the necessary paths, the required data from the JSON file, and the document font.

ProjectDir = Directory.GetCurrentDirectory();
KeywordsJsonFile = Path.Combine(ProjectDir, "Content", "tutorialc_keywords.json");
KeywordsJsonContent = File.ReadAllText(KeywordsJsonFile);
KeywordsList = JsonConvert.DeserializeObject>(KeywordsJsonContent);
ImageUrl = Path.Combine(ProjectDir, "images", "TutorialC", "customers");
DocumentFont = Fonts.Times(12f);

Code optimization

To add several footers times with different texts, we added a new method. Defining methods for common operations is a good optimization practice to achieve better code size.

    internal static void AddFooters(SectionBuilder section, string text)
        var imageUrlLogo = Path.Combine(ProjectDir, "images", "DocumentExample", "LearnCLogo30_30.jpg");
                    .SetMargins(0, 5, 0, 0).SetFont(DocumentFontBoldOrange)
                        new XSize(15, 15), ScalingMode.UserDefined)
                    .AddUrl("", "GEHTSOFT USA LLC.")
                .AddPageNumberToParagraph(" Page #", 1, SmallFont)

Cover section

As a cover we use an image.

var imageUrl = Path.Combine(ProjectDir, "images", "TutorialC", "DocumentExample", "LearnCCoverPage.jpg");

Then we define a hidden font that will be necessary to include this section in the TOC:

var fontHidden = Fonts.Courier(.01f).SetColor(Color.White);

We use this font in the paragraph that we add to this section and that we mark as a TOC item. As a result, we have a paragraph that is not visible on the cover but is included in the TOC, which allows navigating from the TOC to the cover. After that, we add the cover image to the section.

        .AddParagraph("LEARN C PROGRAMMING")
The resulting cover section

Chapter#1. Environment setup

First, we define the necessary paths to the images: imageUrlLogo, imageUrl, imageExclamationMark, imageQuestionMark.

Then, we create a title that will be included in the TOC.

            .SetBorder(Stroke.Solid, Color.Gray, 3)
            .AddText("1. Environment setup")

After that, we add paragraphs and content to the section. We add inline images to the paragraphs to draw the reader’s attention to the important information.

    .AddInlineImageToParagraph(imageExclamationMark, new XSize(15, 15), ScalingMode.UserDefined)

If you need to skip line breaks in the text, use the ignoreNewLineSymbol parameter:

    .AddText(@" to set up your own environment to start learning C 
programming language. Reason is very simple, we already have set up C 
Programming environment online, so that you can compile and execute all the 
available examples online at the same time when you are doing your theory 
work. This gives you confidence in what you are reading and to check the result 
with different options. Feel free to modify any example and execute it online.",
            ignoreNewLineSymbol: true)

To add a reference to additional resources, add a link:


To accurately convey the text of the program, use @ strings and pass the strings as an array.

        "#include ",
        " ",
        "int main()",
        @"    /* my first program in C */",
        @"    printf(""Hello, World! \n"");",
        @"    return 0;",

Chapter#1. Environment setup.

Chapter#2. Basic syntax

As in the previous section, we start with defining the necessary paths to the images again: imageUrlLogo, imageExclamationMark.

Then we create a title that will be included in the TOC.

    .AddParagraph("2. Basic syntax").SetFont(DocumentFontTitleWhite)
        .SetBorder(Stroke.Solid, Color.Gray, 3)

After that, we add the other paragraphs and content to the section.

To accurately convey the text of the bitwise operators, use strings as an array.

            "A = 0011 1100", "B = 0000 1101", "A&B = 0000 1100", "A|B = 0011 1101", "A^B = 0011 0001",
            "~A = 1100 0011"

We add a footer with the title of the chapter to this section.

    AddFooters(s, “ C tutorial. Chapter #2. Basic syntax. “);
Chapter#2. Basic syntax.

Chapter#3. Decision making

Again, we define the necessary paths to the images: imageUrlLogo, imageUrl.

Then we create a title that will be included in the TOC.

            .AddTextToParagraph("3. Decision making")
            .SetBorder(Stroke.Solid, Color.Gray, 3)

After that, we add the other paragraphs and content to the section.

If you need to skip line breaks in the text, use the ignoreNewLineSymbol parameter:

    .AddTextToParagraph(@"Decision-making structures require that the programmer specifies one or more 
conditions to be evaluated or tested by the program, along with a statement or 
statements to be executed if the condition is determined to be true, and 
optionally, other statements to be executed if the condition is determined to be 
false.", ignoreNewLineSymbol: true)

The fluent style allows us to switch from the paragraph to the section context (ToSection). After that, we add an image.

        .SetBorder(Stroke.Dashed, ColorBackground, 3)

We add the footer with the title of the chapter to the section.

    AddFooters(s, “ C tutorial. Chapter #3. Decision making. “);
Chapter #3. Decision making.

Table of contents

We add a title for the TOC page.

        .SetBorder(Stroke.Solid, Color.Gray, 3)

To add a TOC, just call the AddOutline() method:

           .SetSpacingUnderline(Stroke.Dashed, ColorBackground)

We add a footer with the title of the page to this section:

    AddFooters(s, “ C tutorial. Contents. “); 

In the resulting document, you will get the following TOC:

Final result

We’ve just explored how you can create a complex document with table a of contents using the PDFFlow library. This should be sufficient enough for you to go on your own and create your PDF documents. I hope that now you will be able to create your first document with PDFFlow.

Let me know in the comments if you have any questions or some specific usage you would like me to cover, or just head over to the library’s extensive open-source real-world examples to see more complex documents and detailed articles on how they were created.

We believe that the PDFFlow library is the best and most affordable tool on the market to generate your business docs, whether you need to create а simple invoice, or a set of very complex regulatory documents.
If you are ready to get started or if you have any questions, please don’t hesitate to let us know your needs and learn more about our flat-rate custom development offer.
Arina Ostanina
Junior Developer
As a junior programmer, I have little experience with C# and in programming in general. Having joined the PDFFlow team just recently, I was quite surprised with how simple it is to use this tool to generate PDF documents of significant complexity.
Sign up to receive a monthly email on the latest news!
We will never spam you, transfer or sell your email.
Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.

Previous posts