name = $name; $this->price = $price; } }; class addressdata_s { function __construct($firstname, $lastname, $flat, $street, $city) { $this->firstname = $firstname; $this->lastname = $lastname; $this->flat = $flat; $this->street = $street; $this->city = $city; } }; define("MATRIXROWS", 32); define("MATRIXDATASIZE", 4 * MATRIXROWS); define("MAXRECORD", 100); $stationeryfilename = "stationery_pdfx4p.pdf"; $fontname = "LinLibertine_R"; $title = "Starter PDF/VT-2"; /* This is where font/image/PDF input files live. Adjust as necessary. */ $searchpath = dirname(dirname(dirname(__FILE__)))."/input"; $outfile = ""; $left = 55; $right = 530; $bottom = 822; $fontsize = 12; $closingtext = "Terms of payment: 30 days net. " . "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."; $articledata = array( new articledata_s("Super Kite", 20), new articledata_s("Turbo Flyer", 40), new articledata_s("Giga Trash", 180), new articledata_s("Bare Bone Kit", 50), new articledata_s("Nitty Gritty", 20), new articledata_s("Pretty Dark Flyer", 75), new articledata_s("Large Hadron Glider", 85), new articledata_s("Flying Bat", 25), new articledata_s("Simple Dimple", 40), new articledata_s("Mega Sail", 95), new articledata_s("Tiny Tin", 25), new articledata_s("Monster Duck", 275), new articledata_s("Free Gift", 0) ); $addressdata = array( 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") ); $salesrepnames = array( "Charles Ragner", "Hugo Baldwin", "Katie Blomock", "Ernie Bastel", "Lucy Irwin", "Bob Montagnier", "Chuck Hope", "Pierre Richard" ); $headers = array( "ITEM", "DESCRIPTION", "QUANTITY", "PRICE", "AMOUNT" ); $alignments = array( "right", "left", "right", "right", "right" ); $leading = $fontsize + 2; try { $p = new pdflib(); $p->set_option("errorpolicy=return"); $p->set_option("stringformat=utf8"); if ($p->begin_document($outfile, "pdfvt=PDF/VT-2 pdfx=PDF/X-5pg usestransparency=true " . "nodenamelist={root recipient} recordlevel=1") == 0) { throw new Exception("Error: " . $p->get_errmsg()); } $p->set_option("searchpath={" . $searchpath . "}"); $p->set_info("Creator", "PDFlib Cookbook"); $p->set_info("Title", $title); $fontoptions = "fontname=" . $fontname . " fontsize=" . $fontsize . " embedding encoding=unicode"; /* Define output intent profile */ if ($p->load_iccprofile("ISOcoated_v2_eci.icc", "usage=outputintent urls={http://www.color.org}") == 0) { print("Error: " . $p->get_errmsg() . "\n"); print("See www.pdflib.com for ICC profiles.\n"); $p->delete(); exit(1); } /* * ----------------------------------- * Load company stationery as background (used * on first page for each recipient) by reference and * construct proxy for it * ----------------------------------- */ $proxy_stationery = make_proxy($p, $stationeryfilename, "Proxy for stationery"); if ($proxy_stationery == 0) { 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 * ----------------------------------- */ for ($i = 0; $i < count($salesrepnames); $i++) { $description = "Proxy for sales rep image " . $i; $salesrepfilename = "sales_rep" . $i . ".pdf"; $proxy_salesrepimage[$i] = make_proxy($p, $salesrepfilename, $description); if ($proxy_salesrepimage[$i] == 0) { throw new Exception("Proxy error: " . $p->get_errmsg()); } } define("ARTICLECOUNT", count($articledata)); define("ADDRESSCOUNT", count($addressdata)); /* * ----------------------------------- * 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, "recursive=true"); for ($record = 0; $record < MAXRECORD; $record++) { $pagecount = 0; $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, "recursive=true"); # ----------------------------------- # Create and place table with article list # ----------------------------------- # # ---------- Header row $row = 1; $tbl = 0; for ($col=1; $col <= count($headers); $col++) { $optlist = sprintf( "fittextline={position={%s center} %s} margin=2", $alignments[$col-1], $fontoptions); $tbl = $p->add_table_cell($tbl, $col, $row, $headers[$col-1], $optlist); } $row++; # ---------- Data rows: one for each article $total = 0; # ----------------------------------- # Print variable-length article list # ----------------------------------- for ($i = 0, $item = 0; $i < count($articledata); $i++) { $quantity = get_random(9) + 1; if (get_random(2) % 2) { continue; } $col = 1; $item++; $sum = $articledata[$i]->price * $quantity; # column 1: ITEM $buf = sprintf("%d", $item); $optlist = sprintf( "fittextline={position={%s center} %s} colwidth=5%% margin=2", $alignments[$col-1], $fontoptions); $tbl = $p->add_table_cell($tbl, $col++, $row, $buf, $optlist); # column 2: DESCRIPTION $optlist = sprintf( "fittextline={position={%s center} %s} colwidth=50%% " . "margin=2", $alignments[$col-1], $fontoptions); $tbl = $p->add_table_cell($tbl, $col++, $row, $articledata[$i]->name, $optlist); # column 3: QUANTITY $buf = sprintf("%d", $quantity); $optlist = sprintf( "fittextline={position={%s center} %s} margin=2", $alignments[$col-1], $fontoptions); $tbl = $p->add_table_cell($tbl, $col++, $row, $buf, $optlist); # column 4: PRICE $buf = sprintf("%.2f", $articledata[$i]->price); $optlist = sprintf( "fittextline={position={%s center} %s} margin=2", $alignments[$col-1], $fontoptions); $tbl = $p->add_table_cell($tbl, $col++, $row, $buf, $optlist); # column 5: AMOUNT $buf = sprintf("%.2f", $sum); $optlist = sprintf( "fittextline={position={%s center} %s} margin=2", $alignments[$col-1], $fontoptions); $tbl = $p->add_table_cell($tbl, $col++, $row, $buf, $optlist); $total += $sum; $row++; } # ---------- Print total in the rightmost column $buf = sprintf("%.2f", $total); $optlist = sprintf( "fittextline={position={%s center} %s} margin=2", $alignments[count($alignments) - 1], $fontoptions); $tbl = $p->add_table_cell($tbl, count($headers), $row++, $buf, $optlist); # ---------- Footer row with terms of payment $optlist = sprintf("%s alignment=justify leading=120%%", $fontoptions); $tf = $p->create_textflow($closingtext, $optlist); $optlist = sprintf( "rowheight=1 margin=2 margintop=%f textflow=%d colspan=%d", 2*$fontsize, $tf, count($headers)); $tbl = $p->add_table_cell($tbl, 1, $row++, "", $optlist); # ----- Place the table instance(s), creating pages as required do { $p->begin_page_ext(0, 0, "topdown=true width=a4.width height=a4.height"); if (++$pagecount == 1) { # ----------------------------------- # Place company stationery / proxy (template) as background # on the page # ----------------------------------- $p->fit_image($proxy_stationery, 0, 842, ""); # ----------------------------------- # Place name and image of local sales rep on first page # for each recipient # ----------------------------------- $y = 177; $x = 455; $optlist = sprintf( "fontname=%s encoding=winansi embedding fontsize=9", $fontname); $p->fit_textline("Local sales rep:", $x, $y, $optlist); $p->fit_textline( $salesrepnames[$record % count($salesrepnames)], $x, $y+9, $optlist); $y = 280; /* Place the proxy on the page */ $p->fit_image( $proxy_salesrepimage[$record % count($salesrepnames)], $x, $y, "boxsize={90 90} fitmethod=meet"); # ----------------------------------- # Address of recipient # ----------------------------------- $y = 170; $optlist = sprintf( "fontname=%s encoding=winansi embedding fontsize=%f", $fontname, $fontsize); $buf = sprintf("%s %s", $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 = sprintf("%d %s", get_random(999), $addressdata[get_random(ADDRESSCOUNT)]->street); $p->fit_textline($buf, $left, $y, $optlist); $y += $leading; $buf = sprintf("%05d %s", get_random(99999), $addressdata[get_random(ADDRESSCOUNT)]->city); $p->fit_textline($buf, $left, $y, $optlist); # ----------------------------------- # Individual barcode image for each recipient # ----------------------------------- $datamatrix = create_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 == 0) { echo("Error: " . $p->get_errmsg()); exit(1); } $p->fit_image($barcodeimage, 280.0, 200.0, "scale=1.5"); $p->close_image($barcodeimage); $p->delete_pvf("barcode"); # ----------------------------------- # Print header and date # ----------------------------------- date_default_timezone_set('Europe/Berlin'); $y = 300; $buf = sprintf("INVOICE %d-%d", date("Y"), $record+1); $optlist = sprintf( "fontname=%s encoding=winansi embedding fontsize=%d", $fontname, $fontsize); $p->fit_textline($buf, $left, $y, $optlist); # set timezone to avoid PHP warnings $buf = date("F j,Y"); $optlist = sprintf( "fontname=%s encoding=unicode fontsize=%d embedding " . "position {100 0}", $fontname, $fontsize); $p->fit_textline($buf, $right, $y, $optlist); $top = $y + 2*$leading; } else { $top = 50; } # Place the table on the page. # Shade every other row, except the footer row. $result = $p->fit_table($tbl, $left, $bottom, $right, $top, "header=1 " . "fill={{area=rowodd fillcolor={gray 0.9}} " . "{area=rowlast fillcolor={gray 1}}} " . "rowheightdefault=auto colwidthdefault=auto"); if ($result == "_error") { echo("Error when placing table: " . $p->get_errmsg()); exit(1); } $p->end_page_ext(""); } while ($result == "_boxfull"); $p->delete_table($tbl, ""); /* Close node in the document part hierarchy */ $p->end_dpart(""); } /* Close root node in the document part hierarchy */ $p->end_dpart(""); $p->end_document(""); $buf = $p->get_buffer(); $len = strlen($buf); header("Content-type: application/pdf"); header("Content-Length: $len"); header("Content-Disposition: inline; filename=starter_pdfvt2.pdf"); print $buf; } catch (PDFlibException $e) { echo("PDFlib exception occurred in sample:\n" . "[" . $e->get_errnum() . "] " . $e->get_apiname() . ": " . $e->get_errmsg() . "\n"); exit(1); } catch (Exception $e) { echo($e); exit(1); } $p = 0; /* ------------------------------- * 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. */ function make_proxy($p, $targetname, $description) { $linewidth = 2; /* 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 == 0) { 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->set_graphics_option("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(); $fontsize = $width > 550 ? 24.0 : 48.0; $optlist = "fontname=LuciduxSans-Oblique encoding=unicode 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 */ function get_random($n) { return rand(0, $n-1); } /** * Simulate a datamatrix barcode */ function create_datamatrix($record) { $data; $datastring = ""; $i; $x; $d; for ($i=0; $i