PDFlib Cookbook

cookbook

pdfua/tagged_invoice

Download PHP Code     Switch to Java Code     Show Output PDF

<?php
/*
 * $Id: tagged_invoice.php,v 1.9 2015/10/14 12:46:24 rp Exp $
 *
 * Combined PDF/UA-1 and PDF/A-2a invoice generation demo
 *
 * Required software: PDFlib+PDI/PPS 9
 * (set $run_sample_with_pdi=false below to run the sample code without PDI)
 * Required data: two fonts, raster image, Tagged PDF
 */

$run_sample_with_pdi = true;

$x_table = 55;
$tablewidth = 475;

$y_address = 682;
$x_salesrep = 455;
$y_invoice = 542;
$y_invoice_p2 = 800;
$bottom = 40;
$imagesize = 90;

$fontsize = 11;
$fontsizesmall = 9;

$fontname = "DejaVuSerif";

$pagedimensions = "width=a4.width height=a4.height";

$basefontoptions = "fontname=" . $fontname . " fontsize=" . $fontsize
        . " encoding=unicode embedding ";

$basetagoptions = "tag={tagname=P}";
    
/**
 * Place company stationery
 */
function create_stationery($p) {
    global $fontsize, $fontsizesmall, $run_sample_with_pdi, $x_table,
        $y_address, $x_salesrep, $imagesize, $basefontoptions, $basetagoptions;
    
    $sender = "Kraxi Systems, Inc. &#x2022; 17, "
            . "Aviation Road &#x2022; Paperfield";
    $stationeryfontname = "LuciduxSans-Oblique";

    $y_company_logo = 748;

    $senderfull = array(
        "17, Aviation Road",
        "Paperfield",
        "Phone 7079 4301",
        "Fax 7079 4302",
        "info@kraxi.com",
        "www.kraxi.com"
    );

    $salesrepfilename = "sales_rep4.jpg";
    $salesrepname = "Lucy Irwin";
    $salesrepcaption = "Local sales rep:";

    /*
     * ----------------------------------- 
     * Print company logo and sender address
     *  -----------------------------------
     */

    if ($run_sample_with_pdi) {
        $stationeryfilename = "kraxi_logo2.pdf";

        $stationery = $p->open_pdi_document($stationeryfilename, "");
        $page = $p->open_pdi_page($stationery, 1, "");

        /* Check whether the page can be placed in the current situation */
        if ((int) $p->info_pdi_page($page, "fittingpossible", "") == 0) {
            throw new Exception("Cannot place Tagged PDF page: "
                . $p->get_errmsg());
        }

        $p->fit_pdi_page($page, 0, $y_company_logo,
            "boxsize={595 85} position={65 center}");

        $p->close_pdi_page($page);
        $p->close_pdi_document($stationery);
    }

    $optlist = $basefontoptions . " fontsize=" . $fontsizesmall . " fontname="
        . $stationeryfontname . " charref=true tag={tagname=Artifact}";
    $p->fit_textline($sender, $x_table, $y_address + $fontsize, $optlist);

    /*
     * -----------------------------------
     * Print full company contact details
     *  -----------------------------------
     */
    $optlist = $basefontoptions . " fontname=" . $stationeryfontname
            . " fillcolor={rgb 0.35 0.36 0.37} " . $basetagoptions;
    
    for ($i = 0; $i < count($senderfull); $i++) {
        $p->fit_textline($senderfull[$i],
                $x_salesrep, $y_address + 92 - $i * 1.25 * $fontsize, $optlist);
    }
    
    /*
     * -----------------------------------
     * Place name and image of local sales rep
     * -----------------------------------
     */
    $id_p = $p->begin_item("P", "");

    $optlist = $basefontoptions . " fontsize=" . $fontsizesmall;
    $p->fit_textline($salesrepcaption, $x_salesrep, $y_address - $fontsizesmall,
        $optlist);
    $p->fit_textline($salesrepname, $x_salesrep,
            $y_address - 2 * $fontsizesmall, $optlist);

    $salesrepimage = $p->load_image("auto", $salesrepfilename, "");

    $optlist = "boxsize={" . $imagesize . " " . $imagesize
        . "} fitmethod=meet tag={tagname=Figure Alt={Image of sales rep. "
        . $salesrepname . "}}";
    $p->fit_image($salesrepimage, $x_salesrep, $y_address - 3 * $fontsizesmall
        - $imagesize, $optlist);
    $p->close_image($salesrepimage);

    $p->end_item($id_p);
}

/*
 * Print receiver address
 */
