PDFlib Cookbook

cookbook

interactive/markup_annotations

Create various types of markup annotations directly and in a Textflow.

Download Java Code  Switch to PHP Code  Show Output 

/*
 * Markup annotations:
 * Create various types of markup annotations directly and in a Textflow.
 *
 * Some annotations are placed by explicitly specifying their rectangle
 * coordinates.
 * 
 * The remaining annotations are placed over text fragments in a Textflow.
 * These locations are referenced by named matchboxes in the Textflow.
 * The options "matchbox" and "matchbox end" define the matchboxes in
 * the Textflow. The names are later used for creating the annotations;
 * explicit coordinates are not required in this case.
 * 
 * For the Highlight annotation a corresponding Popup annotation is created.
 * 
 * The following types of Markup annotations are demonstrated:
 * Caret, Circle, FileAttachment, FreeText, Highlight, Line, Square, Squiggly,
 * StrikeOut, Text (=sticky note), Underline
 * 
 * The following types of Markup annotations are not demonstrated here:
 * Ink, Polygon, PolyLine
 *
 * Required software: PDFlib/PDFlib+PDI/PPS 10
 * Required data: font
 */
package com.pdflib.cookbook.pdflib.interactive;

import com.pdflib.pdflib;
import com.pdflib.PDFlibException;

public class markup_annotations
{
    public static void main (String argv[])
    {
        /* This is where the data files are. Adjust as necessary. */
        String searchpath = "../input";
        String outfile = "markup_annotations.pdf";
        String title = "Markup annotations";

        pdflib p = null;
        int exitcode = 0;

        try {
            double llx, lly, urx, ury;
            int asset;
            int tf = -1;
            
            p = new pdflib();

            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, "destination={type=fitwindow}") == -1)
                throw new Exception("Error: " + p.get_errmsg());

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

            /* Create page */
            p.begin_page_ext(0, 0, "width=a4.width height=a4.height");

            // For simplicity we name the matchboxes according to the
            // corresponding annotation type that they will hold.
            String text =
                "Lorem " +
                    "<matchbox={name=caret boxheight={ascender descender}}>caret<matchbox=end> " +
                "ipsum dolor sit amet, consectetur adi&shy;pi&shy;sicing elit, " +
                "sed do eius&shy;mod" +
                    "<matchbox={name=circle boxheight={ascender descender}}> circle <matchbox=end>" +
                "tempor incidi&shy;dunt ut labore et dolore magna ali&shy;qua. Ut " +
                    "<matchbox={name=highlight boxheight={ascender descender}}>highlight<matchbox=end> " +
                "enim ad minim ve&shy;niam, quis nostrud " +
                    "<matchbox={name=line}>line<matchbox=end> " +
                "exer&shy;citation ull&shy;amco la&shy;bo&shy;ris nisi ut " +
                    "<matchbox={name=square boxheight={ascender descender}}>square<matchbox=end> " +
                "ali&shy;quip ex ea commodo con&shy;sequat. Duis aute irure dolor in " +
                    "<matchbox={name=squiggly boxheight={ascender descender}}>squiggly<matchbox=end> " +
                "repre&shy;henderit in voluptate velit esse cillum dolore eu " +
                    "<matchbox={name=strikeout}>strikeout<matchbox=end> " +
                "fugiat nulla pari&shy;atur. Excep&shy;teur sint occae&shy;cat " +
                "cupi&shy;datat non proident, sunt in culpa qui officia dese&shy;runt " +
                    "<matchbox={name=underline boxheight={ascender descender}}>underline<matchbox=end> " +
                "mollit anim id est laborum. ";

            tf = p.create_textflow(text,
                "fontname=NotoSerif-Regular fontsize=20 leading=140% charref");
            if (tf == -1)
                throw new Exception("Error: " + p.get_errmsg());

            // Place the Textflow on the page
            String result = p.fit_textflow(tf, 50, 50, 550, 550, "fitmethod=auto");
            if (!result.equals("_stop"))
            {
                /* Check for errors */
            }

