/* * Insert table of contents: * * Create some pages, assign labels to them and insert a table of contents at * the beginning of the document. * * Pages are created in a different chronological order than the order in * which they appear in the document. Using page groups create several pages * and provide them with page labels. After creating the last page, go back * to the start of the document and insert the pages for the table of contents. * * The table of contents is created twice, once using Textlines * and once using Textflows. * * The entries on the table of contents pages can be clicked to jump to * the corresponding page. This is implemented with matchboxes for the titles * and with destinations. * * Required software: PDFlib/PDFlib+PDI/PPS 10 * Required data: none */ package com.pdflib.cookbook.pdflib.pagination; import com.pdflib.pdflib; import java.util.LinkedList; import java.util.List; import com.pdflib.PDFlibException; public class insert_toc { private static class toc_entry { String text; int page; String destination; } public static void main(String argv[]) { /* This is where the data files are. Adjust as necessary. */ String searchpath = "../input"; String outfile = "insert_toc.pdf"; String title = "Insert Table of Contents"; pdflib p = null; int pageno, font, docsize = 0; int exitcode = 0; /* * Using the "groups" option, define several page groups for the title * (title), the table of contents (toc), the individual chapters (body), * and the index (index). List them in the order they will appear in the * document. Using the "labels" option, assign a page label to each page * group. */ String optlist = "groups={title toc content index} " + "labels={{group=title prefix=title} " + "{group=toc prefix={toc } start=1 style=r} " + "{group=content start=1 style=D} " + "{group=index prefix={index } start=1 style=r}} " + "destination={type=fitwindow}"; try { p = new pdflib(); List toc_entries = new LinkedList(); p.set_option("searchpath={" + searchpath + "}"); /* * This means we must check return values of load_font() etc. */ p.set_option("errorpolicy=return"); if (p.begin_document(outfile, optlist) == -1) throw new Exception("Error: " + p.get_errmsg()); p.set_info("Creator", "PDFlib Cookbook"); p.set_info("Title", title); /* Create a page in the page group "title" */ p.begin_page_ext(0, 0, "width=a4.width height=a4.height group title"); docsize += 1; p.fit_textline("Title", 50, 700, "fontname=NotoSerif-Bold fontsize=36"); p.end_page_ext(""); /* Counter for all destinations */ int destno = 0; /* Loop over all pages in the page group "content" */ String destname, headline; for (pageno = 1; pageno <= 5; pageno++) { p.begin_page_ext(0, 0, "width=a4.width height=a4.height group content"); docsize += 1; headline = "Chapter " + pageno; destname = "dest" + destno; p.fit_textline(headline, 50, 700, "fontname=NotoSerif-Bold " + " fontsize=36 matchbox={name=" + destname + "}"); p.end_page_ext(""); add_toc_entry_from_matchbox(p, toc_entries, pageno, headline, destname); destno += 1; } /* Insert two pages in the page group "index" */ p.begin_page_ext(0, 0, "width=a4.width height=a4.height group index"); docsize += 1; headline = "Index I"; destname = "dest" + destno; p.fit_textline(headline, 50, 700, "fontname=NotoSerif-Bold " + " fontsize=36 matchbox={name=" + destname + "}"); add_toc_entry_from_matchbox(p, toc_entries, pageno, headline, destname); destno += 1; pageno += 1; p.end_page_ext(""); p.begin_page_ext(0, 0, "width=a4.width height=a4.height group index"); docsize += 1; headline = "Index II"; destname = "dest" + destno; p.fit_textline(headline, 50, 700, "fontname=NotoSerif-Bold " + " fontsize=36 matchbox={name=" + destname + "}"); add_toc_entry_from_matchbox(p, toc_entries, pageno, headline, destname); destno += 1; pageno += 1; p.end_page_ext(""); int xoff = 50; /* * Insert two pages in the page group "toc" for a table of contents */ p.begin_page_ext(0, 0, "width=a4.width height=a4.height group toc"); docsize += 1; p.fit_textline("Table of Contents I", xoff, 700, "fontname=NotoSerif-Bold fontsize=36"); /* Create table of contents entries with textlines */ int toc_textboxwidth = 400, yoff = 20; String textfontopts = "fontname=NotoSerif-Regular fontsize=14 "; String textopts = textfontopts + " boxsize={" + toc_textboxwidth + " 30} " + "leader={alignment=right}"; String numopts = "fontname=NotoSerif-Bold fontsize=14 "; int y = 660; for (int i = 0; i < toc_entries.size(); i += 1, y -= yoff) { toc_entry entry = toc_entries.get(i); String text_entry_matchbox = "temb" + i; /* Place the text line */ p.fit_textline(entry.text, xoff, y, textopts + " matchbox={name=" + text_entry_matchbox + "}"); String num_entry_matchbox = "nummb" + i; p.fit_textline(Integer.toString(entry.page), xoff + toc_textboxwidth, y, numopts + " matchbox={name=" + num_entry_matchbox + "}"); /* * Create link annotations for both matchboxes */ p.create_annotation(0, 0, 0, 0, "Link", "usematchbox={" + text_entry_matchbox + "} " + "destname={" + entry.destination + "} linewidth=0"); p.create_annotation(0, 0, 0, 0, "Link", "usematchbox={" + num_entry_matchbox + "} " + "destname={" + entry.destination + "} linewidth=0"); } y -= yoff; p.fit_textline("Click on TOC entry to jump to page", xoff, y, textfontopts); p.end_page_ext(""); /* Create table of contents with textflow */ String tf_optlist = "fontname=NotoSerif-Regular fontsize=12 " + "leading=160% ruler=100% " + "hortabmethod=ruler tabalignment=right"; StringBuilder toc_tf_text = new StringBuilder(); /* * Build the text for the whole textflow containing the TOC entries. */ String tf_entry_matchbox_name = "tfentmb"; for (int i = 0; i < toc_entries.size(); i++) { toc_entry entry = toc_entries.get(i); String tf_entry_matchbox = tf_entry_matchbox_name + i; String entry_text = "" + entry.text + "\t" + entry.page + ""; toc_tf_text.append(entry_text); } toc_tf_text.append("Click on TOC entry to jump to page"); int toc_tf = p.create_textflow(toc_tf_text.toString(), tf_optlist); if (toc_tf == -1) throw new Exception("Error: " + p.get_errmsg()); p.begin_page_ext(0, 0, "width=a4.width height=a4.height group toc"); docsize += 1; p.fit_textline("Table of Contents II", xoff, 700, "fontname=NotoSerif-Bold fontsize=36"); p.fit_textline("for a Document of " + docsize + " Pages.", 50, 650, "fontname=NotoSerif-Bold fontsize=24"); /* Error handling and overflow handling omitted here */ p.fit_textflow(toc_tf, xoff, xoff, xoff + toc_textboxwidth, 600, ""); /* Create Link annotations for matchboxes */ for (int i = 0; i < toc_entries.size(); i++) { String tf_entry_matchbox = tf_entry_matchbox_name + i; toc_entry entry = toc_entries.get(i); p.create_annotation(0, 0, 0, 0, "Link", "usematchbox={" + tf_entry_matchbox + "} " + "destname={" + entry.destination + "} linewidth=0"); } p.end_page_ext(""); p.end_document(""); } catch (PDFlibException e) { System.err.println("PDFlib exception occurred:"); System.err.println("[" + e.get_errnum() + "] " + e.get_apiname() + ": " + e.get_errmsg()); exitcode = 1; } catch (Exception e) { System.err.println(e); exitcode = 1; } finally { if (p != null) { p.delete(); } System.exit(exitcode); } } private static void add_toc_entry_from_matchbox(pdflib p, List toc_entries, int pageno, String headline, String matchboxname) throws PDFlibException { /* Retrieve y coordinate of upper edge of matchbox. */ double top = p.info_matchbox(matchboxname, 1, "y4"); p.add_nameddest(matchboxname, "top=" + top); /* Create an entry in the list of TOC entries. */ toc_entry entry = new toc_entry(); entry.text = headline; entry.page = pageno; entry.destination = matchboxname; toc_entries.add(entry); } }