BASKET
Search
PDFlib

text_output/create_interactive_index

Download Java Code      Switch to PHP Code      Show Output PDF

/* $Id: create_interactive_index.java,v 1.6 2013/02/26 11:10:24 stm Exp $

 * Create interactive index:

 * In a Textflow define some terms to be indexed and create a sorted index from

 * the indexed terms

 *

 * For indicating an indexed term in a Textflow use the inline options

 * "matchbox" and "matchbox end" to create a matchbox at the position to which

 * the index entry will refer to. The matchbox name will be similar to the

 * indexed term. Place the Textflow. Then, create the index by collecting all

 * matchboxes. Each index entry will consist of the matchbox name (indexed term)

 * and the respective page number. Provide the page number with a link

 * annotation to jump to the respective page. Matchboxes are used here a

 * second time to indicate the active link area on the page number.

 *

 * Note that compiling this code with JDK 1.5 will result in a compiler warning

 * "... uses unchecked or unsafe operations ...". The reason is that we prefer

 * JDK 1.4 compatible code over the use of JDK 1.5 generics.

 *

 * Required software: PDFlib/PDFlib+PDI/PPS 9

 * Required data: none

 */

package com.pdflib.cookbook.pdflib.text_output;


import java.util.Arrays;

import java.util.LinkedList;

import java.util.List;


import com.pdflib.pdflib;

import com.pdflib.PDFlibException;


public class create_interactive_index

{

    public static void main (String argv[])

