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 PHP Code  Switch to Java Code  Show Output 

<?php
/*
 * 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
 */
class toc_entry {
    function __construct($text, $page, $destination) {
        $this->text = $text;
        $this->page = $page;
        $this->destination = $destination;
    }
}

/* This is where the data files are. Adjust as necessary. */
$searchpath = dirname(__FILE__,3)."/input";
$title = "Insert Table of Contents";

$docsize = 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.
 */
$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();
    
    $toc_entries = array();
    
    $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("", $optlist) == 0)
        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 */
    $destno = 0;
    
    /* Loop over all pages in the page group "content" */
    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("");
    
    $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 */
    $toc_textboxwidth = 400;
    $yoff = 20;
    
    $textfontopts = "fontname=NotoSerif-Regular fontsize=14";
    $textopts = $textfontopts . " boxsize={" . $toc_textboxwidth . " 30} " .
                     "leader={alignment=right}";
    $numopts = "fontname=NotoSerif-Bold fontsize=14";
    
    $y = 660;
    for($i = 0; $i < count($toc_entries); $i += 1, $y -= $yoff) {
        
        $entry = $toc_entries[$i];
        $text_entry_matchbox = "temb" . $i;
        
        /* Place the text line */
        $p->fit_textline($entry->text, $xoff, $y, 
                        $textopts . " matchbox={name=" . $text_entry_matchbox .
                                         "}");
        
        $num_entry_matchbox = "nummb" . $i;
        $p->fit_textline($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 */
    $tf_optlist = "fontname=NotoSerif-Regular fontsize=12 " .
                     "leading=160% ruler=100% " .
                     "hortabmethod=ruler tabalignment=right";
    $toc_tf_text = "";
    
    /*
     * Build the text for the whole textflow containing the TOC entries.
     */
    $tf_entry_matchbox_name = "tfentmb";
    for($i = 0; $i < count($toc_entries); $i++) {
        
        $entry = $toc_entries[$i];
        
        $tf_entry_matchbox = $tf_entry_matchbox_name . $i;
        
        $entry_text = "<alignment=left><matchbox={name=" . $tf_entry_matchbox .
                         "}>" . $entry->text . "<leader={alignment={grid}}>\t" .
                         $entry->page . "<matchbox=end><nextline>";
        $toc_tf_text .= $entry_text;
    }
    
    $toc_tf_text .= "<nextline>Click on TOC entry to jump to page";
    
    $toc_tf = $p->create_textflow($toc_tf_text, $tf_optlist);
    if ($toc_tf == 0)
        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($i = 0; $i < count($toc_entries); $i++) {
        $tf_entry_matchbox = $tf_entry_matchbox_name . $i;
        $entry = $toc_entries[$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("");
    $buf = $p->get_buffer();
    $len = strlen($buf);
    
    header("Content-type: application/pdf");
    header("Content-Length: $len");
    header("Content-Disposition: inline; filename=insert_toc.pdf");
    print $buf;
}
catch (PDFlibException $e) {
    echo("PDFlib exception occurred:\n" . "[" . $e->get_errnum() . "] " .
                     $e->get_apiname() . ": " . $e->get_errmsg() . "\n");
    exit(1);
}
catch (Throwable $e) {
    echo("PHP exception occurred: " . $e->getMessage() . "\n");
    exit(1);
}
$p = 0;

function add_toc_entry_from_matchbox($p, &$toc_entries, $pageno, $headline, 
                $matchboxname) {
    /* Retrieve y coordinate of upper edge of matchbox. */
    $top = $p->info_matchbox($matchboxname, 1, "y4");
    $p->add_nameddest($matchboxname, "top=" . $top);
    
    /* Create an entry in the list of TOC entries. */
    array_push($toc_entries, new toc_entry($headline, $pageno, $matchboxname));
}
?>