Drawing UPC-A Barcodes with C#






4.94/5 (52 votes)
Apr 6, 2005
8 min read

276383

12129
Demonstrates a method to draw UPC-A barcodes using C#.
- Download source files - 11.6 Kb
- Download demo project - 6.75 Kb
- Download source files for .NET 2003 - 10.6 Kb
- Download demo project for .NET 2003 - 7.87 Kb
Introduction
On almost every product sold, there is typically a UPC barcode of some type which is used to identify the product. The most common barcode used, in the United States and Canada, is the UPC-A barcode. In this article, we will look at the UPC-A specification and examine some code that can produce UPC-A barcodes.
UPC-A Background
The UPC-A barcode is composed of 12 digits which are made up of the following sections:
- the first digit is the product type,
- the next five digits are the manufacturer code,
- the next five digits are the product code,
- the last digit is the checksum digit.
Product Type
The product type is a one digit number which is used to describe the type of product.
Product Type Number | Description |
---|---|
0 | Regular UPC codes |
1 | Reserved |
2 | Weight items marked at the store. |
3 | National Drug/Health-related code. |
4 | No format restrictions, in-store use on non-food items. |
5 | Coupons |
6 | Reserved |
7 | Regular UPC codes |
8 | Reserved |
9 | Reserved |
Manufacturer code and product code
The manufacturer code is assigned by the Uniform Code Council, and is used to uniquely identify the product's manufacturer. The product code is used to identify the product.
Checksum digit
The checksum digit is calculated using the product type, manufacturer's code, and the product code. The odd numbers are multiplied by 3 and added to the sum, while the even numbers are simply added to the sum. The modulus of 10 is then taken of the summed total. This is subtracted from 10 and the modulus of 10 is taken again.
For example: UPC-A 01234567890 |
Product Type : 0 |
Manufacturer's Code : 12345 |
Product Code : 67890 |
The first digit '0' is odd, so multiple it by 3, the second digit 1 is even so just add it, etc... |
(0 * 3) + 1 + (2 * 3) + 3 + (4 * 3) + 5 + (6 * 3) + 7 + (8 * 3) + 9 + (0 * 3) = 85 |
85 % 10 = 5 |
( ( 10 - 5 ) % 10 ) = 5 |
Symbol size
The specifications for the UPC-A barcode specify the nominal size of a UPC symbol as 1.496" wide and 1.02" high. Based upon this nominal size the UPC symbol can be scaled by a magnification factor of 0.8 to 2.0. Scaling the barcode will produce a barcode between the minimal allowable size of 1.175" wide by .816" high and the maximum allowable size of 2.938" wide and 2.04" high.
Digit patterns
Each digit in a UPC-A bar code is composed of a series of two spaces and two bars. Each digit is drawn within a space that is 7 modules wide. In addition to the 12 digits, which make up a UPC-A barcode, the barcode symbol also has two quite zones, a lead block, a separator, and a trailing block. Each quite zone is 9 modules wide, the lead and trailing blocks are a series of lines and spaces in the format of bar, space, bar. The separator is signified by the sequence space/bar/space/bar/space.
|
where '0' represents space and '1' denotes a bar. |
In addition to the special symbol patterns listed above, the UPC-A barcode symbol uses two distinct digit patterns as well, the Left Digit pattern and the Right Digit pattern. The Left Digit pattern is used to draw the product type and the manufacturer code. The Right Digit pattern is used to draw the product code and the checksum digit. The Left Digit pattern starts with spaces and the Right Digit pattern starts with bars (see table below).
Number | Left Digits | Right Digits |
---|---|---|
0 | 0001101 | 1110010 |
1 | 0011001 | 1100110 |
2 | 0010011 | 1101100 |
3 | 0111101 | 1000010 |
4 | 0100011 | 1011100 |
5 | 0110001 | 1001110 |
6 | 0101111 | 1010000 |
7 | 0111011 | 1000100 |
8 | 0110111 | 1001000 |
9 | 0001011 | 1110100 |
where a '0' denotes a space and '1' represents a bar.
Using the code
First, we will examine how to use the UpcA
class, and then we'll examine how the UpcA
class works.
Using the UpcA Class
The code excerpt below uses the UpcA
class to draw a UPC-A barcode in a picture box control:
private void DrawUPC( )
{
System.Drawing.Graphics g = this.picBarcode.CreateGraphics( );
g.FillRectangle(new System.Drawing.SolidBrush(
System.Drawing.SystemColors.Control),
new Rectangle(0, 0, picBarcode.Width, picBarcode.Height));
// Create an instance of the UpcA Class.
upc = new UpcA( );
upc.ProductType = "0";
upc.ManufacturerCode = "21200";
upc.ProductCode = "10384";
upc.Scale =
(float)Convert.ToDecimal( cboScale.Items [cboScale.SelectedIndex] );
upc.DrawUpcaBarcode( g, new System.Drawing.Point( 0, 0 ) );
g.Dispose( );
}
The first step for the DrawUPC
function is to create an instance of the UpcA
class, and then set the product type, manufacturer code, the product code, and the scale factor properties (the check sum will be calculated by the UpcA
class). Once these properties are set, a call to the DrawUpcaBarcode
function is made, passing a Graphics
object and a Point
, which indicates the starting position to draw at, this will cause the barcode to be drawn in the picture box starting at point (0, 0).
The UpcA Class
The most significant variables are listed below:
// This is the nomimal size recommended by the UCC.
private float _fWidth = 1.469f;
private float _fHeight = 1.02f;
private float _fFontSize = 8.0f;
private float _fScale = 1.0f;
// Left Hand Digits.
private string [] _aLeft = { "0001101", "0011001", "0010011", "0111101",
"0100011", "0110001", "0101111", "0111011",
"0110111", "0001011" };
// Right Hand Digits.
private string [] _aRight = { "1110010", "1100110", "1101100", "1000010",
"1011100", "1001110", "1010000", "1000100",
"1001000", "1110100" };
private string _sQuiteZone = "0000000000";
private string _sLeadTail = "101";
private string _sSeparator = "01010";
The _fWidth
, _fHeight
, and the _fScale
variables are initialized with the nominal size recommended by the Uniform Code Council. When the barcode is rendered, its actual size will be determined by the nominal size, and the scale factor, as discussed in the Symbol Size section of this article. The variables _aLeft
, _aRight
, _sQuiteZone
, _sLeadTail
, and _sSeparator
are all string representations of the bar/space graphics, which represent the various parts of a UPC-A barcode. Essentially, a '1' represents a bar and a '0' represents a space, so _sSeparator
would cause a space-bar-space-bar-space to be rendered. An alternate method to using a string
could be to use a binary representation, where a 0 bit would be space and a 1 bit is a bar.
There are three primary functions which provide the majority of the functionality for the UpcA
class. The workhorse of these functions is DrawUpcaBarcode
. DrawUpcaBarcode
uses the other two functions as helper functions. The two helper functions are: CalculateChecksumDigit
, ConvertToDigitPatterns
and these will be discussed first. There is also a fourth function, CreateBitmap
, which provides an easy means for creating a bitmap image.
The first helper function DrawUpcaBarcode
calls the CalculateChecksumDigit
function, which uses the product type, manufacturer code, and product code to calculate the barcode's check sum.
public void CalculateChecksumDigit( )
{
string sTemp = this.ProductType + this.ManufacturerCode + this.ProductCode;
int iSum = 0;
int iDigit = 0;
// Calculate the checksum digit here.
for( int i = 1; i <= sTemp.Length; i++ )
{
iDigit = Convert.ToInt32( sTemp.Substring( i - 1, 1 ) );
if( i % 2 == 0 )
{ // even
iSum += iDigit * 1;
}
else
{ // odd
iSum += iDigit * 3;
}
}
int iCheckSum = ( 10 - ( iSum % 10 ) ) % 10;
this.ChecksumDigit = iCheckSum.ToString( );
}
The CalculateChecksumDigit
function calculates the check sum using the method discussed in the Checksum Digit section listed above.
The second helper function used is the ConvertToDigitPatterns
function. This function takes the individual numbers of the manufacturer code, and the product number, and converts them to the string representation of the barcode graphics.
private string ConvertToDigitPatterns( string inputNumber, string [] patterns )
{
System.Text.StringBuilder sbTemp = new StringBuilder( );
int iIndex = 0;
for( int i = 0; i < inputNumber.Length; i++ )
{
iIndex = Convert.ToInt32( inputNumber.Substring( i, 1 ) );
sbTemp.Append( patterns[iIndex] );
}
return sbTemp.ToString( );
}
The ConvertToDigitPatterns
function requires two parameters:
inputNumber
patterns
The inputNumber
will be either the manufacturer number or the product number, and the patterns
will either be the _aLeft
or the _aRight
array depending on whether the inputNumber
is the manufacturer number or the product number.
Finally the workhorse; the DrawUpcaBarcode
handles the rendering of the barcode graphics and requires two parameters:
g
pt
This function begins by determining the width and height for the barcode, by scaling the nominal width and height by the scale factor. The lineWidth
is based upon the total number of modules required to render a UPC-A barcode. The total number of modules, 113, is determined by the following: for example:
UPC-A code - 021900103841
Barcode Section | Numeric Value | Graphic Representation | Number of Modules |
---|---|---|---|
Quite Zone | N/A | 000000000 | 9 modules |
Lead | N/A | 101 | 3 modules |
Product Type | 1 digit - "0" | 0001101 | 7 modules |
Manufacturer Number | 5 digits = "21900" | 00100110011001000101100011010001101 | 5 digits * 7 modules = 35 modules |
Separator | N/A | 01010 | 5 modules |
Product Number | 5 digits = "10384" | 11001101110010100001010010001011100 | 5 digits * 7 modules = 35 modules |
Check Sum | 1 digit = "1" | 1100110 | 7 modules |
Trailer | N/A | 101 | 3 modules |
Quite Zone | N/A | 000000000 | 9 modules |
So, to determine the total module width, simply add the individual parts: 9 + 3 + 7 + 35 + 5 + 35 + 7 + 3 + 9 = 113.
public void DrawUpcaBarcode(System.Drawing.Graphics g,System.Drawing.Point pt)
{
float width = this.Width * this.Scale;
float height = this.Height * this.Scale;
// A upc-a excluding 2 or 5 digit supplement information
// should be a total of 113 modules wide.
// Supplement information is typically
// used for periodicals and books.
float lineWidth = width / 113f;
// Save the GraphicsState.
System.Drawing.Drawing2D.GraphicsState gs = g.Save( );
// Set the PageUnit to Inch because all of
// our measurements are in inches.
g.PageUnit = System.Drawing.GraphicsUnit.Inch;
// Set the PageScale to 1, so an inch will represent a true inch.
g.PageScale = 1;
System.Drawing.SolidBrush brush =
new System.Drawing.SolidBrush( System.Drawing.Color.Black );
float xPosition = 0;
System.Text.StringBuilder strbUPC = new System.Text.StringBuilder( );
float xStart = pt.X;
float yStart = pt.Y;
float xEnd = 0;
System.Drawing.Font font =
new System.Drawing.Font( "Arial", this._fFontSize * this.Scale );
// Calculate the Check Digit.
this.CalculateChecksumDigit( );
// Build the UPC Code.
strbUPC.AppendFormat( "{0}{1}{2}{3}{4}{5}{6}{1}{0}",
this._sQuiteZone, this._sLeadTail,
ConvertToDigitPatterns( this.ProductType, this._aLeft ),
ConvertToDigitPatterns( this.ManufacturerCode, this._aLeft ),
this._sSeparator,
ConvertToDigitPatterns( this.ProductCode, this._aRight ),
ConvertToDigitPatterns( this.ChecksumDigit, this._aRight ) );
string sTempUPC = strbUPC.ToString( );
float fTextHeight = g.MeasureString( sTempUPC, font ).Height;
// Draw the barcode lines.
for( int i = 0; i < strbUPC.Length; i++ )
{
if( sTempUPC.Substring( i, 1 ) == "1" )
{
if( xStart == pt.X )
xStart = xPosition;
// Save room for the UPC number below the bar code.
if( ( i > 19 && i < 56 ) || ( i > 59 && i < 95 ) )
// Draw space for the number
g.FillRectangle( brush, xPosition, yStart,
lineWidth, height - fTextHeight );
else
// Draw a full line.
g.FillRectangle( brush, xPosition, yStart, lineWidth, height );
}
xPosition += lineWidth;
xEnd = xPosition;
}
// Draw the upc numbers below the line.
xPosition = xStart - g.MeasureString( this.ProductType, font ).Width;
float yPosition = yStart + ( height - fTextHeight );
// Draw Product Type.
g.DrawString( this.ProductType, font, brush,
new System.Drawing.PointF( xPosition, yPosition ) );
// Each digit is 7 modules wide, therefore the MFG_Number
// is 5 digits wide so
// 5 * 7 = 35, then add 3 for the LeadTrailer
// Info and another 7 for good measure,
// that is where the 45 comes from.
xPosition +=
g.MeasureString( this.ProductType, font ).Width + 45 * lineWidth -
g.MeasureString( this.ManufacturerCode, font ).Width;
// Draw MFG Number.
g.DrawString( this.ManufacturerCode, font, brush,
new System.Drawing.PointF( xPosition, yPosition ) );
// Add the width of the MFG Number and 5 modules for the separator.
xPosition += g.MeasureString( this.ManufacturerCode, font ).Width +
5 * lineWidth;
// Draw Product ID.
g.DrawString( this.ProductCode, font, brush,
new System.Drawing.PointF( xPosition, yPosition ) );
// Each digit is 7 modules wide, therefore
// the Product Id is 5 digits wide so
// 5 * 7 = 35, then add 3 for the LeadTrailer
// Info, + 8 more just for spacing
// that is where the 46 comes from.
xPosition += 46 * lineWidth;
// Draw Check Digit.
g.DrawString( this.ChecksumDigit, font, brush,
new System.Drawing.PointF( xPosition, yPosition ) );
// Restore the GraphicsState.
g.Restore( gs );
}
The function uses the CalculateChecksumDigit
function to calculate the correct check sum digit, and then uses the ConvertToDigitPatterns
function to convert the various numeric parts of the UPC-A barcode number to a string representation. Once the number has been converted over to a string representation, the code uses the string representation to render the barcode, 1 will cause a rectangle to be drawn, and 0 will cause the code to skip drawing a rectangle. If the code draws a rectangle, it also takes into consideration whether it needs to shorten the rectangle to allow space for the manufacturer's number and the product number. Once the barcode is completely rendered, the code then determines the position, and draws the product type number, the manufacturer's number, the product number, and the check sum digit.
The CreateBitmap
function simply creates a Bitmap
object, and uses the DrawUpcaBarcode
function to render the barcode to the Bitmap
object, and then it returns the Bitmap
.
public System.Drawing.Bitmap CreateBitmap( )
{
float tempWidth = ( this.Width * this.Scale ) * 100 ;
float tempHeight = ( this.Height * this.Scale ) * 100;
System.Drawing.Bitmap bmp =
new System.Drawing.Bitmap( (int)tempWidth, (int)tempHeight );
System.Drawing.Graphics g = System.Drawing.Graphics.FromImage( bmp );
this.DrawUpcaBarcode( g, new System.Drawing.Point( 0, 0 ) );
g.Dispose( );
return bmp;
}
Points of interest
The United States and Canada are the only two countries that use the UPC-A barcode system, the rest of the world uses the EAN barcode system. So, as of January 1, 2005, the Uniform Code Council, UCC, has mandated that all U.S. and Canadian point-of-sale companies must be able to scan and process EAN-8, and EAN-13 barcodes, in addition to the UPC-A barcodes (this is called the 2005 Sunrise). The UCC has also began to push a new bar code system, known as the Global Trade Item Numbers (GTINs), basically a GTIN is a 14 digit number which conforms to the UPC-A, and EAN-13 symbol standards but uses additional digits to store country of origin information. If you want more information, go to UCC: 2005 Sunrise.
History
- Version 1.0 - Initial application.