PDFlib Cookbook

cookbook

interactive/barcode_field

Download Java Code        Switch to PHP Code      Show Output PDF

package com.pdflib.cookbook.pdflib.interactive;

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

/**
 * barcode_field: Create the three types of barcode fields that Acrobat
 * supports.
 * 
 * This barcode form works as follows:
 * - Text fields to the left serve as data source where the user can type.
 * - Barcode fields to the right reflect the value of the text fields,
 *   represented as barcodes in the PDF417, Data Matrix and QuickResponse
 *   (QR) symbologies.
 * - Each barcode field is assigned a JavaScript as "calculate" action.
 *   Whenever the "calculate" event fires, the barcodes will be recalculated.
 * - An additional "page open" action explicitly calls this.calculateNow()
 *   to force the barcodes to be rendered upon opening the page.
 * - The "Reset" button can be used to initialize all text fields (and
 *   therefore also the dependent barcode fields) to their original state.
 * 
 * Important: Displaying and printing the barcode fields will only work with
 * full Acrobat version 9 or newer, but not with Adobe Reader.
 * 
 * Required software: PDFlib/PDFlib+PDI/PPS 9
 * Required data: none
 * 
 * @version $Id: barcode_field.java,v 1.5 2013/01/15 10:12:00 stm Exp $
 */
public class barcode_field {
    /**
     * Margin from the page border. 
     */
    final static int MARGIN = 30;
    
    /**
     * Sample text to provide default data for the barcode fields.
     */
    final static String SAMPLE_TEXT =
        "To change the barcode field to the right, type in this box. "
        + "The barcode field to the right will reflect the contents of the "
        + "text field as barcode after the text field lost the focus. To "
        + "reset the contents of all barcode fields, click the 'Reset' button.";
    
    /**
     * Tooltip text for text entry fields.
     */
    final static String TOOLTIP_TEXT = "Enter data for barcode field here";
    
    /**
     * Page height.
     */
    final static int PAGE_HEIGHT = 842;
    
    /**
     * Page width.
     */
    final static int PAGE_WIDTH = 595;
    
    /**
     * Height of reset button.
     */
    final static int RESET_BUTTON_HEIGHT = 50;
    
    /**
     * Width of reset button.
     */
    final static int RESET_BUTTON_WIDTH = 120;
    
