PDFlib
BASKET
PDFlib

pdfvt/starter_pdfvt2

Create a large number of invoices in a single PDF and make use of the following PDF/VT-2 features:

create a document part (DPart) hierarchy

assign PDF/VT scope attributes to images and imported PDF pages

add document part metadata (DPM) to the DPart root node and all page nodes

use proxy/reference pairs for imported PDF pages for the letterhead and photographic images. The referenced PDFs are PDF/X-4p themselves.

Since transparency is used (for the dashed rectangles in the proxies) we supply the required options to achieve GTS_Encapsulated status:

"transparencygroup" for the proxy templates

"mask" for the barcode image (use "renderingintent" for color images)

Required software: PDFlib 8 VT Edition

Download Java Code     Show Output      Show Input Files    Switch to PHP Code

/* $Id: starter_pdfvt2.java,v 1.5 2012/05/07 09:13:51 stm Exp $

 *

 * Starter sample for PDF/VT-2

 * Create a large number of invoices in a single PDF and make use of

 * the following PDF/VT-2 features:

 * - create a document part (DPart) hierarchy

 * - assign PDF/VT scope attributes to images and imported PDF pages

 * - add document part metadata (DPM) to the DPart root node and all page nodes

 * - use proxy/reference pairs for imported PDF pages for the letterhead

 *   and photographic images. The referenced PDFs are PDF/X-4p themselves.

 * - Since transparency is used (for the dashed rectangles in the proxies)

 *   we supply the required options to achieve GTS_Encapsulated status:

 *   - "transparencygroup" for the proxy templates

 *   - "mask" for the barcode image (use "renderingintent" for color images)

 *

 * Required software: PDFlib 8 VT Edition

 * Required data: PDF/X-4p input documents, fonts

 */


package com.pdflib.cookbook.pdflib.pdfvt;


import java.text.DateFormat;

import java.text.DecimalFormat;

import java.text.NumberFormat;

import java.util.Date;

import java.util.Locale;

import java.util.Random;


import com.pdflib.pdflib;

import com.pdflib.PDFlibException;


public class starter_pdfvt2 {


    final static Random random = new Random();


    static class articledata_s {

        articledata_s(String name, double price, int quantity) {

            this.name = name;

            this.price = price;

            this.quantity = quantity;

        }


        String name;

        double price;

        int quantity;

    };


    static class addressdata_s {

        addressdata_s(String firstname, String lastname, String flat,

                String street, String city) {

            this.firstname = firstname;

            this.lastname = lastname;

            this.flat = flat;

            this.street = street;

            this.city = city;

        }


        String firstname;

        String lastname;

        String flat;

        String street;

        String city;

    };


    static final int MATRIXROWS = 32;

    static final int MATRIXDATASIZE = 4 * MATRIXROWS;


