UPC-2 is a simpler variation of the UPC-5 barcode designed to contain 2 digits of data.
The checksum (or parity) for the UPC-2 format is used only to encode the barcode, and therefore is not coded directly, and out of all the UPc barcodes, is the only one in this series which does not use modulo 10.
The parity is simply the two digits treated as an integer and then applying modulo 4 to it, and the remainder is the parity.
Like with UPC-5, UPC-2 only has a left guard and centre guard (which is places after the third digit), which are encoded as 1011 and 01 respectively.
We then apply the odd or even encoding based on the parity string we determine from the parity
The odd and even encodings are the same as the ones for the UPC-5 format .
Digit
Odd
Even
0
0001101
0100111
1
0011001
0110011
2
0010011
0011011
3
0111101
0100001
4
0100011
0011101
5
0110001
0111001
6
0101111
0000101
7
0111011
0010001
8
0110111
0001001
9
0001011
0010111
The full source code is available at https://github.com/sjmeunier/barcoder .
namespace BarcoderLib
{
public class BarcodeUPC2
{
private string gLeftGuard = "1011" ;
private string gCentreGuard = "01" ;
private string [] gOdd = { "0001101" , "0011001" , "0010011" , "0111101" , "0100011" , "0110001" , "0101111" , "0111011" , "0110111" , "0001011" };
private string [] gEven = { "0100111" , "0110011" , "0011011" , "0100001" , "0011101" , "0111001" , "0000101" , "0010001" , "0001001" , "0010111" };
private string [] gParity = { "11" , "10" , "01" , "00" };
public Bitmap Encode ( string message )
{
string encodedMessage ;
Bitmap barcodeImage = new Bitmap ( 250 , 100 );
Graphics g = Graphics . FromImage ( barcodeImage );
Validate ( message );
encodedMessage = EncodeBarcode ( message );
PrintBarcode ( g , encodedMessage , message , 250 , 100 );
return barcodeImage ;
}
private void Validate ( string message )
{
Regex reNum = new Regex ( @"^\d+$" );
if ( reNum . Match ( message ). Success == false )
{
throw new Exception ( "Encode string must be numeric" );
}
if ( message . Length != 2 )
{
throw new Exception ( "Encode string must be 2 digits long" );
}
}
private void PrintBarcode ( Graphics g , string encodedMessage , string message , int width , int height )
{
SolidBrush whiteBrush = new SolidBrush ( Color . White );
SolidBrush blackBrush = new SolidBrush ( Color . Black );
Font textFont = new Font ( FontFamily . GenericMonospace , 10 , FontStyle . Regular );
g . FillRectangle ( whiteBrush , 0 , 0 , width , height );
int xPos = 20 ;
int yTop = 20 ;
int barHeight = 50 ;
for ( int i = 0 ; i < encodedMessage . Length ; i ++)
{
if ( encodedMessage [ i ] == '1' )
{
g . FillRectangle ( blackBrush , xPos , yTop , 1 , barHeight );
}
xPos += 1 ;
}
xPos = 20 ;
yTop -= 17 ;
for ( int i = 0 ; i < message . Length ; i ++)
{
g . DrawString ( message [ i ]. ToString (), textFont , blackBrush , xPos , yTop );
xPos += 8 ;
}
}
private string EncodeBarcode ( string message )
{
int i ;
int parityCode = CalcParity ( message );
char parity ;
string encodedString = gLeftGuard ;
for ( i = 0 ; i < 2 ; i ++)
{
parity = gParity [ parityCode ][ i ];
if ( parity == '1' )
{
encodedString += gOdd [ Convert . ToInt32 ( message [ i ]. ToString ())];
}
else
{
encodedString += gEven [ Convert . ToInt32 ( message [ i ]. ToString ())];
}
if ( i < 1 )
{
encodedString += gCentreGuard ;
}
}
return encodedString ;
}
private int CalcParity ( string message )
{
int parity = Convert . ToInt32 ( message ) % 4 ;
return parity ;
}
}
}
Originally posted on my old blog, Smoky Cogs, on 27 Oct 2009