The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

NAME

PostScript::MailLabels - Modules for creating PostScript files of mailing address labels, to be printed on standard adhesive-backed mailing label stock.

SYNOPSIS

Create PostScript(tm) code for calibrating and testing mailing label printing, and finally create the code for the labels themselves.

DESCRIPTION

The module has three distinct output modes. In my experience, printing mailing labels is a matter of tweaking parameters to get them all to fit properly on the page. This module is designed with this in mind.

The first output is the calibration sheet. This is a pair of annotated axes, either in inches or centimeters, centered on the page and covering the whole page in X and Y directions. The intent is for you to output this page first, and simply read off the relevant page dimensions directly.

The second output is the label test. This output is a series of boxes drawn on the page, meant to outline the edges of all the mailing labels. Take this sheet and line it up with a sheet of labels to see if they actually match perfectly. If not, tweak the parameters until they do. Note that sometimes you will get a message at the bottom of the sheet saying "Bottom gap too large, last row cannot be printed". This means that the printable area of your printer is too small to utilize the last row of labels. I have this problem. But I handle it for you. Note also the arrows on the test sheet. As you hold the test sheet over a sheet of labels, hold it up to the light and slide the test sheet so that the boxes match the edges of the labels. If you slide in the arrow direction, that is a positive adjustment. The other direction is negative. If the edges of some boxes come out dashed, that means that the non-printing border cuts off the end of the label, so I will adjust the printing area appropriately. Don't try to line up the dashed lines with label edges - it won't work. Just line up the solid lines.

The third output is the labels themselves. The addresses must be given to the program already broken up into :

    firstname, lastname, street address, city, state, zipcode

Yes, this is US-centric. If you would like to help me open this up to print labels using non-US address standards, let me know. I'm happy to do it, I just don't know what the standards ought to be.

Parameters you can set :

Paper size, borders on the printable area (many printers will not print right up to the edge of the paper), where the labels live on the page and how big they are, overall x-y shift of page, whether or not to print PostNET barcode, font, fontsize, units (english or metric), which Avery (tm) product code to use, and where the first label starts.

This last needs explanation. If you have a partially used sheet of labels, you might want to use it up. So you count the missing labels, starting at the upper left, and counting across, and then down. For example, if I have 3 columns of labels, label five is the second label in the second row.

The Avery(tm) label codes are woefully incomplete. I can't find the Avery(tm) specs anywhere, so the ones that are in there are for products I personally own. I e-mailed Avery(tm) and they gave me a long distance phone number to call.

If you have an Avery(tm) product that I haven't defined, send me the specs and I'll add it.

Also, if there is another brand of labels that you use, send me the relevant data and I'll add that as well. I suspect that there must be some other vendor in Europe, but I don't know who that would be.

When setting up the addresses, I check to see if they will fit on the label. If not, I try to shorten them semi-intelligently until they fit. This part could use quite a bit more work, if done right it probably merits a module all it's own.

Briefly, for the name line, I start trimming the ends off the first name, and leave the last name alone.

For the street, I look for things like Road or Avenue and nuke those first, then I trim the street name from the right.

For the last line, I trim the city and leave the state and zip alone.

The barcode will be either a 5-digit zip or 9 digit zip-plus code. I could also create the delivery point code, but since my mailing labels are not even wide enough for the 9 digit zip-plus, I haven't bothered. I have read the USPS spec on the barcode, and so far as I can tell, I meet the spec.

    labelsetup :
    
    my $setup = $labels -> labelsetup( 

        #    paper size

        PaperSize        => 'Letter',
            
        #    printable area on physical page

        Printable_Left        => 0.0,
        Printable_Right        => 0.0,
        Printable_Top        => 0.0,
        Printable_Bot        => 0.0,

        #    define where the labels live (ideally)

        Output_Top        => 0.0, 
        Output_Left        => 0.0, 
        Output_Width    => 0.0, 
        Output_Height    => 0.0, 
        X_Gap            => 0.0,
        Y_Gap            => 0.0,
        Number            => 0,

        #    Adjustments for printer idiosyncracies

        X_Adjust        => 0.0,
        Y_Adjust        => 0.0,

        #    Other controls

        Postnet        => 'yes',
        Font        => 'Helvetica',
        FontSize     => 12,
        Units        => 'english',
        FirstLabel    => 1,

        # set equal to the Avery(tm) product code, and the label description
        # will be updated from the database.
        Avery        => undef,
        );

    $output = $labels->labelcalibration ;
    $output = $labels->labeltest ;
    $output = $labels->makelabels(\@addrs) ;
    $templatecode = $labels->averycode($product_code) ;
    @width_height = @{ $labels->papersize } ;
    $stringwidth = $labels->stringwidth("This is a string") ;
    @fontname = $labels->ListFonts;