    public static void main(String argv[]) {

        int MAXRECORD = 100;

        int i;

        int record;

        int barcodeimage;

        String stationeryfilename = "stationery_pdfx4p.pdf";

        String fontname = "DejaVuSerif";

        String title = "Starter PDF/VT-2";


        /* This is where font/image/PDF input files live. Adjust as necessary. */

        String searchpath = "../input";

        String outfile = "starter_pdfvt2.pdf";

        double left = 55;

        double right = 530;


        double fontsize = 12, leading, x, y;

        double sum, total;

        String buf;

        String optlist;

        String baseopt = "encoding=winansi embedding "

                + "ruler       ={   30 45     275   375   475} "

                + "tabalignment={right left right right right} "

                + "hortabmethod=ruler fontsize=12 ";


        int textflow;


        String closingtext = "Terms of payment: <fillcolor={cmyk 0 1 1 0}>30 days net. "

                + "<fillcolor={gray 0}>90 days warranty starting at the day of sale. "

                + "This warranty covers defects in workmanship only. "

                + "<fontname=DejaVuSerif embedding encoding=winansi>Kraxi Systems, Inc. "

                + "<resetfont>will, at its option, repair or replace the "

                + "product under the warranty. This warranty is not transferable. "

                + "No returns or exchanges will be accepted for wet products.";


        articledata_s articledata[] = {

            new articledata_s("Super Kite", 20, 2),

            new articledata_s("Turbo Flyer", 40, 5),

            new articledata_s("Giga Trash", 180, 1),

            new articledata_s("Bare Bone Kit", 50, 3),

            new articledata_s("Nitty Gritty", 20, 10),

            new articledata_s("Pretty Dark Flyer", 75, 1),

            new articledata_s("Large Hadron Glider", 85, 1),

            new articledata_s("Flying Bat", 25, 1),

            new articledata_s("Simple Dimple", 40, 1),

            new articledata_s("Mega Sail", 95, 1),

            new articledata_s("Tiny Tin", 25, 1),

            new articledata_s("Monster Duck", 275, 1),

            new articledata_s("Free Gift", 0, 1)

        };


        addressdata_s addressdata[] = {

            new addressdata_s("Edith", "Poulard", "Suite C", "Main Street",

                    "New York"),

            new addressdata_s("Max", "Huber", "", "Lipton Avenue",

                    "Albuquerque"),

            new addressdata_s("Herbert", "Pakard", "App. 29", "Easel",

                    "Duckberg"),

            new addressdata_s("Charles", "Fever", "Office 3", "Scenic Drive",

                    "Los Angeles"),

            new addressdata_s("D.", "Milliband", "", "Old Harbour", "Westland"),

            new addressdata_s("Lizzy", "Tin", "Workshop", "Ford", "Detroit"),

            new addressdata_s("Patrick", "Black", "Backside",

                    "Woolworth Street", "Clover")

        };


        String[] salesrepnames = { "Charles Ragner", "Hugo Baldwin",

            "Katie Blomock", "Ernie Bastel", "Lucy Irwin", "Bob Montagnier",

            "Chuck Hope", "Pierre Richard" };


        int dpm = 0, cip4_root, cip4_metadata;


        leading = fontsize + 2;


        pdflib p = null;


        try {

            p = new pdflib();


            if (p.begin_document(outfile,

                    "pdfvt=PDF/VT-2 pdfx=PDF/X-5pg usestransparency=true "

                    + "nodenamelist={root recipient} recordlevel=1") == -1) {

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

            }


            p.set_parameter("SearchPath", searchpath);


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

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


            /* Define output intent profile */

            if (p.load_iccprofile("ISOcoated.icc",

                    "usage=outputintent urls={http://www.color.org}") == -1) {

                System.err.print("Error: " + p.get_errmsg() + "\n");

                System.err.print("Please install the ICC profile package from "

                        + "www.pdflib.com to run the PDF/VT-2 starter sample.\n");

                p.delete();

                System.exit(2);

            }


            /*

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

             * Load company stationery as background (used

             * on first page for each recipient) by reference and

             * construct proxy for it

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

             */

            int proxy_stationery = make_proxy(p, stationeryfilename,

                                            "Proxy for stationery");

            if (proxy_stationery == -1)

            {

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

            }


            /*

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

             * Preload PDF images of all local sales reps (used on first page

             * for each recipient) by reference and construct proxy for it

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

             */

            int proxy_salesrepimage[] = new int[salesrepnames.length];

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

                String description = "Proxy for sales rep image " + i;

                String salesrepfilename = "sales_rep" + i + ".pdf";

               

                proxy_salesrepimage[i] = make_proxy(p, salesrepfilename, description);


                if (proxy_salesrepimage[i] == -1) {

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

                }

            }


            final int ARTICLECOUNT = articledata.length;

            final int ADDRESSCOUNT = addressdata.length;


            /*

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

             * Construct DPM metadata for the DPart

             * root node

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

             */

            dpm = p.poca_new("containertype=dict usage=dpm");

            cip4_root = p.poca_new("containertype=dict usage=dpm");

            cip4_metadata = p.poca_new("containertype=dict usage=dpm");


            optlist = "type=dict key=CIP4_Root value=" + cip4_root;

            p.poca_insert(dpm, optlist);


            optlist = "type=dict key=CIP4_Metadata value=" + cip4_metadata;

            p.poca_insert(cip4_root, optlist);


            p.poca_insert(cip4_metadata,

                    "type=string key=CIP4_Conformance value=base");

            p.poca_insert(cip4_metadata,

                    "type=string key=CIP4_Creator value=starter_pdfvt2");

            p.poca_insert(cip4_metadata,

                    "type=string key=CIP4_JobID value={Kraxi Systems invoice}");


            /* Create root node in the DPart hierarchy and add DPM metadata */

            optlist = "dpm=" + dpm;

            p.begin_dpart(optlist);


            p.poca_delete(dpm);

            p.poca_delete(cip4_root);

            p.poca_delete(cip4_metadata);


            DecimalFormat zip_code_format = new DecimalFormat("00000");


            for (record = 0; record < MAXRECORD; record++) {

                byte datamatrix[] = new byte[MATRIXDATASIZE];

                int item;

                int cip4_recipient, cip4_contact, cip4_person;

                String firstname, lastname;


                firstname = addressdata[get_random(ADDRESSCOUNT)].firstname;

                lastname = addressdata[get_random(ADDRESSCOUNT)].lastname;


                /*

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

                 * Construct DPM metadata for the next

                 * DPart node (i.e. the page)

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

                 */

                dpm = p.poca_new("containertype=dict usage=dpm");

                cip4_root = p.poca_new("containertype=dict usage=dpm");

                cip4_recipient = p.poca_new("containertype=dict usage=dpm");

                cip4_contact = p.poca_new("containertype=dict usage=dpm");

                cip4_person = p.poca_new("containertype=dict usage=dpm");


                optlist = "type=dict key=CIP4_Root value=" + cip4_root;

                p.poca_insert(dpm, optlist);


                optlist = "type=dict key=CIP4_Recipient value="

                        + cip4_recipient;

                p.poca_insert(cip4_root, optlist);


                optlist = "type=string key=CIP4_UniqueID value={ID_" + record

                        + "}";

                p.poca_insert(cip4_recipient, optlist);


                optlist = "type=dict key=CIP4_Contact value=" + cip4_contact;

                p.poca_insert(cip4_recipient, optlist);


                optlist = "type=dict key=CIP4_Person value=" + cip4_person;

                p.poca_insert(cip4_contact, optlist);


                optlist = "type=string key=CIP4_Firstname value={" + firstname

                        + "}";

                p.poca_insert(cip4_person, optlist);


                optlist = "type=string key=CIP4_Lastname value={" + lastname

                        + "}";

                p.poca_insert(cip4_person, optlist);


                /*

                 * Create a new node in the document part hierarchy and add DPM

                 * metadata

                 */

                optlist = "dpm=" + dpm;

                p.begin_dpart(optlist);


                p.poca_delete(dpm);

                p.poca_delete(cip4_root);

                p.poca_delete(cip4_recipient);

                p.poca_delete(cip4_contact);

                p.poca_delete(cip4_person);


                /*

                 * Establish coordinates with the origin in the upper left

                 * corner.

                 */

                p.begin_page_ext(0, 0,

                        "topdown width=a4.width height=a4.height");


                /*

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

                 * Place company stationery / proxy (template) as background

                 * on the page

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

                 */

                p.fit_image(proxy_stationery, 0, 842, "");


                /*

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

                 * Place name and image proxy (template) of local sales

                 * rep on the page

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

                 */

                y = 177;

                x = 455;


                buf = "Local sales rep:";

                optlist = "fontname=" + fontname

                        + " encoding=winansi embedding fontsize=9";

                p.fit_textline(buf, x, y, optlist);

                p.fit_textline(salesrepnames[record % salesrepnames.length], x,

                        y + 9, optlist);


                y = 280;

               

                /* Place the proxy on the page */

                p.fit_image(proxy_salesrepimage[record % salesrepnames.length],

                        x, y, "boxsize={90 90} fitmethod=meet");


                /*

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

                 * Address of recipient

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

                 */

                y = 170;


                optlist = "fontname=" + fontname

                        + " encoding=winansi embedding fontsize=" + fontsize;

                buf = firstname + " " + lastname;

                p.fit_textline(buf, left, y, optlist);


                y += leading;

                p.fit_textline(addressdata[get_random(ADDRESSCOUNT)].flat,

                        left, y, optlist);


                y += leading;

                buf = "" + get_random(999) + " "

                        + addressdata[get_random(ADDRESSCOUNT)].street;

                p.fit_textline(buf, left, y, optlist);


                y += leading;

                buf = zip_code_format.format(get_random(99999)) + " "

                        + addressdata[get_random(ADDRESSCOUNT)].city;

                p.fit_textline(buf, left, y, optlist);


                /*

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

                 * Individual barcode image for each recipient

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

                 */

                create_datamatrix(datamatrix, record);

                p.create_pvf("barcode", datamatrix, "");


                /* The "mask" option helps us achieve GTS_Encapsulated status */

                barcodeimage = p.load_image("raw", "barcode",

                        "bpc=1 components=1 width=32 height=32 invert "

                                + "pdfvt={scope=singleuse} mask");

                if (barcodeimage == -1) {

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

                }


                p.fit_image(barcodeimage, 280.0, 200.0, "scale=1.5");

                p.close_image(barcodeimage);

                p.delete_pvf("barcode");


                /*

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

                 * Print header and date

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

                 */

                y = 300;

                buf = "INVOICE 2011-" + (record + 1);

                optlist = "fontname=" + fontname

                        + " encoding=winansi embedding fontsize=" + fontsize;

                p.fit_textline(buf, left, y, optlist);


                buf = DateFormat.getDateInstance(DateFormat.LONG, Locale.US)

                        .format(new Date());

                optlist = "fontname=" + fontname

                        + " encoding=winansi fontsize=" + fontsize

                        + " embedding " + "position {100 0}";

                p.fit_textline(buf, right, y, optlist);


                /* Print the invoice header line */

                y = 370;

                buf = "\tITEM\tDESCRIPTION\tQUANTITY\tPRICE\tAMOUNT";


                optlist = baseopt + " fontname=" + fontname;

                textflow = p.create_textflow(buf, optlist);


                if (textflow == -1) {

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

                }

                p.fit_textflow(textflow, left, y - leading, right, y, "");

                p.delete_textflow(textflow);


                /*

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

                 * Print variable-length article list

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

                 */

                y += 2 * leading;

                total = 0;


                optlist = baseopt + " fontname=" + fontname;


                final NumberFormat priceFormat = NumberFormat.getInstance(Locale.US);

                priceFormat.setMaximumFractionDigits(2);

                priceFormat.setMinimumFractionDigits(2);

               

                for (i = 0, item = 0; i < ARTICLECOUNT; i++) {

                    int quantity = get_random(9) + 1;


                    if ((get_random(2) % 2) != 0)

                        continue;


                    item++;

                    sum = articledata[i].price * quantity;


                    buf = "\t" + item + "\t" + articledata[i].name + "\t"

                            + quantity + "\t"

                            + priceFormat.format(articledata[i].price) + "\t"

                            + priceFormat.format(sum);

                   

                    textflow = p.create_textflow(buf, optlist);


                    if (textflow == -1) {

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

                    }

                    p.fit_textflow(textflow, left, y - leading, right, y, "");

                    p.delete_textflow(textflow);


                    y += leading;

                    total += sum;

                }


                y += leading;


                buf = priceFormat.format(total);

                optlist = "fontname=" + fontname

                        + " encoding=winansi embedding " + "fontsize="

                        + fontsize + " position {100 0}";

                p.fit_textline(buf, right, y, optlist);


                /*

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

                 * Constant closing text

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

                 */


                y += 5 * leading;

                optlist = baseopt + " fontname=" + fontname

                        + " alignment=justify leading=120%";

                textflow = p.create_textflow(closingtext, optlist);


                if (textflow == -1) {

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

                }

                p.fit_textflow(textflow, left, y + 6 * leading, right, y, "");

                p.delete_textflow(textflow);


                p.end_page_ext("");


                /* Close node in the document part hierarchy */

                p.end_dpart("");

            }


            /* Close root node in the document part hierarchy */

            p.end_dpart("");


            p.end_document("");

        }