    public static void main(String argv[]) {
        String outfile = "barcode_field.pdf";
        String title = "Barcode Fields";

        pdflib p = null;

        try {
            p = new pdflib();

            /* This means we must check return values of load_font() etc. */
            p.set_option("errorpolicy=return");

            if (p.begin_document(outfile,
                    "compatibility=1.7ext3 pagelayout=singlepage") == -1)
                throw new Exception("Error: " + p.get_errmsg());

            p.set_info("Creator", "PDFlib Cookbook");
            p.set_info("Title", title + " $Revision: 1.5 $");

            int font = p.load_font("Helvetica", "winansi", "");
            if (font == -1)
                throw new Exception("Error: " + p.get_errmsg());

            /*
             * Define JavaScript that recalculates all field contents on the
             * page.
             */
            final int calculate_now_action =
                p.create_action("JavaScript", "script { this.calculateNow(); }");
            
            /* Start page */
            p.begin_page_ext(0, 0, 
                "width=a4.width height=a4.height "
                    + "action={open "+ calculate_now_action + "}");

            /*
             * Build the option list for the reset button, which has to contain
             * the names of all the fields to reset to their default values.
             */
            String reset_optlist = "namelist={";
            
            /*
             * Calculate available area and sizes for the text and barcode
             * fields. Barcode fields are twice as wide as the corresponding
             * text fields.
             */
            final int num_fields = 3;
            final double field_area_height =
                PAGE_HEIGHT - 3 * MARGIN - RESET_BUTTON_HEIGHT;
            final double field_area_width =
                PAGE_WIDTH - 2 * MARGIN;
            final double field_height =
                (field_area_height - (num_fields - 1) * MARGIN) / num_fields;
            final double text_field_width = (field_area_width - MARGIN) / 3;
            final double barcode_field_width =
                                (field_area_width - MARGIN) * 2 / 3;
            
            int field_number = 0;
            
            String text_field_name = "text_" + field_number;
            String barcode_field_name = "barcode_" + field_number;
            
            /*
             * Add the name of the text field to the list fields to reset.
             */
            reset_optlist += " {" + text_field_name + "}";
            
            /*
             * Create text field.
             * 
             * Note that Acrobat at least up to version 10.1 contains a bug 
             * that makes it crash in case the first field on a page is a 
             * barcode field. Therefore make sure that a field of another type
             * is created first.
             */
            String optlist = "tooltip={PDF417 barcode:\n" + TOOLTIP_TEXT + "} "
                + "multiline=true bordercolor={gray 0} linewidth=1 "
                + "font=" + font + " "
                + "currentvalue={PDF417 barcode:\n" + SAMPLE_TEXT + "} "
                + "defaultvalue={PDF417 barcode:\n" + SAMPLE_TEXT + "}";
            double x = MARGIN;
            double y = PAGE_HEIGHT - (MARGIN + RESET_BUTTON_HEIGHT )
                        - (field_number + 1) * (MARGIN + field_height);
            p.create_field(x, y, x + text_field_width, y + field_height,
                text_field_name, "textfield", optlist);
            
            /*
             * Create an action that calculates the value for the barcode field
             * from the contents of the text field.
             */
            int calculate_action = create_calc_action(p, text_field_name);
            
            /*
             * Create a PDF417 barcode:
             * 
             * - no compression (dataprep=0)
             * - apply error correction level 7 (ecc=7)
             * - x symbol width 3, x symbol height 6 (xsymheight=6 xsymwidth=3)
             */
            optlist = "barcode={symbology=PDF417 dataprep=0 "
                + "ecc=7 xsymheight=6 xsymwidth=3} "
                + "action={calculate=" + calculate_action + "} font=" + font;
            x = 2 * MARGIN + text_field_width;
            p.create_field(x, y, x + barcode_field_width, y + field_height,
                barcode_field_name, "textfield", optlist);
            
            /*
             * Repeat same steps to create a Data Matrix barcode.
             */
            field_number += 1;
            text_field_name = "text_" + field_number;
            barcode_field_name = "barcode_" + field_number;
            
            reset_optlist += " {" + text_field_name + "}";
            
            optlist = "tooltip={Data Matrix barcode:\n" + TOOLTIP_TEXT + "} "
                + "multiline=true bordercolor={gray 0} linewidth=1 "
                + "font=" + font + " "
                + "currentvalue={Data Matrix barcode:\n" + SAMPLE_TEXT + "} "
                + "defaultvalue={Data Matrix barcode:\n" + SAMPLE_TEXT + "}";
            x = MARGIN;
            y = PAGE_HEIGHT - (MARGIN + RESET_BUTTON_HEIGHT )
                    - (field_number + 1) * (MARGIN + field_height);
            p.create_field(x, y, x + text_field_width, y + field_height,
                text_field_name, "textfield", optlist);
            calculate_action = create_calc_action(p, text_field_name);
            
            /*
             * Create the Data Matrix barcode.
             */
            optlist = "barcode={symbology=DataMatrix dataprep=0 "
                + "ecc=0 xsymwidth=10} "
                + "action={calculate=" + calculate_action + "} font=" + font;
            x = 2 * MARGIN + text_field_width;
            p.create_field(x, y, x + barcode_field_width, y + field_height,
                barcode_field_name, "textfield", optlist);
            
            /*
             * Repeat same steps to create a QR Code barcode.
             */
            field_number += 1;
            text_field_name = "text_" + field_number;
            barcode_field_name = "barcode_" + field_number;
            
            reset_optlist += " {" + text_field_name + "}";
            
            optlist = "tooltip={QR Code barcode:\n" + TOOLTIP_TEXT + "} "
                + "multiline=true bordercolor={gray 0} linewidth=1 "
                + "font=" + font + " "
                + "currentvalue={QR Code barcode:\n" + SAMPLE_TEXT + "} "
                + "defaultvalue={QR Code barcode:\n" + SAMPLE_TEXT + "}";
            x = MARGIN;
            y = PAGE_HEIGHT - (MARGIN + RESET_BUTTON_HEIGHT )
                    - (field_number + 1) * (MARGIN + field_height);
            p.create_field(x, y, x + text_field_width, y + field_height,
                text_field_name, "textfield", optlist);
            calculate_action = create_calc_action(p, text_field_name);
            
            /*
             * Create the QR code barcode:
             * 
             * - apply error correction level 2 (ecc=2)
             * - x symbol width 10
             * - compress data before encoding (dataprep=1)
             */
            optlist = "barcode={symbology=QRCode ecc=2 xsymwidth=10 dataprep=1} "
                + "action={calculate=" + calculate_action + "} font=" + font;
            x = 2 * MARGIN + text_field_width;
            p.create_field(x, y, x + barcode_field_width, y + field_height,
                barcode_field_name, "textfield", optlist);
            
            /*
             * Terminate the option list for the reset button, and create a
             * reset button that resets the text input fields to their default
             * values.
             */
            reset_optlist += "}";
            final int reset_action = p.create_action("ResetForm", reset_optlist);

            optlist = "action={activate=" + reset_action + "} font={" + font 
                    + "} caption={Reset} bordercolor=black "
                    + "tooltip={Reset all fields to default values}";
            x = MARGIN;
            y = PAGE_HEIGHT - MARGIN - RESET_BUTTON_HEIGHT;
            p.create_field(x, y, x + RESET_BUTTON_WIDTH, y + RESET_BUTTON_HEIGHT,
                "Reset", "PushButton", optlist);
            
            /*
             * Create a text box with a warning that Adobe Reader does not
             * display the barcode fields.
             */
            optlist = "font=" + font + " fontsize=14 fillcolor=red";
            int tf = -1;
            tf = p.add_textflow(tf,
                "Note that the barcode fields only work with full Acrobat "
                    + "version 9 or newer, but not with Adobe Reader!",
                    optlist);
            x = 2 * MARGIN + RESET_BUTTON_WIDTH;
            p.fit_textflow(tf, x, y,
                PAGE_WIDTH + 3 * MARGIN - RESET_BUTTON_WIDTH,
                y + RESET_BUTTON_HEIGHT, "fitmethod=auto");
            
            p.end_page_ext("");
            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.getMessage());
        }
        finally {
            if (p != null) {
                p.delete();
            }
        }
    }

    /**
     * Create the action to calculate the value of the barcode field.
     * 
     * @param p
     *            the pdflib object
     * @param text_field_name
     *            the name of the text field that determines the value of the
     *            barcode field
     * 
     * @return the handle of the calculate action
     * 
     * @throws PDFlibException
     */
    private static int create_calc_action(pdflib p, String text_field_name)
            throws PDFlibException {
        final String script =
            "script { "
                + "try { "
                    + "var fieldname = \"" + text_field_name + "\"; "
                    + "event.value = fieldname + \":\" + this.getField(fieldname).value;"
                + "} "
                + "catch(e) {"
                    + "event.value = \"EXCEPTION\";"
                + "}"
            + "}";
        return p.create_action("JavaScript", script);
    }
}