Naomiss
Naomiss

Reputation: 165

Create PDF Table of Contents with links to chapter of text

I create PDF document ant I have go problem with links to chapter of text. I use code of Bruno Lowagie from here, but it's Java and I have got some difficulties.

I'm doing like this:

class TOCEvents

public class TOCEvents : PdfPageEventHelper
{

    //protected System.Collections.Generic.List<TitleTOC> toc = new System.Collections.Generic.List<TitleTOC>();
    protected Dictionary<string, int> toc = new Dictionary<string, int>(5);

    public override void OnGenericTag(PdfWriter writer, Document document, Rectangle rect, String text)
    {
        toc.Add(text, writer.PageNumber);
    }

    public Dictionary<string, int> GetTOC()
    {
        return toc;
    }

}

main

                    for (int i = 0; i < 10; i++)
                {
                    String title = "This is title " + i;
                    Chunk c = new Chunk(title, f14);
                    c.SetGenericTag(title);
                    doc.Add(new Paragraph(c));
                    for (int j = 0; j < 50; j++)
                    {
                        doc.Add(new Paragraph("Line " + j + " of title " + i));
                    }
                }
                doc.NewPage();

                doc.Add(new Paragraph("Table of Contents", f24));

                Chunk dottedLine = new Chunk(new iTextSharp.text.pdf.draw.DottedLineSeparator());
                Dictionary<string, int> entries = ev.GetTOC();
                Paragraph p;

                foreach (KeyValuePair<string, int> entry in entries)
                {
                    Chunk chunk = new Chunk(entry.Key);
                    chunk.SetAction(PdfAction.GotoLocalPage(entry.Key, false));

                    p = new Paragraph(chunk);
                    p.Add(dottedLine);

                    chunk = new Chunk(entry.Value.ToString());
                    chunk.SetAction(PdfAction.GotoLocalPage(entry.Key, false));

                    p.Add(chunk);

                    doc.Add(p);


                }

I have got problems whith this:

foreach (KeyValuePair<string, int> entry in entries)
                {
                    Chunk chunk = new Chunk(entry.Key);
                    chunk.SetAction(PdfAction.GotoLocalPage(entry.Key, false));

                    p = new Paragraph(chunk);
                    p.Add(dottedLine);

                    chunk = new Chunk(entry.Value.ToString());
                    chunk.SetAction(PdfAction.GotoLocalPage(entry.Key, false));

                    p.Add(chunk);

                    doc.Add(p);


                }

What am I doing wrong? I can't set links to chapters of text. I think, that i'm using wrong Dictionary<string, int>. Where did i mistakes?

Thank you.

Upvotes: 1

Views: 3270

Answers (1)

Bruno Lowagie
Bruno Lowagie

Reputation: 77528

You are creating a TOC like this:

| key       | page number |
|-----------|-------------|
| Chapter 1 |    1        |
| Chapter 2 |    5        |
| Chapter 3 |    7        |
| Chapter 4 |    9        |
| Chapter 5 |   10        |

You render this information like this:

Chapter 1 ................... 1
Chapter 2 ................... 5
Chapter 3 ................... 7
Chapter 4 ................... 9
Chapter 5 .................. 10

You do this in such a way that, when you click a title in the TOC, or a page number, you trigger a link to a named destination with name Chapter X where X is a number from 1 to 5.

Nothing happens when you click that link, and nothing should happen, because you haven't defined any destination with names Chapter X anywhere.

You have copied code that I wrote for you in Java, more specifically the CreateTOC2 example. I wrote this example based on an example that was written in answer to your previous question How to create Table Of Contents in iTextSharp

However, you overlooked the fact that the TOCEvent changed:

public class TOCEvent extends PdfPageEventHelper {

    protected int counter = 0;
    protected List<SimpleEntry<String, SimpleEntry<String, Integer>>> toc = new ArrayList<>();

    @Override
    public void onGenericTag(PdfWriter writer, Document document, Rectangle rect, String text) {
        String name = "dest" + (counter++);
        int page = writer.getPageNumber();
        toc.add(new SimpleEntry<String, SimpleEntry<String, Integer>>(text, new SimpleEntry<String, Integer>(name, page)));
        writer.addNamedDestination(name, page, new PdfDestination(PdfDestination.FITH, rect.getTop()));
    }

    public List<SimpleEntry<String, SimpleEntry<String, Integer>>> getTOC() {
        return toc;
    }
}

In this new TOCEvent, we keep track of a counter. Each time, a title is encountered, a new (unique!) name is created and the counter goes up.

 String name = "dest" + (counter++);

With this name, you have to create a named destination. In this case, we create a /FitH (fit horizontally) destination, at a specific Y position:

writer.addNamedDestination(
    name,  // the unique name
    page,  // the current page number where the title is added
    new PdfDestination(        // the destination on that page
        PdfDestination.FITH, rect.getTop()));

You do not add any such destinations, hence you can't link to any named destination in the document.

In my example, I pass the unique name to the TOC:

| key       | named destination | page number |
|-----------|-------------------|-------------|
| Chapter 1 |    dest0          |    1        |
| Chapter 2 |    dest1          |    5        |
| Chapter 3 |    dest2          |    7        |
| Chapter 4 |    dest3          |    9        |
| Chapter 5 |    dest4          |   10        |

When I create the TOC, I use these names, dest0, dest1,... to create actions like this:

PdfAction.gotoLocalPage("dest0", false)
PdfAction.gotoLocalPage("dest1", false)
PdfAction.gotoLocalPage("dest2", false)
PdfAction.gotoLocalPage("dest3", false)
PdfAction.gotoLocalPage("dest4", false)

You use the wrong values, you create links like this:

PdfAction.gotoLocalPage("Chapter 1", false)
PdfAction.gotoLocalPage("Chapter 2", false)
PdfAction.gotoLocalPage("Chapter 3", false)
PdfAction.gotoLocalPage("Chapter 4", false)
PdfAction.gotoLocalPage("Chapter 5", false)

That can never work, unless you use Chapter 1, Chapter 2,... as names for your named destinations. As you can't be sure those names will always be unique, I think that my approach is the better choice.

The answer to your question What am I doing wrong? is simple: you are creating links, but you forgot to create the destinations.

Upvotes: 3

Related Questions