        catch (PDFlibException e) {

            System.err.println(

                    "PDFlib exception occurred in starter_pdfvt1 sample:");

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

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

        }

        catch (Exception e) {

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

        }

        finally {

            if (p != null) {

                p.delete();

            }

        }

    }


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

     * Load page 1 of the specified PDF and use it as reference for

     * a proxy which consists of a transparent crossed-out rectangle

     * of the same size.

     */

    static int

    make_proxy(pdflib p, String targetname, String description) throws PDFlibException

    {

        String optlist;

        int proxy;

        double linewidth = 2;

        double width, height;

        double x1, y1, x2, y2, x3, y3, x4, y4;

        int gstate;


        /* Create the template which will serve as proxy. The referenced

         * page (the target) is attached to the proxy.

         * The width and height parameters will be set in PDF_end_template_ext()

         * after we queried the size of the target page.

         * The "transparencygroup" option is provided to achieve GTS_Encapsulated

         * status.

         * You can add "pdfvt={xid={uuid:...} }" to optlist if you can

         * generate unique IDs.

         */


        optlist = "reference={filename=" + targetname

            + " pagenumber=1} pdfvt={scope=file} "

            + "transparencygroup={colorspace=devicecmyk isolated=true}";

        proxy = p.begin_template_ext(0, 0, optlist);


        if (proxy == -1)

        {

            return proxy;

        }


        /* Determine the coordinates of the target; we use it for

         * dimensioning the proxy appropriately.

         */

        x1 = p.info_image(proxy, "targetx1", "");

        y1 = p.info_image(proxy, "targety1", "");

        x2 = p.info_image(proxy, "targetx2", "");

        y2 = p.info_image(proxy, "targety2", "");

        x3 = p.info_image(proxy, "targetx3", "");

        y3 = p.info_image(proxy, "targety3", "");

        x4 = p.info_image(proxy, "targetx4", "");

        y4 = p.info_image(proxy, "targety4", "");


        width = x2 - x1;

        height = y4 - y1;


        /* Draw a transparent crossed-out rectangle to visualize the proxy.

         * Attention: if we use the exact corner points, one half of the

         * linewidth would end up outside the template, and therefore be

         * clipped.

         */

        p.setlinewidth(linewidth);

        p.setdashpattern("dasharray={10 5}");


        /* Make the dashed crossed-out rectangle transparent so that the proxy

         * does not obscure the underlying page contents.

         */

        gstate = p.create_gstate("opacitystroke=0.25 opacityfill=0.25");

        p.set_gstate(gstate);


        p.moveto(x1 + linewidth / 2, y1 + linewidth / 2);

        p.lineto(x2 - linewidth / 2, y2 + linewidth / 2);

        p.lineto(x3 - linewidth / 2, y3 - linewidth / 2);

        p.lineto(x4 + linewidth / 2, y4 - linewidth / 2);

        p.lineto(x1 + linewidth / 2, y1 + linewidth / 2);

        p.lineto(x3 - linewidth / 2, y3 - linewidth / 2);

        p.moveto(x2 - linewidth / 2, y2 + linewidth / 2);

        p.lineto(x4 + linewidth / 2, y4 - linewidth / 2);

        p.stroke();


        double fontsize = width > 550 ? 24.0 : 48.0;

        optlist = "fontname=LuciduxSans-Oblique encoding=winansi embedding "

                + "fontsize=" + fontsize + " fitmethod=auto position=center "

                + "boxsize={" + width + " " + height + "}";

        p.fit_textline(description, 0, 0, optlist);


        /* Make the proxy template the same size as the target page */

        p.end_template_ext(width, height);


        return proxy;

    }

    /**

     * Get a pseudo random number between 0 and n-1

     */

    static int get_random(int n) {

        return random.nextInt(n);

    }


    /**

     * Simulate a datamatrix barcode

     */

    static void create_datamatrix(byte datamatrix[], int record) {

        int i;


        for (i = 0; i < MATRIXROWS; i++) {

            datamatrix[4 * i + 0] = (byte) ((0xA3 + 1 * record + 17 * i) % 0xFF);

            datamatrix[4 * i + 1] = (byte) ((0xA2 + 3 * record + 11 * i) % 0xFF);

            datamatrix[4 * i + 2] = (byte) ((0xA0 + 5 * record + 7 * i) % 0xFF);

            datamatrix[4 * i + 3] = (byte) ((0x71 + 7 * record + 9 * i) % 0xFF);

        }

        for (i = 0; i < MATRIXROWS; i++) {

            datamatrix[4 * i + 0] |= 0x80;

            datamatrix[4 * i + 2] |= 0x80;

            if ((i % 2) != 0)

                datamatrix[4 * i + 3] |= 0x01;

            else

                datamatrix[4 * i + 3] &= 0xFE;

        }

        for (i = 0; i < 4; i++) {

            datamatrix[4 * (MATRIXROWS / 2 - 1) + i] = (byte) 0xFF;

            datamatrix[4 * (MATRIXROWS - 1) + i] = (byte) 0xFF;

        }

    }

}