function create_address($p) {
    global $x_table, $tablewidth, $y_address, $basefontoptions, $basetagoptions;
    global $fontsize;
    
    $address = array(
        "John Q. Doe",
        "255 Customer Lane",
        "Suite B",
        "12345 User Town",
        "Everland"
    );

    for ($i = 0; $i < count($address); $i++) {
        $p->fit_textline($address[$i], $x_table,
            $y_address - ($i+1)*1.2*$fontsize,
            $basefontoptions . $basetagoptions);
    }
}

/*
 * -----------------------------------
 * Print the header and date
 * -----------------------------------
 */
function create_table_header($p, $id_div) {
    global $x_table, $tablewidth, $y_invoice, $basefontoptions, $basetagoptions;
    
    $invoiceheader = "INVOICE " . date("Y") . "-03";

    /* Add a structured bookmark which references the Div element */
    $optlist = "item=" . $id_div;
    $p->create_bookmark($invoiceheader, $optlist);

    $optlist = $basefontoptions . " tag={tagname=H1 Title={" . $invoiceheader
        . "}}";
    $p->fit_textline($invoiceheader, $x_table, $y_invoice, $optlist);

    $date = date("F j, Y");

    $optlist = "position {100 0} " . $basefontoptions . " " . $basetagoptions;
    $p->fit_textline($date, $x_table + $tablewidth, $y_invoice, $optlist);
}

/* This is where the data files are. Adjust as necessary. */
$searchpath = dirname(dirname(dirname(__FILE__)))."/input";
    
$tablesummary = "List of purchased articles";

$closingtext =
    "Terms of payment: <fillcolor={rgb 1 0 0}>30 days net. "
    . "<fillcolor={gray 0}>90 days warranty starting at the day of sale. "
    . "This warranty covers defects in workmanship only. "
    . "Kraxi Systems, Inc. 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.";

class articledata {
    function __construct($name, $price, $quantity) {
	$this->name = $name;
	$this->price = $price;
	$this->quantity = $quantity;
    }
}

$data = array(
    new articledata("Super Kite", 20, 2),
    new articledata("Turbo Flyer", 40, 5),
    new articledata("Giga Trash", 180, 1),
    new articledata("Bare Bone Kit", 50, 3),
    new articledata("Nitty Gritty", 20, 10),
    new articledata("Pretty Dark Flyer", 75, 1),
    new articledata("Free Gift", 0, 1)
);

$headers = array( "ITEM", "DESCRIPTION", "QUANTITY", "PRICE", "AMOUNT" );

$alignments = array( "right", "left", "right", "right", "right" );

$id_sect = 0;
$id_div = 0;

