blocks/pdfvt1_with_blocks
Create a large number of invoices in a single PDF and make use of PDF/VT-1 features.
Download Java Code Switch to PHP Code Show Output Show Input (stationery_pdfx4p.pdf)
package com.pdflib.cookbook.pdflib.blocks;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.Date;
import java.util.Calendar;
import java.util.Locale;
import java.util.Random;
import com.pdflib.pdflib;
import com.pdflib.PDFlibException;
/**
* Create PDF/VT-1 with Blocks
*
* Create a large number of invoices in a single PDF and make use of
* the following PDF/VT-1 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
*
* This topic is similar to starter_pdfvt1, but it uses PDFlib Blocks to
* place various text and image items on the page.
*
* Required software: PPS 10
* Required data: PDF background, fonts, several raster images
*/
public class pdfvt1_with_blocks {
final static Random random = new Random();
static class articledata_s {
articledata_s(String name, double price) {
this.name = name;
this.price = price;
}
String name;
double price;
};
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, stationery, page;
int record;
int barcodeimage;
String stationeryfilename = "stationery_pdfx4p.pdf";
String fontname = "NotoSerif-Regular";
/*
* This is where font/image/PDF input files live. Adjust as necessary.
*/
String searchpath = "../input";
/* By default annotations are also imported. In some cases this
* requires the Noto fonts for creating annotation appearance streams.
* We therefore set the searchpath to also point to the font directory.
*/
String fontpath = "../resource/font";
String title = "Create PDF/VT-1 with Blocks";
String outfile = "pdfvt1_with_blocks.pdf";
double left = 55;
double right = 530;
double bottom = 822;
double fontsize = 11;
String buf;
String optlist;
String fontoptions;
String closingtext = "Terms of payment: <save fillcolor={cmyk 0 1 1 0}>30 days net<restore>. "
+ "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_s articledata[] = { 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_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 salesrepimage[] = new int[salesrepnames.length];
String[] headers = { "ITEM", "DESCRIPTION", "QUANTITY", "PRICE",
"AMOUNT" };
String[] alignments = { "right", "left", "right", "right", "right" };
int dpm = 0, cip4_root, cip4_metadata;
int exitcode = 0;
double leading = fontsize + 2;
pdflib p = null;
try {
p = new pdflib();
if (p.begin_document(outfile,
"pdfx=PDF/X-4 pdfvt=PDF/VT-1 usestransparency=false "
+ "nodenamelist={root recipient} recordlevel=1") == -1) {
throw new Exception("Error: " + p.get_errmsg());
}
/*
* Set errorpolicy to return, this means we must check return values
* of load_font() etc. Set the search path for fonts and images etc.
*/
p.set_option("errorpolicy=return SearchPath={" + searchpath + "}");
p.set_option("SearchPath={" + fontpath + "}");
p.set_info("Creator", "PDFlib Cookbook");
p.set_info("Title", title);
fontoptions = "fontname=" + fontname + " fontsize=" + fontsize;
/* Define output intent profile */
if (p.load_iccprofile("ISOcoated_v2_eci.icc",
"usage=outputintent") == -1) {
System.err.println("Error: " + p.get_errmsg());
System.err.println("See www.pdflib.com for ICC profiles.");
p.delete();
System.exit(2);
}
/*
* Load company stationery as background (used on first page for
* each recipient)
*/
stationery = p.open_pdi_document(stationeryfilename, "");
if (stationery == -1) {
throw new Exception("Error: " + p.get_errmsg());
}
page = p.open_pdi_page(stationery, 1,
"pdfvt={scope=global environment={Kraxi Systems}}");
if (page == -1) {
throw new Exception("Error: " + p.get_errmsg());
}
/*
* Preload images of all local sales reps (used on first page
* for each recipient). To get encapsulated image XObjects, the
* renderingintent option is used.
*/
for (i = 0; i < salesrepnames.length; i++) {
String salesrepfilename = "sales_rep" + i + ".jpg";
salesrepimage[i] = p.load_image("auto", salesrepfilename,
"pdfvt={scope=file} renderingintent=Perceptual");
if (salesrepimage[i] == -1) {
throw new Exception("Error: " + p.get_errmsg());
}
}
final int ARTICLECOUNT = articledata.length;
final int ADDRESSCOUNT = addressdata.length;
final int COLUMNCOUNT = headers.length;
final int SALESREPS = salesrepnames.length;
/*
* Construct DPM metadata for the DPart root node
*/
cip4_metadata = p.poca_new("containertype=dict usage=dpm");
p.poca_insert(cip4_metadata,
"type=string key=CIP4_Conformance value=base");
p.poca_insert(cip4_metadata,
"type=string key=CIP4_Creator value=pdfvt1_with_blocks");
p.poca_insert(cip4_metadata,
"type=string key=CIP4_JobID value={Kraxi Systems invoice}");
optlist = "containertype=dict usage=dpm "
+ "type=dict key=CIP4_Metadata value=" + cip4_metadata;
cip4_root = p.poca_new(optlist);
optlist = "containertype=dict usage=dpm "
+ "type=dict key=CIP4_Root value=" + cip4_root;
dpm = p.poca_new(optlist);
/* Create root node in the DPart hierarchy and add DPM metadata */
optlist = "dpm=" + dpm;
p.begin_dpart(optlist);
p.poca_delete(dpm, "recursive=true");
DecimalFormat zip_code_format = new DecimalFormat("00000");
NumberFormat priceFormat = NumberFormat.getInstance(Locale.US);
priceFormat.setMaximumFractionDigits(2);
priceFormat.setMinimumFractionDigits(2);
for (record = 0; record < MAXRECORD; record++) {
byte datamatrix[] = new byte[MATRIXDATASIZE];
int cip4_recipient, cip4_contact, cip4_person;
String firstname, lastname, result;
int pagecount = 0;
int item;
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 */
int row = 1, col;
int tbl = -1;
for (col = 1; col <= COLUMNCOUNT; col++) {
optlist = "fittextline={position={" + alignments[col - 1]
+ " center} " + fontoptions + "} margin=2";
tbl = p.add_table_cell(tbl, col, row, headers[col - 1],
optlist);
if (tbl == -1) {
throw new Exception("Error: " + p.get_errmsg());
}
}
row++;
/* Data rows: one for each article */
double total = 0;
/*
* Print variable-length article list
*/
for (i = 0, item = 0; i < ARTICLECOUNT; i++) {
int quantity = get_random(9) + 1;
double sum;
if (item > 0 && get_random(100) > 50)
continue;
col = 1;
item++;
sum = articledata[i].price * quantity;
/* column 1: ITEM */
buf = "" + item;
optlist = "fittextline={position={" + alignments[col - 1]
+ " center} " + fontoptions + "} colwidth=5% margin=2";
tbl = p.add_table_cell(tbl, col++, row, buf, optlist);
if (tbl == -1) {
throw new Exception("Error: " + p.get_errmsg());
}
/* column 2: DESCRIPTION */
optlist = "fittextline={position={" + alignments[col - 1]
+ " center} " + fontoptions + "} colwidth=50% margin=2";
tbl = p.add_table_cell(tbl, col++, row, articledata[i].name,
optlist);
if (tbl == -1) {
throw new Exception("Error: " + p.get_errmsg());
}
/* column 3: QUANTITY */
buf = "" + quantity;
optlist = "fittextline={position={" + alignments[col - 1]
+ " center} " + fontoptions + "} margin=2";
tbl = p.add_table_cell(tbl, col++, row, buf, optlist);
if (tbl == -1) {
throw new Exception("Error: " + p.get_errmsg());
}
/* column 4: PRICE */
buf = priceFormat.format(articledata[i].price);
optlist = "fittextline={position={" + alignments[col - 1]
+ " center} " + fontoptions + "} margin=2";
tbl = p.add_table_cell(tbl, col++, row, buf, optlist);
if (tbl == -1) {
throw new Exception("Error: " + p.get_errmsg());
}
/* column 5: AMOUNT */
buf = priceFormat.format(sum);
optlist = "fittextline={position={" + alignments[col - 1]
+ " center} " + fontoptions + "} margin=2";
tbl = p.add_table_cell(tbl, col++, row, buf, optlist);
if (tbl == -1) {
throw new Exception("Error: " + p.get_errmsg());
}
total += sum;
row++;
}
/* Print total in the rightmost column */
buf = priceFormat.format(total);
optlist = "fittextline={position={"
+ alignments[COLUMNCOUNT - 1] + " center} " + fontoptions
+ "} margin=2";
tbl = p.add_table_cell(tbl, COLUMNCOUNT, row++, buf, optlist);
if (tbl == -1) {
throw new Exception("Error: " + p.get_errmsg());
}
/* Footer row with terms of payment */
optlist = fontoptions + " alignment=justify leading=120%";
int tf = p.create_textflow(closingtext, optlist);
if (tf == -1) {
throw new Exception("Error: " + p.get_errmsg());
}
optlist = "rowheight=1 margin=2 margintop=" + 2 * fontsize
+ " textflow=" + tf + " colspan=" + COLUMNCOUNT;
tbl = p.add_table_cell(tbl, 1, row++, "", optlist);
if (tbl == -1) {
throw new Exception("Error: " + p.get_errmsg());
}
/* Place the table instance(s), creating pages as required */
do {
double top = 100; // estimate value
p.begin_page_ext(0, 0,
"topdown=true width=a4.width height=a4.height");
if (++pagecount == 1) {
/*
* Place company stationery as background on first page
* for each recipient
*/
p.fit_pdi_page(page, 0, 842, "");
/*
* Fill Blocks with name and image of local sales rep on
* first page for each recipient
*/
optlist = "";
buf = "Local sales rep:" + "\n"
+ salesrepnames[record % SALESREPS];
if (p.fill_textblock(page, "salesrepname", buf,
optlist) == -1)
System.err.println("Warning: " + p.get_errmsg());
if (p.fill_imageblock(page, "salesrepimage",
salesrepimage[record % SALESREPS], "") == -1)
System.err.println("Warning: " + p.get_errmsg());
/*
* Fill Text Blocks with recipient's address
*/
optlist = "";
buf = firstname + " " + lastname;
if (p.fill_textblock(page, "name", buf, optlist) == -1)
System.err.println("Warning: " + p.get_errmsg());
buf = addressdata[get_random(ADDRESSCOUNT)].flat;
if (p.fill_textblock(page, "flat", buf, optlist) == -1)
System.err.println("Warning: " + p.get_errmsg());
buf = get_random(999) + " "
+ addressdata[get_random(ADDRESSCOUNT)].street;
if (p.fill_textblock(page, "street", buf,
optlist) == -1)
System.err.println("Warning: " + p.get_errmsg());
buf = zip_code_format.format(get_random(99999)) + " "
+ addressdata[get_random(ADDRESSCOUNT)].city;
if (p.fill_textblock(page, "city", buf, optlist) == -1)
System.err.println("Warning: " + p.get_errmsg());
/*
* Fill image Block with barcode image for each
* recipient. To get encapsulated image XObjects the
* renderingintent option is used.
*/
create_datamatrix(datamatrix, record);
p.create_pvf("barcode", datamatrix, "");
barcodeimage = p.load_image("raw", "barcode",
"bpc=1 components=1 width=32 height=32 invert "
+ "pdfvt={scope=singleuse} "
+ "renderingintent=Saturation");
if (barcodeimage == -1) {
throw new Exception("Error: " + p.get_errmsg());
}
if (p.fill_imageblock(page, "barcode", barcodeimage,
"") == -1)
System.err.println("Warning: " + p.get_errmsg());
p.close_image(barcodeimage);
p.delete_pvf("barcode");
/*
* Fill Text Blocks with header and date
*/
optlist = "";
buf = "INVOICE "
+ Calendar.getInstance().get(Calendar.YEAR) + "-"
+ (record + 1);
if (p.fill_textblock(page, "invoice_number", buf,
optlist) == -1)
System.err.println("Warning: " + p.get_errmsg());
buf = DateFormat
.getDateInstance(DateFormat.LONG, Locale.US)
.format(new Date());
if (p.fill_textblock(page, "date", buf, optlist) == -1)
System.err.println("Warning: " + p.get_errmsg());
/*
* Retrieve y coordinate of the lowest Block
* "invoice_number" so that we know where subsequent
* data can be placed.
*/
top = p.pcos_get_number(stationery,
"pages[0]/blocks/invoice_number/Rect[1]");
// adjust for topdown coordinate system
top = 842 - top + 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.equals("_error")) {
throw new Exception(
"Couldn't place table: " + p.get_errmsg());
}
p.end_page_ext("");
}
while (result.equals("_boxfull"));
p.delete_table(tbl, "");
/* Close node in the document part hierarchy */
p.end_dpart("");
}
p.close_pdi_page(page);
p.close_pdi_document(stationery);
for (i = 0; i < salesrepnames.length; i++) {
p.close_image(salesrepimage[i]);
}
/* Close root node in the document part hierarchy */
p.end_dpart("");
p.end_document("");
}
catch (PDFlibException e) {
System.err.println(
"PDFlib exception occurred in pdfvt1_with_blocks sample:");
System.err.println("[" + e.get_errnum() + "] " + e.get_apiname()
+ ": " + e.get_errmsg());
exitcode = 1;
}
catch (Exception e) {
System.err.println(e);
exitcode = 1;
}
finally {
if (p != null) {
p.delete();
}
System.exit(exitcode);
}
}
/**
* Get a pseudo random number between 0 and n-1.
* For internal reasons we use our own simplistic random number generator.
*/
static long seed = 0x1234;
static int get_random(int n)
{
seed = ((seed * 0xDEECE66D) + 11) & 0x7FFFFFFF;
return (int) (seed % 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;
}
}
}