From: aa736@cleveland.Freenet.Edu (Bob Blum)
Subject: Re: bar codes
Organization: Case Western Reserve University, Cleveland, Ohio, (USA)
Date: Wed, 29 Jul 92 15:56:40 GMT


These are some Postal Bar Code Postcript programs I found
--------------------------------------------------------------

%!PS PostalBarCode.PS
 
% Postscript program to address a business-size envelope in accordance
% with US Postal Service guidelines, including the 52-bit POSTNET barcode.
% Use of this program can help your mail arrive up to 2 days faster!
% Note: A barcode will only be printed if the last word of the last line of
% 	the address is a 9-digit zipcode.
 
% by Tod McQuillin
% tm1d@nike.cheme.cmu.edu
% 10-Oct-1991
% Copyright (C) 1991 Tod McQuillin
 
% This program is free software; you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation; either version 1, or (at your option)
% any later version.
 
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU General Public License for more details.
 
/inch {72 mul} def
/cm {inch 2.54 div} def
 
% LWIDTH and LHEIGHT define letter size paper.  The envelope will be printed
% centered in this area, flush with the top of the page.  This works great
% with a HP III printer; your mileage may vary
/LWIDTH 8.5 inch def
/LHEIGHT 11 inch def
 
% EHEIGHT and EWIDTH define the com10 size envelope.  They're supposed to be
% 9.5 x 4.25 inches, but the ones I had were only 10.5 cm tall.  Change these
% values to suit your envelopes -- the program will work with any envelopes
% provided these values are set appropriately.
/EHEIGHT 10.5 cm def
/EWIDTH 9.5 inch def
 
/interline {	 	% define default leading
  POINTSIZE 1.2 mul
  } def
 
/fontset {		% fontname pointsize => -
  exch findfont exch dup /POINTSIZE exch def scalefont setfont
  } def
 
/defleading {		% define leading for nl
  /LEADING interline def
  } def
 
/nl {			% print string and move to start of next line
  dup stringwidth pop exch show neg LEADING neg rmoveto
  } def
 
/addressfont {		% set font for address
/Helvetica 16 fontset defleading
  } def
 
/returnfont {		% set font for return address
  /Helvetica 12 fontset defleading
  } def
 
/envelope {		% translate and rotate coordinate system to match com10
  LWIDTH EHEIGHT sub 2 div EHEIGHT add LHEIGHT EWIDTH sub translate
  90 rotate
  0 3 32 div inch translate % fudge factor for my printer - change or remove
  } def
 
/returnaddress {	% Print the return address
  gsave
    returnfont
    % This positions the return address .25 inches from upper left of
envelope
    .25 inch EHEIGHT .25 inch sub POINTSIZE 3 64 div inch sub sub moveto
    {nl} forall
  grestore
  } def
 
/address {		        % Print the address
  gsave
    addressfont
    4 inch 2.25 inch moveto	% Magic numbers conform to USPS guidelines
    dup				% save the address
    {nl} forall
    dup length 1 sub get	% Get the last line of the address
    mark
      {
        exch token not {exit} if
      } loop		      	% Get the last word of the last line
    dup
    /str 20 string def
    type cvlit /marktype ne {str cvs barcode} if
    cleartomark
  grestore
  } def
 
/barcodebits [		% From "A Guide to Business Mail Preparation"
  (11000)	%0	% USPS Brochure/Pamphlet
  (00011)	%1
  (00101)	%2
  (00110)	%3
  (01001)	%4
  (01010)	%5
  (01100)	%6
  (10001)	%7
  (10010)	%8
  (10100)	%9
  ] def
 
/bit1 {			% Draw a 1 bit of the POSTNET Barcode
  0 .125 inch rlineto
  1 inch 21 div .125 inch neg rmoveto
  } bind def
 
/bit0 {	 		% Draw a 0 bit of the POSTNET Barcode
  0 .05 inch rlineto
  1 inch 21 div .05 inch neg rmoveto
  } bind def  
 
/dodigit {    		% Do a complete digit of the barcode
  barcodebits exch get {
    2 mod 1 eq
      {bit1}
      {bit0}
    ifelse
    /BITS BITS 1 add def
    } forall
  } def
 
/barcode {		% Do a complete barcode
  gsave
    /CHECKSUM 0 def
    /BITS 0 def
    % More magic numbers to conform to USPS guidelines
    EWIDTH 3.9375 inch sub .25 inch moveto
    bit1
      {
      (0) 0 get sub dup dup 0 ge exch 9 le and {
        dup /CHECKSUM exch CHECKSUM add def
	dodigit
	} if
      } forall
    CHECKSUM 10 mod neg 10 add dup 10 eq {pop 0} if
    dodigit
    bit1
    BITS 50 eq {.02 inch setlinewidth stroke} if
% if you want 5 digit zip codes barcoded as well, make the previous line be
% BITS 50 eq BITS 30 eq or {.02 inch setlinewidth stroke} if
% I don't think it's a good idea to barcode a 5-digit zip.  Kinda defeats
% the purpose.
  grestore
  } def
 
% Note that if you print your own barcode, you need not follow the address font
% guidelines since the only use of the OCR machines is to print barcodes.
  
/tod [			% That's me!
  (Tod N. McQuillin)
  (25 Dilworth Street)
  (Apartment 2)
  (Pittsburgh, PA 15211-1913)
  ] def
 
/addressee [
  (J. Random Loser)
  (1234 Anystreet Blvd)
  (Anytown, NY 10001-1234)
  ] def
 
envelope
tod returnaddress
addressee address
showpage
----------------------------------------------------------

% PostScript to draw USPS barcodes
 
% takes string
% convert ASCII code to character
% if it's a digit
% add to sum
% generate check digit
% expand string
% append check
% returns string
/addcheckdigit {
  /checkdigit 0 def
  dup {
    1 string dup 0 4 3 roll put
    (0123456789) exch search
    {pop exch pop cvi checkdigit add /checkdigit exch store} {pop} ifelse
 } forall
  90 checkdigit sub 10 mod /checkdigit exch store
  dup length 1 add string dup 3 1 roll copy pop
  dup dup length 1 sub checkdigit 1 string cvs putinterval
checkdigit
} bind def
 
% show a "long" bar
/longbar {
  currentpoint
  0 9 rlineto 1.44 0 rlineto 0 -9 rlineto closepath fill
  exch 72 21 div add exch
  moveto
} bind def
 
% show a "short" bar
/shortbar {
  currentpoint
  0 3.6 rlineto 1.44 0 rlineto 0 -3.6 rlineto closepath fill
  exch 72 21 div add exch
  moveto
} bind def
 
% takes string
% draw guard bar
/showbarcode {
  longbar
  {
    1 string dup 0 4 3 roll put
    (0123456789) exch search { pop exch pop
      cvi
      [
        { longbar longbar shortbar shortbar shortbar } % 0
        { shortbar shortbar shortbar longbar longbar } % 1
        { shortbar shortbar longbar shortbar longbar } % 2
        { shortbar shortbar longbar longbar shortbar } % 3
        { shortbar longbar shortbar shortbar longbar } % 4
        { shortbar longbar shortbar longbar shortbar } % 5
        { shortbar longbar longbar shortbar shortbar } % 6
        { longbar shortbar shortbar shortbar longbar } % 7
        { longbar shortbar shortbar longbar shortbar } % 8
        { longbar shortbar longbar shortbar shortbar } % 9
      ]
      exch get exec
    } { pop } ifelse
  } forall
  longbar
  flush
} bind def
 
x y moveto (12345-6789) addcheckdigit showbarcode
 
showpage