I've created a document with some Chapter
s.
How to generate a TOC for this document?
It should look like this:
TOC:
Chapter 1 3
Chapter 2 4
Chapter 3 6
Chapter 4 9
Chapter 5 10
This is possible by using PdfTemplate
s. PdfTemplate
s are a kind of placeholder that you can fill afterwards.
Update with the hints from Bruno:
To generate at TOC at the beginning, you need to put some Placeholders for all the page numbers in the TOC. Those PdfTemplate
s you collect in a Map
. Then, when you add the Chapter
s to the document, you can fill those placeholders.
This example shows how:
package com.example.main;
import java.io.FileOutputStream;
import java.util.HashMap;
import java.util.Map;
import com.itextpdf.text.Chapter;
import com.itextpdf.text.Chunk;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Font;
import com.itextpdf.text.FontFactory;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfPageEventHelper;
import com.itextpdf.text.pdf.PdfTemplate;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.text.pdf.draw.VerticalPositionMark;
public class Main extends PdfPageEventHelper {
private final Document document;
private final PdfWriter writer;
private final BaseFont baseFont = BaseFont.createFont();
private final Font chapterFont = FontFactory.getFont(FontFactory.HELVETICA, 24, Font.NORMAL);
// table to store placeholder for all chapters and sections
private final Map<String, PdfTemplate> tocPlaceholder = new HashMap<String, PdfTemplate>();
// store the chapters and sections with their title here.
private final Map<String, Integer> pageByTitle = new HashMap<>();
public static void main(final String[] args) throws Exception {
final Main main = new Main();
main.document.add(new Paragraph("This is an example to generate a TOC."));
main.createTOC(10);
main.createChapters(10);
main.document.close();
}
public Main() throws Exception {
this.document = new Document(PageSize.A6);
this.writer = PdfWriter.getInstance(this.document, new FileOutputStream("test.pdf"));
this.writer.setPageEvent(this);
this.document.open();
}
@Override
public void onChapter(final PdfWriter writer, final Document document, final float paragraphPosition, final Paragraph title) {
this.pageByTitle.put(title.getContent(), writer.getPageNumber());
}
@Override
public void onSection(final PdfWriter writer, final Document document, final float paragraphPosition, final int depth, final Paragraph title) {
this.pageByTitle.put(title.getContent(), writer.getPageNumber());
}
private void createTOC(final int count) throws DocumentException {
// add a small introduction chapter the shouldn't be counted.
final Chapter intro = new Chapter(new Paragraph("This is TOC ", this.chapterFont), 0);
intro.setNumberDepth(0);
this.document.add(intro);
for (int i = 1; i < count + 1; i++) {
// Write "Chapter i"
final String title = "Chapter " + i;
final Chunk chunk = new Chunk(title).setLocalGoto(title);
this.document.add(new Paragraph(chunk));
// Add a placeholder for the page reference
this.document.add(new VerticalPositionMark() {
@Override
public void draw(final PdfContentByte canvas, final float llx, final float lly, final float urx, final float ury, final float y) {
final PdfTemplate createTemplate = canvas.createTemplate(50, 50);
Main.this.tocPlaceholder.put(title, createTemplate);
canvas.addTemplate(createTemplate, urx - 50, y);
}
});
}
}
private void createChapters(final int count) throws DocumentException {
for (int i = 1; i < count + 1; i++) {
// append the chapter
final String title = "Chapter " + i;
final Chunk chunk = new Chunk(title, this.chapterFont).setLocalDestination(title);
final Chapter chapter = new Chapter(new Paragraph(chunk), i);
chapter.setNumberDepth(0);
chapter.addSection("Foobar1");
chapter.addSection("Foobar2");
this.document.add(chapter);
// When we wrote the chapter, we now the pagenumber
final PdfTemplate template = this.tocPlaceholder.get(title);
template.beginText();
template.setFontAndSize(this.baseFont, 12);
template.setTextMatrix(50 - this.baseFont.getWidthPoint(String.valueOf(this.writer.getPageNumber()), 12), 0);
template.showText(String.valueOf(this.writer.getPageNumber()));
template.endText();
}
}
}
The generated PDF looks like this: TableOfContents.pdf
The answer by Christian Schneider seems somewhat complex. I would also use page event, but I would use the onChapter()
method to create a list of chapter titles and page numbers. If you also need Section
titles, use the onSection()
method to keep track of the sections too.
Once you have this list, create the TOC at the end of the document. If you want to move the TOC to the front, read my answer to this question: PDF Page re-ordering using itext
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With