PDFlib Cookbook

cookbook

pagination/insert_toc

Create some pages, assign labels to them and insert a table of contents at the beginning of the document.

Download Java Code  Switch to PHP Code  Show Output 

/*
 * 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_entry> toc_entries = new LinkedList<toc_entry>();

            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 = "<alignment=left><matchbox={name="
                        + tf_entry_matchbox + "}>" + entry.text
                        + "<leader={alignment={grid}}>\t" + entry.page
                        + "<matchbox=end><nextline>";
                toc_tf_text.append(entry_text);
            }
            
            toc_tf_text.append("<nextline>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_entry> 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);
    }
}