try {
    $p = new pdflib();

    $optlist = "SearchPath=" . $searchpath;
    $p->set_option($optlist);

    /*
     * This mean we don't have to check error return values, but will
     * get an exception in case of runtime problems.
     */
    $p->set_option("errorpolicy=exception");

    /* all strings are expected as utf8*/
    $p->set_option("stringformat=utf8");
    
    /* "autospace" improves Reflow */
    $p->set_option("autospace=true");

    $p->begin_document("",
        "pdfua=PDF/UA-1 pdfa=PDF/A-2a lang=en "
            . "tag={tagname=Document "
            . "Title={Invoice for John Q. Doe - Kraxi Systems, Inc.}}");

    $p->set_info("Creator", "tagged_invoice.php");
    $p->set_info("Author", "Kraxi Systems, Inc.");
    $p->set_info("Title", "Invoice for John Q. Doe - Kraxi Systems, Inc.");

    /* Use sRGB output intent so that we can use RGB color */
    $p->load_iccprofile("sRGB", "usage=outputintent");

    /* Each Div element could contain a separate invoice */
    $id_div = $p->begin_item("Div", "Title={Invoice}");

    /*
     * -----------------------------------
     * Create and place table with article list
     * -----------------------------------
     */
    /* ---------- Header row */
    $row = 1;
    $tbl = 0;

    for ($col = 1; $col <= count($headers); $col++) {
        $optlist = "fittextline={position={" . $alignments[$col - 1]
            . " center} " . $basefontoptions
            . "} margin=2";
        $tbl = $p->add_table_cell($tbl, $col, $row, $headers[$col - 1],
                                    $optlist);
    }
    $row++;

    /* ---------- Data rows: one for each article */
    $total = 0;

    for ($i = 0; $i < count($data); $i++) {
        $sum = $data[$i]->price * $data[$i]->quantity;
        $col = 1;

        /* column 1: ITEM */
        $buf = sprintf("%d", $i + 1);
        $optlist = "fittextline={position={" . $alignments[$col - 1]
            . " center} " . $basefontoptions
            . "} margin=2";
        $tbl = $p->add_table_cell($tbl, $col++, $row, $buf, $optlist);

        /* column 2: DESCRIPTION */
        $optlist = "fittextline={position={" . $alignments[$col - 1]
            . " center} " . $basefontoptions
            . "} colwidth=50% margin=2";
        $tbl = $p->add_table_cell($tbl, $col++, $row, $data[$i]->name,
                                        $optlist);

        /* column 3: QUANTITY */
        $buf = sprintf("%d", $data[$i]->quantity);
        $optlist = "fittextline={position={" . $alignments[$col - 1]
            . " center} " . $basefontoptions
            . "} margin=2";
        $tbl = $p->add_table_cell($tbl, $col++, $row, $buf, $optlist);

        /* column 4: PRICE */
        $buf =  sprintf("%.2f", $data[$i]->price);
        $optlist = "fittextline={position={" . $alignments[$col - 1]
            . " center} " . $basefontoptions
            . "} margin=2";
        $tbl = $p->add_table_cell($tbl, $col++, $row, $buf, $optlist);

        /* column 5: AMOUNT */
        $buf = sprintf("%.2f", $sum);
        $optlist = "fittextline={position={" . $alignments[$col - 1]
            . " center} " . $basefontoptions
            . "} margin=2";
        $tbl = $p->add_table_cell($tbl, $col++, $row, $buf, $optlist);

        $total += $sum;
        $row++;
    }

    /* ---------- Print total in the rightmost column */
    $buf = sprintf("%.2f", $total);
    $optlist = "fittextline={position={"
        . $alignments[count($headers) - 1] . " center} "
        . $basefontoptions . " " . $basetagoptions . "} margin=2";
    $tbl = $p->add_table_cell($tbl, count($headers), $row++, $buf,
                                    $optlist);

    /* ---------- Create invoice header on first page */
    $p->begin_page_ext(0, 0, $pagedimensions);
            
    $id_sect = $p->begin_item("Sect", "Title={Invoice header}");
            
    create_stationery($p);
    create_address($p);
            
    $p->end_item($id_sect);
            
    $id_sect = $p->begin_item("Sect", "Title={Invoice body}");
            
    create_table_header($p, $id_div);

    /*
     * ---------- Place the table instance(s), creating pages as required
     */
    $top = $y_invoice - 3 * $fontsize;
    do {
        /* Place the table on the page; Shade every other row. */
        $optlist = "header=1 fill={{area=rowodd fillcolor={gray 0.9}}} "
            . "tag={tagname=Table Summary={" . $tablesummary . "}}";

        $result = $p->fit_table($tbl, $x_table, $bottom,
            $x_table + $tablewidth, $top, $optlist);

        if ($result == "_error") {
            throw new Exception("Couldn't place table: " . $p->get_errmsg());
        }
        else if ($result == "_boxfull")
        {
        	$p->end_page_ext("");
        	$p->begin_page_ext(0, 0, $pagedimensions);
        	$top = $y_invoice_p2;
        }
    }
    while ($result == "_boxfull");

    /* Determine vertical start point for footer from top of last
     * placed table fragment.
     */
    $table_height = $p->info_table($tbl, "height");
    $top -= $table_height + 2 * $fontsize;
            
    $p->delete_table($tbl, "");
            
    /* ---------- Footer with terms of payment */
    $optlist = $basefontoptions . " alignment=justify leading=120%";
    $tf = $p->create_textflow($closingtext, $optlist);

    /* Loop until all of the text is placed; create new pages
     * as long as more text needs to be placed.
     */
    $id_footer = $p->begin_item("P", "");
    do
    {
        $result = $p->fit_textflow($tf, $x_table, $bottom,
                            $x_table + $tablewidth, $top, "");
    
        /* Start new page if more text is to be placed */
        if ($result == "_boxfull" || $result == "_nextpage")
        {
             $p->end_page_ext("");
             $p->begin_page_ext(0, 0, $pagedimensions);
             $top = $y_invoice_p2;
        }
    } while ($result == "_boxfull" || $result == "_nextpage");
    $p->end_item($id_footer);

    $p->end_item($id_sect);
    $p->end_item($id_div);
            
    $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=tagged_invoice.pdf");
    print $buf;
}
catch (PDFlibException $e) {
    echo("PDFlib exception occurred in tagged_invoice sample:\n" .
        "[" . $e->get_errnum() . "] " . $e->get_apiname() . ": " .
        $e->get_errmsg() . "\n");
    exit(1);
}
catch (Exception $e) {
    echo($e);
    exit(1);
}

$p = 0;

?>