Add-On POSTNET barcodes
Informations
Author: Shailesh HumbadLicense: FPDF
Description
This is an extension for printing U.S. Postal Service POSTNET barcodes in PDF. It supports both 5 and 9 digit zip codes and includes a utility function for parsing zip codes from an address line. The barcode is drawn directly in PDF without using an image or special font.POSTNETBarCode(float x, float y, string zipcode)
x
: abscissa of barcodey
: ordinate of barcodezipcode
: zip code to draw$zipcode must be a string containing a zip code of the form DDDDD or DDDDD-DDDD. This function will trigger a PHP error if the zip code is invalid, so if the string's validity is in question, use ParseZipCode first. The parameters $x and $y specify the lower left corner of the barcode in user units. This function changes the line width in the FPDF context.
string ParseZipCode(string stringToParse)
The parsed zip code returned will be the first string matching DDDDD or DDDDD-DDDD, in that order, where D is a digit from 0 through 9. The search begins at the end of $stringToParse.
If a valid zip code cannot be found, it returns an empty string. Otherwise, it returns the parsed zip code (including the hyphen if it's a 9-digit zip).
An online example is available here.
POSTNET BARCODES
The specifications for POSTNET Barcodes can be found in U.S. Postal Service Publication 25, Designing Letter and Reply Mail. See Chapter 2 for barcode placement specifications, and Chapter 4 for barcode reading and writing specifications.
You can print barcodes on papers that will be inserted into envelopes with windows, or directly on envelopes. For envelopes with windows, in general, the barcode should be printed a minimum of 1/25" above the first line of the address, and below the top edge of the envelope window. The left and right clearance for the address should be a minimum of 1/8", and the bottom clearance should be 1/25" minimum. The address must satisfy the minimum clearances regardless of where the mailpiece shifts to within the envelope. Note that 1/4" of clearance is preferred.
Refer to the Guidelines for complete details.
Source
<?php
require('fpdf.php');
class PDF_POSTNET extends FPDF
{
// PUBLIC PROCEDURES
// draws a bar code for the given zip code using pdf lines
// triggers error if zip code is invalid
// x, y specifies the lower left corner of the bar code
function POSTNETBarCode($x, $y, $zipcode)
{
// Save nominal bar dimensions in user units
// Full Bar Nominal Height = 0.125"
$FullBarHeight = 9 / $this->k;
// Half Bar Nominal Height = 0.050"
$HalfBarHeight = 3.6 / $this->k;
// Full and Half Bar Nominal Width = 0.020"
$BarWidth = 1.44 / $this->k;
// Bar Spacing = 0.050"
$BarSpacing = 3.6 / $this->k;
$FiveBarSpacing = $BarSpacing * 5;
// 1 represents full-height bars and 0 represents half-height bars
$BarDefinitionsArray = Array(
1 => Array(0, 0, 0, 1, 1),
2 => Array(0, 0, 1, 0, 1),
3 => Array(0, 0, 1, 1, 0),
4 => Array(0, 1, 0, 0, 1),
5 => Array(0, 1, 0, 1, 0),
6 => Array(0, 1, 1, 0, 0),
7 => Array(1, 0, 0, 0, 1),
8 => Array(1, 0, 0, 1, 0),
9 => Array(1, 0, 1, 0, 0),
0 => Array(1, 1, 0, 0, 0));
// validate the zip code
$this->_ValidateZipCode($zipcode);
// set the line width
$this->SetLineWidth($BarWidth);
// draw start frame bar
$this->Line($x, $y, $x, $y - $FullBarHeight);
$x += $BarSpacing;
// draw digit bars
for($i = 0; $i < 5; $i++)
{
$this->_DrawDigitBars($x, $y, $BarSpacing, $HalfBarHeight,
$FullBarHeight, $BarDefinitionsArray, $zipcode[$i]);
$x += $FiveBarSpacing;
}
// draw more digit bars if 10 digit zip code
if(strlen($zipcode) == 10)
{
for($i = 6; $i < 10; $i++)
{
$this->_DrawDigitBars($x, $y, $BarSpacing, $HalfBarHeight,
$FullBarHeight, $BarDefinitionsArray, $zipcode[$i]);
$x += $FiveBarSpacing;
}
}
// draw check sum digit
$this->_DrawDigitBars($x, $y, $BarSpacing, $HalfBarHeight,
$FullBarHeight, $BarDefinitionsArray,
$this->_CalculateCheckSumDigit($zipcode));
$x += $FiveBarSpacing;
// draw end frame bar
$this->Line($x, $y, $x, $y - $FullBarHeight);
}
// Reads from end of string and returns first matching valid
// zip code of form DDDDD or DDDDD-DDDD, in that order.
// Returns empty string if no zip code found.
function ParseZipCode($stringToParse)
{
// check if string is an array or object
if(is_array($stringToParse) || is_object($stringToParse))
{
return "";
}
// convert parameter to a string
$stringToParse = strval($stringToParse);
$lengthOfString = strlen($stringToParse);
if ( $lengthOfString < 5 ) {
return "";
}
// parse the zip code backward
$zipcodeLength = 0;
$zipcode = "";
for ($i = $lengthOfString-1; $i >= 0; $i--)
{
// conditions to continue the zip code
switch($zipcodeLength)
{
case 0:
case 1:
case 2:
case 3:
if ( is_numeric($stringToParse[$i]) ) {
$zipcodeLength += 1;
$zipcode .= $stringToParse[$i];
} else {
$zipcodeLength = 0;
$zipcode = "";
}
break;
case 4:
if ( $stringToParse[$i] == "-" ) {
$zipcodeLength += 1;
$zipcode .= $stringToParse[$i];
} elseif ( is_numeric($stringToParse[$i]) ) {
$zipcodeLength += 1;
$zipcode .= $stringToParse[$i];
break 2;
} else {
$zipcodeLength = 0;
$zipcode = "";
}
break;
case 5:
case 6:
case 7:
case 8:
if ( is_numeric($stringToParse[$i]) ) {
$zipcodeLength = $zipcodeLength + 1;
$zipcode = $zipcode . $stringToParse[$i];
} else {
$zipcodeLength = 0;
$zipcode = "";
}
break;
case 9:
if ( is_numeric($stringToParse[$i]) ) {
$zipcodeLength = $zipcodeLength + 1;
$zipcode = $zipcode . $stringToParse[$i];
break;
} else {
$zipcodeLength = 0;
$zipcode = "";
}
break;
}
}
// return the parsed zip code if found
if ( $zipcodeLength == 5 || $zipcodeLength == 10 ) {
// reverse the zip code
return strrev($zipcode);
} else {
return "";
}
}
// PRIVATE PROCEDURES
// triggers user error if the zip code is invalid
// valid zip codes are of the form DDDDD or DDDDD-DDDD
// where D is a digit from 0 to 9, returns the validated zip code
function _ValidateZipCode($zipcode)
{
$functionname = "ValidateZipCode Error: ";
// check if zipcode is an array or object
if(is_array($zipcode) || is_object($zipcode))
{
trigger_error($functionname.
"Zip code may not be an array or object.", E_USER_ERROR);
}
// convert zip code to a string
$zipcode = strval($zipcode);
// check if length is 5
if ( strlen($zipcode) != 5 && strlen($zipcode) != 10 ) {
trigger_error($functionname.
"Zip code must be 5 digits or 10 digits including hyphen. len:".
strlen($zipcode)." zipcode: ".$zipcode, E_USER_ERROR);
}
if ( strlen($zipcode) == 5 ) {
// check that all characters are numeric
for ( $i = 0; $i < 5; $i++ ) {
if ( is_numeric( $zipcode[$i] ) == false ) {
trigger_error($functionname.
"5 digit zip code contains non-numeric character.",
E_USER_ERROR);
}
}
} else {
// check for hyphen
if ( $zipcode[5] != "-" ) {
trigger_error($functionname.
"10 digit zip code does not contain hyphen in right place.",
E_USER_ERROR);
}
// check that all characters are numeric
for ( $i = 0; $i < 10; $i++ ) {
if ( is_numeric($zipcode[$i]) == false && $i != 5 ) {
trigger_error($functionname.
"10 digit zip code contains non-numeric character.",
E_USER_ERROR);
}
}
}
// return the string
return $zipcode;
}
// takes a validated zip code and
// calculates the checksum for POSTNET
function _CalculateCheckSumDigit($zipcode)
{
// calculate sum of digits
if( strlen($zipcode) == 10 ) {
$sumOfDigits = $zipcode[0] + $zipcode[1] +
$zipcode[2] + $zipcode[3] + $zipcode[4] +
$zipcode[6] + $zipcode[7] + $zipcode[8] +
$zipcode[9];
} else {
$sumOfDigits = $zipcode[0] + $zipcode[1] +
$zipcode[2] + $zipcode[3] + $zipcode[4];
}
// return checksum digit
if( ($sumOfDigits % 10) == 0 )
return 0;
else
return 10 - ($sumOfDigits % 10);
}
// Takes a digit and draws the corresponding POSTNET bars.
function _DrawDigitBars($x, $y, $BarSpacing, $HalfBarHeight, $FullBarHeight,
$BarDefinitionsArray, $digit)
{
// check for invalid digit
if($digit < 0 && $digit > 9)
trigger_error("DrawDigitBars: invalid digit.", E_USER_ERROR);
// draw the five bars representing a digit
for($i = 0; $i < 5; $i++)
{
if($BarDefinitionsArray[$digit][$i] == 1)
$this->Line($x, $y, $x, $y - $FullBarHeight);
else
$this->Line($x, $y, $x, $y - $HalfBarHeight);
$x += $BarSpacing;
}
}
}
?>
Example
<?php
require('postnet.php');
$pdf = new PDF_POSTNET("P", "pt");
$pdf->AddPage();
$pdf->SetFont("Arial", "", 10);
// ParseZipCode examples
//$stringToParse = "Ann Arbor, MI 48109-110asdf"; // returns "48109"
//$stringToParse = "Ann Arbor, MI 48109-110"; // returns "48109"
//$stringToParse = "Ann Arbor, MI 481091109"; // returns "91109"
//$stringToParse = "Ann Arbor, MI 48109-1109asdf"; // returns "48109-1109"
//$stringToParse = "Cambridge, MA 0192"; // returns empty string
//$stringToParse = "Cambridge, MA 02139"; // perfect, returns "01239"
$stringToParse = "Ann Arbor, MI 48109-1109"; // perfect, returns "48109-1109"
$zipcode = $pdf->ParseZipCode($stringToParse);
$pdf->POSTNETBarCode(40, 40, $zipcode);
$pdf->Text(40, 90, $zipcode);
$pdf->Output();
?>