#!/usr/bin/perl -w # # Example 12-4. Use the PDF::API2 module to generate columns of # text for printing names and addresses on labels. # # Usage: perl example12-4.pl ./labels.xml # use strict; use PDF::API2; # Used to generate the PDF output use XML::Simple; # Used to parse the XML input my %font = (); # A hash holding plain and bold font styles my ($rows, $columns) = (11,3); # Size of each label is calculated my ($hspace, $vspace) = (6, 0); # Space between columns and rows my ($tmargin, $bmargin, # The margins of the page $lmargin, $rmargin) = (36, 36, 36, 36); my ($width, $height) = (612, 792); # Dimensions of page my $print_grid_lines = 1; # If true, print grid lines # Calculate the width and height of each label my $colwidth = ($width-$lmargin-$rmargin- ($columns-1)*$hspace)/$columns; my $rowheight = ($height-$tmargin-$bmargin- ($rows-1)*$vspace)/$rows; # Create a new top-level PDF document # and initialize the font objects for later use my $pdf=PDF::API2->new; $font{'plain'} = $pdf->corefont('Helvetica',1); $font{'bold'} = $pdf->corefont('Helvetica-Bold',1); foreach (keys(%font)) { $font{$_}->encode('latin1'); } # Create a new simple XML parser. # XML::Simple only implements two functions: XMLin and XMLout. my $parser = new XML::Simple(); my $data = $parser->XMLin($ARGV[0]); my @labels = dereference($data->{'label'}); my ($page, $text, $label); # Each element of @labels is a reference to a hash containing # the parsed content of each name and address PAGE: while (@labels) { $page=$pdf->page(); # Add a new page $page->mediabox($width, $height); # Set the dimensions # Add a new graphic state element to be used if # $draw_grid_lines is true. my $g = $page->gfx(); $g->strokecolor("#FF0000"); if ($print_grid_lines) { # Draw the bounding box $g->rect($lmargin, $bmargin, $width-$lmargin-$rmargin, $height-$tmargin-$bmargin); $g->stroke(); $g->endpath(); } # Add a text block that holds all of the text on the page $text=$page->text(); # Loop through the columns foreach my $c (0..$columns-1) { my $x = $lmargin + $c * ($colwidth + $hspace); if ($print_grid_lines && ($c>0)) { # Print a vertical grid line $g->move($x, 0); $g->line($x, $height); $g->move($x-$hspace, 0); $g->line($x-$hspace, $height); $g->stroke; $g->endpath(); } # Loop through the rows foreach my $r (0..$rows-1) { my $y = $height - $tmargin - $r * ($rowheight + $vspace); if ($print_grid_lines && ($r > 0)) { # Print two horizontal grid lines $g->move(0, $y); $g->line($width, $y); $g->move(0, $y+$vspace); $g->line($width, $y+$vspace); $g->stroke; $g->endpath(); } # Add three lines: fullname, address, and city/state/zip $text->translate($x+6, $y-16); my $label = shift(@labels); $text->font($font{'bold'},10); $text->text($label->{'fullname'}); $text->cr(-16); $text->font($font{'plain'},10); $text->text($label->{'address'}); $text->cr(-16); $text->text("$label->{'city'} $label->{'state'} ". "$label->{'zip'}"); unless (@labels) { last PAGE; # Jump out if no more labels } } } } print $pdf->stringify(); # Print the object as a string $pdf->end; exit; sub dereference { # We need this function if the input XML has only one element. # If the parameter is an array reference, de-reference # and return it. Otherwise return the parameter unchanged my $ref = shift; if (ref($ref) eq 'ARRAY') { return (@$ref); } else { return ($ref); } }