http://qs1969.pair.com?node_id=414788

Oh, well, this is just another rewrite of a program that outputs commercial labels as PDF files, but could be usefull, and stills cool. Hope somebuddy here enjoys it...

Update: Added doc item "PURPOSE" so potential users could understand why this module was written before trying it; Corrected the example datafile name from "data" to "data.txt"

OK, enough talk. To the code:

################################################## package Tag::Builder; ################################################## use strict; use PDF::API2; use base 'Class::Accessor'; use constant UNIT => 2.83462; # Revision control; $__PACKAGE__::VERSION = '0.01'; # Accessor methods __PACKAGE__->mk_accessors( qw( page tag data colwidth rowheight pdf font printGridLines ) ); sub new{ my ( $class, $page, $tag, $data ) = ( shift, shift, shift, shift ); my $self = bless { page => $page, tag => $tag, data => $data }, $class; # Convert between metric system and PDF measurement system. map { $self->page->{$_} = $self->page->{$_} * UNIT } keys %{$self->page}; $self->tag->{vspace} *= UNIT; $self->tag->{hspace} *= UNIT; # Calculate tag dimension $self->recalculateTagDimensions; # Create a new PDF aggregate object. $self->pdf( new PDF::API2 ); ## Font handling $self->font( {} ); $self->font->{plain} = $self->pdf->corefont( 'Helvetica', 1 ); $self->font->{bold} = $self->pdf->corefont( 'Helvetica-Bold', 1 ); map $_->encode( 'latin1' ), values %{ $self->font }; # Set to true to ask module to print grid lines. # Setted to false is default, we don't need grid # lines (this is a tag sheet, not a common paper # sheet) $self->printGridLines( undef ); return $self; } sub recalculateTagDimensions{ my $self = shift; # Calculates the column width. $self->colwidth( ( $self->page->{width} - $self->page->{leftmargin} - $self->page->{rightmargin} - ( $self->tag->{columns} - 1 ) * $self->tag->{hspace} ) / $self->tag->{columns} ); # Calculates the row height $self->rowheight( ( $self->page->{height} - $self->page->{topmargin} - $self->page->{bottommargin} - ( $self->tag->{rows} - 1 ) * $self->tag->{vspace} ) / $self->tag->{rows} ); ## Debug # print STDERR "Calculados: ", # $self->tag->{rows} . " linhas X " . $self->tag->{columns} . # "colunas, com largura " . $self->colwidth . # " e altura ". $self->rowheight . "\n"; return $self; } sub genTagFile{ my $self = shift; my $page; PAGE: while( @{ $self->data } ){ # Create a new page $page = $self->pdf->page; # Set page dimensions $page->mediabox( $self->page->{width}, $self->page->{height} ); # Get the page's graphic state element my $graphic = $page->gfx; $graphic->strokecolor( "#CCCCCC" ); if ( $self->printGridLines ) { $graphic->rect( $self->page->{leftmargin}, # Upper-left X $self->page->{bottommargin}, # Upper-left Y $self->page->{width} - $self->page->{leftmargin} - $self->page->{rightmargin}, # Lower-right X $self->page->{height} - $self->page->{topmargin} - $self->page->{bottommargin} # Lower-right Y ); $graphic->stroke; $graphic->endpath; } # Add a text block to hold all text on this page. my $text = $page->text; # Loop trought the columns foreach my $c ( 0..$self->tag->{columns}-1 ) { # Calculate the distance of this column from the page border my $x = $self->page->{leftmargin} + $c * ( $self->colwidth + $self->tag->{hspace} ); # Trace vertical grid lines if ( ($c > 0) && $self->printGridLines ) { $graphic->move( $x, 0 ); $graphic->line( $x, $self->page->{height} ); $graphic->move( $x - $self->tag->{hspace}, 0 ); $graphic->line( $x - $self->tag->{hspace}, $self->page->{height} ); $graphic->stroke; $graphic->endpath; } # Loop trought the rows foreach my $r ( 0..$self->tag->{rows}-1 ) { # Calculate the distance of this row from the top margin my $y = $self->page->{height} - $self->page->{topmargin} - $r * ( $self->rowheight + $self->tag->{vspace} ); # Trace horizontal grid lines if ( ($c > 0) && $self->printGridLines ) { $graphic->move( 0, $y ); $graphic->line( $self->page->{width}, $y ); $graphic->move( 0, $y + $self->tag->{vspace} ); $graphic->line( $self->page->{width}, $y + $self->tag->{vspace} ); $graphic->stroke; $graphic->endpath; } # Add text lines $text->translate( $x + 6, $y - 16 ); # Address the next recipient using the row and column counters my $label = shift @{$self->data}; # Write the tag text... $text->font( $self->font->{'bold'}, 10 ); $text->text( $label->{'name'} ); $text->cr( -16 ); $text->font( $self->font->{'plain'}, 10 ); $text->text( $label->{'address'} ); $text->cr( -16 ); $text->text( $label->{zipcode} ); unless( $label ){ last PAGE; } } # foreach row } # foreach column } # PAGE: while... } #sub sub asString{ my $self = shift; $self->genTagFile; return $self->pdf->stringify; } sub writeFile{ my ( $self, $filename ) = ( shift, shift ); die "File exists, covardly refusing overwrite it.\n" if -f $filename; $self->genTagFile; open PDF, '>', $filename or die $!; print PDF $self->pdf->stringify; close PDF or die $!; return $self; } 1;################################################ __END__ =pod =head1 Tag::Builder - Commercial tag in PDF for printing. =over 4 =item NAME Tag::Builder - A commercial PDF-based tag builder module. =item SYNOPSIS use Tag::Builder; my ( $page, $tag, $data ) = ( { width => 210, height => 297, topmargin => 36, bottommargin => 36, leftmargin => 36, rightmargin => 36 }, { rows => 11, columns => 3, hspace => 6, vspace => 0 }, [ { name => "J. Nobody", address => "Nowhere st, 1, Nothing Hill", zipcode => "NT0304 - London, UK" }, { name => "T. Buddy", address => "Somewhere st, 120, Nowhere Valley", zipcode => "04321-098 - San Diego, US" }, ] ); my $tbuilder = new Tag::Builder( $page, $tag, $data ); $tbuilder->writeFile( "/path/to/file.pdf" ); or $pdf_file = $tbuilder->asString; =item DESCRIPTION Tag::Builder gets some postal address info and build a printable PDF file with tags for each postal address record given. =item OPTIONS =over 4 =item printGridLines When setted to true (see printGridLines() accessor, below), asks the module tio print grid lines when generating the tag sheets. false (off) is the default, as we expect no-one will desire grid lines on a label sheet at all. This serves for debugging purposes mainly. =item METHODS =over 4 =item new() Constructor. Needs three parameters: =over 4 =item * Page Specification This is just a hash reference holding values for the following keys: =over 4 =item ** width This is the page width, in milimeters. =item ** height This is the page height in milimeters. =item ** topmargin The distance from the top of the page to the top margin, in milimeters. =item ** bottommargin The distance from the bottom of the page to the bottom margin, in milimeters. =item ** leftmargin The distance from the left of the page to the left margin, in milimeters. =item ** rightmargin The distance from the right of the page to the right margin, in milimeters. =back =item * Tag Specification The tag specification is just another hash reference, with the following keys: =over 4 =item ** rows Tells the number of tags we have on a row. Must be greather than zero. =item ** columns Tells the number of tags we have on a column. Must be greather than zero. =item ** hspace This is the horizontal distance between adjacent tags, in milimeters. =item ** vspace This is the vertical distance between adjacent tags, in milimeters. =back =item * Address Book The address book is just an array reference with the necessary data to fill in the tags. You can pass as many hash references as you need to into this array reference. The hash reference fields needed to fill in the tags are "name", "address" and "zipcode": =over 4 =item ** name This is the name of the recipient of the mail this tag is for. =item ** address This is the address of the recipient of the mail this tag is for. =item ** zipcode This field englobes city, state, country and zipcode, all in one string. =back =back =item recalculateTagDimensions() This method recalculate tag dimensions, so you can "resize" your tag after creating the object and force a recalculation. =item writeFile() This method creates a PDF file containing the requested tags. You must pass in a filename, as a parameter. This method die()s if there is something wrong during the PDF File creation. =item genTagFile() This method is responsible for the tag rendering. You shall call it everytime you change any tag parameter the tag data. =item asString() This method calls genTagFile() for you, and returns a scalar value containing a string representation of the generated PDF file. Use this while generating tags from a web server, so you don't need to touch the disk nor write files just for sending the contents trought the web. =item printGridLines() Accessor method to the printGridLines option. =back =item EXAMPLE ################################################## # "tag.pl" - uses Tag::Builder ################################################## #!/usr/bin/perl use strict; use warnings; use lib '/home/champs/src/lib'; use Tag::Builder; my $data = do './data.txt'; my $builder = new Tag::Builder( { width => 210, height => 297, topmargin => 20, bottommargin => 25, leftmargin => 25, rightmargin => 20 }, { rows => 6, columns => 3, hspace => 1, vspace => 1 }, $data ); $builder->writeFile( 'test.pdf' ); __END__ ################################################## # data.txt - data file ################################################## [ { name => "J. Nobody", address => "Nowhere st, 1", zipcode => "NT0 304 - London, UK" }, { name => "T. Buddy", address => "Somewhere st, 120", zipcode => "04321-098 - San Diego, US" }, ] #EOF =item KNOW BUGS =over 4 =item Bug0001 I don't know why I need to multiply distance values in milimeters by the UNIT constant so they actualy are rendered in milimeters. =back =item TODO LIST =over 4 =item * Allow user to choose font and font size; =item * Incorporate Avery Standard tag specifications; =item * Allow user to specify tag and page by names; =back =item REVISION HISTORY =item PURPOSE This module just takes over all calculation and (basic) diagramation effort needed to generate address labels by hand... its just a reproductible add-on functionality to programs. =item AUTHOR Luis Campos de Carvalho - [monsieur_champs AT yahoo DOT com DOT br] =back =cut

2005-01-10 Janitored by Arunbear - added readmore tags, as per Monastery guidelines