EXAMPLE

  require PostScript::MailLabels;

  $labels = PostScript::MailLabels->new;

  #    -------- first a few utility functions that are available
    
    #       List the available fonts

  @fonts = $labels->ListFonts;
  foreach (@fonts) {
    print "$_\n";
  }

  print "String width of this is a test = ", 
        $labels->stringwidth("this is a test",)/72,"\n";
    my $setup = $labels -> labelsetup( Font => 'PostNetJHC');
    print "zip code tests, 6,9, and 12 digit lengths barcodes:  ", 
        $labels->stringwidth("123456",)/72," : ",
        $labels->stringwidth("123456789",)/72," : ",
        $labels->stringwidth("123456789012",)/72,
        "\n";

    print "Paper size = ",($labels->papersize)->[0]," x ",
                      ($labels->papersize)->[1],"\n";


    # print the Avery(tm) template code for a given product code

  print "Avery(tm) code for 8196 is >",$labels->averycode(8196),"<\n";

      # set up the basic parameters for the labels

  $labels -> labelsetup(
                    Avery        => '5196',
                    PaperSize     => 'A4',
                    Font        => 'Times-Roman',
                    );

    #--------- okay, let's get serious now and create some test sheets


    #    paper and label description so far
  $labels -> labelsetup(
                Units => 'english',
                PaperSize => 'letter',
                Avery => undef, # turn off previous definition
  );

    # create a calibration sheet
  my $output = $labels->labelcalibration;
  `lpr < $output`;

    # create a test sheet

  $labels -> labelsetup( 
          # page setup - where is printing allowed? (border widths)
        Printable_Left   => 0.25,
        Printable_Right  => 0.25,
        Printable_Top    => 0.05,
        Printable_Bot    => 0.6,

        # Label description

            # top of first label is 0.5 inches from top of page
        Output_Top      => 0.5, 
            # each label is 2.625 inches wide
        Output_Width    => 2.625, 
            # each label is 1.0 inches high
        Output_Height   => 1.0, 
            # there is a 0.16 inch gap between labels in the X direction
        X_Gap           => 0.16,
            # there is no gap between labels in the Y direction
        Y_Gap           => 0.0,
            # there are 30 labels on a page
        Number           => 30,

        #    Adjustments for printer idiosyncracies

            # shift the whole page 0.05 inches right
        X_Adjust        => 0.05,
            # shift the whole page 0.05 inches down
        Y_Adjust        => 0.05,

                       );
    #    Create and print a label test sheet

  $output = $labels->labeltest;
  `lpr < $output`;

      #    Everything looks good, let's print some labels!

    @addresses = magic; # I magically populate my address array. 8-)

    #    each element of the array is an array of 
    #   first,last,street_addr,city,state,zip

    $labels -> (  Font       => 'Helvetica',
                  FontSize   => 12,
                  FirstLabel => 7,
                  Postnet    => 'yes',
               );
    
    $output = $labels->makelabels(\@addresses);
    `lpr < $output`;

AUTHOR

    Alan Jackson
    October 1999
    alan@ajackson.org

    The PostNET font was gotten (under Gnu copyleft) from
    James H. Cloos, Jr. <cloos@jhcloos.com>

    The font metrics and paper sizes were pulled from the
    PostScript::Metrics module written by Shawn Wallace