    {

    pdflib p = null;

    String searchpath = "../input";

    String outfile = "create_interactive_index.pdf";

    String title = "Create Interactive Index";

   

    final double llx = 20, lly = 20, urx = 200, ury = 200;

    final int pagewidth = 250, pageheight = 230;

   

    int i, pageno, entryno, tf = -1, idx = -1;

    String mname, result;

    double mcount, minfo;

     

   

    /* Option list to indicate the start of a matchbox */

    String startopts = "";

   

    /* Option list to indicate the end of a matchbox */

    final String endopts = "matchbox=end";

   

    /* Standard option list for adding a Textflow.

     * "avoidemptybegin" deletes empty lines at the beginning of a fitbox.

     * "charref" enables the substitution of numeric and character entity

     * or glyph name references, e.g. of the character reference "­"

     * for a soft hyphen.

     */

    final String stdopts = "fontname=Helvetica fontsize=12 encoding=unicode " +

        "leading=120% charref avoidemptybegin ";

       

    int ntexts = 10;

     

    /* The text array contains pairs of strings. Each first string will be used

     * as indexed term, i.e. the text of an index marker.

     */

    String texts[] =

    {

        "Long Distance Glider",

        "\nWith this paper rocket you can send all your messages even when " +

        "sitting in a hall or in the cinema pretty near the back.\n\n",

       

        "Giant Wing",

        "\nAn unbelievable sailplane! It is amazingly robust and can even " +

        "do aerobatics. But it best suited to gliding.\n\n",

       

        "Cone Head Rocket",

        "\nThis paper arrow can be thrown with big swing. We launched it " +

        "from the roof of a hotel. It stayed in the air a long time and " +

        "covered a considerable distance.\n\n",

       

        "Super Dart",

        "\nThe super dart can fly giant loops with a radius of 4 or 5 " +

        "metres and cover very long distances. Its heavy cone point is " +

        "slightly bowed upwards to get the lift required for loops.\n\n",

       

        "German Bi-Plane",

        "\nBrand-new and ready for take-off. If you have lessons in the " +

        "history of aviation you can show your interest by letting it " +

        "land on your teacher's desk.\n\n",

    };

   

    /* Index entry containing a name and a page number. For sorting the index

     * entries a compare method is provided.

     */

    class IndexEntry implements Comparable<IndexEntry> {

        String name;

        int page;

        public int compareTo(IndexEntry other) {

            return name.compareTo(other.name);

        }

    };

   

    /*

     * List of all index entries

     */

    List<IndexEntry> index = new LinkedList<IndexEntry>();

   

    try {

        p = new pdflib();


        p.set_option("searchpath={" + searchpath + "}");


        /* This means we must check return values of load_font() etc. */

        p.set_option("errorpolicy=return");

     

        /* Start the output document */

        if (p.begin_document(outfile, "") == -1)

            throw new Exception("Error: " + p.get_errmsg());


        p.set_info("Creator", "PDFlib Cookbook");

        p.set_info("Title", title + " $Revision: 1.6 $");

       

       

        /* ----------------------------------------------------------------

         * Add the text Textflow and define a matchbox on each indexed term

         * ----------------------------------------------------------------

         */

       

        /* Supply the standard options to the Textflow. This has to be done

         * only once. Further calls of add_textflow() for this Textflow will use

         * these settings by default.

         */

        tf = p.add_textflow(-1, "", stdopts);

        if (tf == -1)

            throw new Exception("Error: " + p.get_errmsg());

       

        /* Loop over all texts. Add each text and define a matchbox on each

         * indexed term. The matchbox name is set to the indexed term.

         */

        for (i = 0; i < ntexts; i+=2) {

            /* Add text and start a matchbox indicating an indexed term.

             * Colorize the matchbox rectangle (only for illustration purposes)

             */

            startopts = "matchbox={name={" + texts[i] + "} " +

                "fillcolor={rgb 0 0.95 0.95}}";

       

            tf = p.add_textflow(tf, texts[i], startopts);

            if (tf == -1)

                throw new Exception("Error: " + p.get_errmsg());

           

            /* Add text and finish the matchbox */

            tf = p.add_textflow(tf, texts[i+1], endopts);

            if (tf == -1)

                throw new Exception("Error: " + p.get_errmsg());

        }

       

       

        /* --------------------------------------------------------------------

         * Place the text and retrieve all matchboxes (indexed terms) to create

         * the index entries from

         * --------------------------------------------------------------------

         */

           

        /* Initialize the current page number to be output in the index */

        pageno = 0;

       

        /* Initialize the number of index entries */

        entryno = 0;

       

        /* Loop until all of the text is placed; create new pages as long as

         * more text needs to be placed.

         */

        do

        {

            p.begin_page_ext(pagewidth, pageheight, "");

            pageno++;


            /* Place the text */

            result = p.fit_textflow(tf, llx, lly, urx, ury, "");

           

            /* Place a page number at the lower right corner of the page */

            p.fit_textline(String.valueOf(pageno), pagewidth - 20, 10,

                "fontname=Helvetica encoding=unicode fontsize=12 " +

                "fillcolor={rgb 0 0.95 0.95}");

           

            /* Create the index by creating an index entry from each matchbox on

             * the page. Create an index entry by retrieving the matchbox name

             * as well as the current page number.

             *

             * (In our solution multiple index entries may refer to the same

             * indexed term. An indexer for general use would combine entries

             * for the same term into a single index entry with multiple

             * page numbers. Implement this by creating a chain of multiple

             * matchboxes for each indexed term.)

             */

           

            /* Query the number of matchboxes on the page; the "num" parameter

             * is set to 0 and will be ignored

             */

            mcount = p.info_matchbox("*", 0, "count");

           

            for (i = 1; i <= mcount; i++)

            {

                /* Get the matchbox name */

                minfo = p.info_matchbox("*", i, "name");

           

                mname = p.get_string((int) minfo, "");

               

                /* Retrieve the name of the matchbox to be used as the indexed

                 * term and the page number to be used as the page number in the

                 * index entry

                 */

                IndexEntry newEntry = new IndexEntry();

                newEntry.name = new String(mname);

                newEntry.page = pageno;

                index.add(newEntry);

                             

                entryno++;

            }

             

            p.end_page_ext("");


            /* "_boxfull" means we must continue because there is more text;

             * "_nextpage" is interpreted as "start new column"

             */

        } while (result.equals("_boxfull") || result.equals("_nextpage"));


        /* Check for errors */

        if (!result.equals("_stop"))

        {

            /* "_boxempty" happens if the box is very small and doesn't

             * hold any text at all.

             */

            if (result.equals( "_boxempty"))

                throw new Exception ("Error: Textflow box too small");

            else

            {

                /* Any other return value is a user exit caused by

                 * the "return" option; this requires dedicated code to

                 * deal with.

                 */

                throw new Exception ("User return '" + result +

                    "' found in Textflow");

            }

        }


        p.delete_textflow(tf);

       

 

        /* -------------------------------------------------------------

         * Sort the list of index entries. Convert it to an array first.

         * -------------------------------------------------------------

         */

        IndexEntry sortedIndex[] = new IndexEntry[index.size()];

        sortedIndex = index.toArray(sortedIndex);

        Arrays.sort(sortedIndex);

       

       

        /* ---------------------------------------------------------------------

         * Construct the contents of the index page(s) based on the collected

         * pairs containing the indexed term plus the corresponding page number

         * ---------------------------------------------------------------------

         */

        /* Supply the standard options to the index Textflow. This has to be

         * done only once for each Textflow. Further calls of add_textflow() for

         * this Textflow will use these settings by default.

         */

        idx = p.add_textflow(-1, "", stdopts);

        if (idx == -1)

            throw new Exception("Error: " + p.get_errmsg());

       

        /* Add the heading "Index" to the index Textflow */

        idx = p.add_textflow(idx, "Index\n\n", "");

        if (idx == -1)

            throw new Exception("Error: " + p.get_errmsg());

       

        /* Add the collected and sorted index entries to the index Textflow */

        for (i = 0; i < sortedIndex.length; i++) {

            /* Add the indexed term of the index entry */

            idx = p.add_textflow(idx, sortedIndex[i].name + "  ",

                "fillcolor={gray 0}");

            if (idx == -1)

                throw new Exception("Error: " + p.get_errmsg());

           

            /* Add the page number of the index entry. In addition, define a

             * matchbox with a sequence number as the name. This matchbox will

             * be used later to define a link annotation on it to jump to the

             * respective page.

             */

            idx = p.add_textflow(idx, String.valueOf(sortedIndex[i].page),

                "fillcolor={rgb 0 0.95 0.95} matchbox={name=" + i + "}");

            if (idx == -1)

                throw new Exception("Error: " + p.get_errmsg());

                     

            idx = p.add_textflow(idx, "\n", endopts);

            if (idx == -1)

                throw new Exception("Error: " + p.get_errmsg());

        }

       

       

        /* ---------------------------------------------------------------------

         * Place the index Textflow with each entry consisting of a text, a page

         * number, and a link annotation on the page number

         * ---------------------------------------------------------------------

         */

           

        /* Initialize the current number of the index entry */

        entryno = 0;

       

        /* Loop until all index entries are placed; create new pages as long as

         * more index entries need to be placed

         */

        do

        {

            p.begin_page_ext(pagewidth, pageheight, "");

            pageno++;

           

            /* Fit the index Textflow */

            result = p.fit_textflow(idx, llx, lly, urx, ury, "");

           

            /* Place a page number */

            p.fit_textline(String.valueOf(pageno), pagewidth - 20, 10,

                "fontname=Helvetica encoding=unicode fontsize=12 " +

                "fillcolor={rgb 0 0.95 0.95}");

           

            /* Collect the index entries by retrieving the number of matchboxes

             * on the current page

             */

            mcount = p.info_matchbox("*", 1, "count");

           

            for (i = 1; i <= mcount; i++)

            {

                /* Get the matchbox name which corresponds to the text of the

                 * index entry

                 */

                minfo = p.info_matchbox("*", i, "name");

           

                mname = p.get_string((int) minfo, "");

               

                int action = p.create_action("GoTo", "destination={page=" +

                    (sortedIndex[entryno].page) + "}");

               

                /* With the "GoTo" action, create a Link annotation on the

                 * matchbox defined above. 0 rectangle coordinates will be

                 * replaced with matchbox coordinates.

                 */

                p.create_annotation(0, 0, 0, 0, "Link",

                    "action={activate " + action + "} linewidth=0 " +

                    "usematchbox={" + mname + "}");

               

                entryno++;

            }

            p.end_page_ext("");

           

        } while (result.equals("_boxfull") || result.equals("_nextpage"));


        /* Check for errors */

        if (!result.equals("_stop"))

        {

            /* "_boxempty" happens if the box is very small and doesn't

             * hold any text at all.

             */

            if (result.equals( "_boxempty"))

                throw new Exception ("Error: Textflow box too small");

            else

            {

                /* Any other return value is a user exit caused by

                 * the "return" option; this requires dedicated code to

                 * deal with.

                 */

                throw new Exception ("User return '" + result +

                    "' found in Textflow");

            }

        }


        p.delete_textflow(idx);


        p.end_document("");


        } catch (PDFlibException e) {

            System.err.print("PDFlib exception occurred:\n");

            System.err.print("[" + e.get_errnum() + "] " + e.get_apiname() +

                ": " + e.get_errmsg() + "\n");

        } catch (Exception e) {

            System.err.println(e.toString());

        } finally {

            if (p != null) {

                p.delete();

            }

        }

    }

}