            /*
             * p.info_matchbox() returns box coordinates in user coordinates
             * which we use in calls to create_annotation(). If the user
             * coordinate system has been transformed we need this method to
             * accept user coordinates. Instead of supplying "usercoordinate=true"
             * to individual calls we set it here globally. 
             */
            p.set_option("usercoordinates=true");
            
            // Create some annotation types with explicit rectangle coordinates
            
            int font = p.load_font("NotoSerif-Bold", "unicode", "");
            p.create_annotation(300, 750, 500, 800, "Stamp", "contents={Stamp annotation} font=" + font);
            
            p.create_annotation(50, 750, 75, 800, "Text",
                "contents={My little note...} open=false iconname=comment annotcolor=red");

            /* File attachment annotation */
            asset = p.load_asset("Attachment", "af1.txt", "description={Simple text file}");
            if (asset == -1)
                throw new Exception("Error: " + p.get_errmsg());
            
            p.create_annotation(50, 700, 75, 725, "FileAttachment",
                "attachment=" + asset + " contents={My file attachment} iconname=pushpin annotcolor=blue");
            
            /* FreeText annotation with a callout line pointing to the
             * top left corner of the Textflow box.
             */
            llx = 200;
            lly = 600;
            urx = 350;
            ury = 650;

            font = p.load_font("NotoSerif-Regular", "unicode", "");
            p.create_annotation(llx, lly, urx, ury, "FreeText",
                "contents={FreeText with callout line} calloutline={" +
                "50 550 " +                                     // start point (what it points to)
                (llx+50)/2 + " " + (lly + ury)/2 + " " +        // optional knee point
                llx + " " + (lly + ury)/2 + "} " +              // end point (on the annotation border)
                "endingstyles={closedarrow none} fontsize=12 font=" + font + " annotcolor=yellow fillcolor=red");

            
            /* Create various annotation types in the corresponding matchboxes
             * in the Textflow. Since we use matchboxes as target rectangles
             * we can supply the annotation coordinates as 0, 0, 0, 0.
             */
            p.create_annotation(0, 0, 0, 0, "Caret", "usematchbox=caret annotcolor=blue");
            
            p.create_annotation(0, 0, 0, 0, "Circle", "usematchbox=circle linewidth=2 annotcolor=purple interiorcolor=purple opacity=0.25");
            
            // Attach Popup to the Highlight annotation via name
            p.create_annotation(0, 0, 0, 0, "Highlight", "name=my_highlight title={My highlight} contents={My comment in the Popup...} usematchbox=highlight linewidth=3 annotcolor=red");
            
            /* Create a Popup annotation for the Highlight annotation.
             * Fetch corner coordinates of the parent Highlight annotation so
             * that we can place the corresponding Popup close to it.
             */
            llx = p.info_matchbox("highlight", 1, "x1") +  50;
            lly = p.info_matchbox("highlight", 1, "y1") + 150;
            p.create_annotation(llx, lly, llx+150, lly+100, "Popup", "parentname=my_highlight open");
            
            // Fetch corner coordinates so that we can draw a diagonal line
            llx = p.info_matchbox("line", 1, "x1");
            lly = p.info_matchbox("line", 1, "y1");
            urx = p.info_matchbox("line", 1, "x3");
            ury = p.info_matchbox("line", 1, "y3");
            p.create_annotation(0, 0, 0, 0, "Line", "usematchbox=line line={" + llx + " " + lly + " " + urx + " " + ury + "} linewidth=3 annotcolor=green");

            p.create_annotation(0, 0, 0, 0, "Square", "usematchbox=square cloudy=1 linewidth=2 annotcolor=magenta");
            
            p.create_annotation(0, 0, 0, 0, "Squiggly", "usematchbox=squiggly annotcolor=blue");
            
            p.create_annotation(0, 0, 0, 0, "Strikeout", "usematchbox=strikeout annotcolor=red");
            
            p.create_annotation(0, 0, 0, 0, "Underline", "usematchbox=underline annotcolor=purple");
            
            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.toString());
            exitcode = 1;
        } finally {
            if (p != null) {
                p.delete();
            }
            System.exit(exitcode);
        }
    }
}