使用 C# 绘制 POSTNET 条形码






4.86/5 (14投票s)
本文演示了一种绘制 POSTNET 条形码的方法。

引言
本文研究了 POSTNET 条形码系统,并演示了使用 C# 2005 和 GDI+ 创建 POSTNET 条形码的一些基本功能。
背景
如今,许多雇主都相当节俭,因此让他们购买像邮政条形码字体这样的简单东西有时会非常困难。曾有过几次这样的经历,我决定研究邮政条形码系统,并创建一个简单的库,在给定邮政编码的情况下能够绘制 POSTNET 条形码。
POSTNET 条形码概述
POSTNET 条形码可以包含几个信息片段:起始/结束码、邮政编码、+4 码、投递点码和校验码(见下图)。
起始/结束码标志着条形码的开始和结束。起始/结束码是强制性的,由一个单独的“全条”组成。邮政编码也是强制性的,由 25 个条组成。“+4”码由 20 个条组成,是可选的。投递点码由 10 个条组成,是可选的,通常是街道地址、邮政信箱、乡村路线号或公路合同路线号的最后两位数字。校验码是强制性的,基本上是一个校验和(我在本文中可互换地使用校验码和校验和这两个术语)。
![]() |
每个数字都由一个由五个条组成的独特图案表示(左侧图片显示了图案)。基本上,有两种不同的条类型:“全条”和“半条”。“全条”的高度必须在 0.115 英寸到 0.135 英寸之间。“半条”的高度必须在 0.04 英寸到 0.06 英寸之间。全条和半条的宽度都必须在 0.015 英寸到 0.025 英寸之间。 除了高度和宽度规格外,条之间还有间距要求;它必须在 0.012 英寸到 0.040 英寸之间。 POSTNET 条形码规格
(如需完整参考,请参阅美国邮政服务局提供的 POSTNET 条形码规格,可在此 处获取,或搜索 POSTNET 条形码规格。) |
校验码
校验码是一个简单的校验和,通过将邮政编码中的所有数字相加,然后对总和取模 10,最后用 10 减去该结果来计算。
示例:邮政编码 + 4 位是 12345-6789,投递点是 01。
1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 0 + 1 = 46
46 % 10 = 6
10 - 6 = 4
4 % 10 = 4
所以校验码是 4;最后的模运算用于总和邮政编码是 10 的倍数的特殊情况。
代码
Postnet
类用于使用 Graphics
对象句柄来渲染条形码,或创建 Bitmap
类。唯一必需的数据是邮政编码;+4 位和投递点是可选的。校验码将由 Postnet
类计算。
Using the Code
Postnet
类将处理渲染条形码的所有方面。只需创建 Postnet
类的实例,并将邮政编码作为参数传递给构造函数。然后,调用 DrawPOSTNET
函数,并将 Graphics
对象和起始点作为参数传递。处理完成后,执行任何其他绘图任务,然后通过调用 Graphics
对象的 Dispose
函数进行清理。
// Create an instance of the Postnet class and send it
// the zip code, +4, and delivery point. The Postnet class will
// calculate the correction character.
Postnet ps = new Postnet( "12345", "6789", "01" );
// Create a Graphics object handle from a picture box.
System.Drawing.Graphics g = this.pictureBox1.CreateGraphics( );
// Send a handle to the Graphics object and the starting
// point to begin drawing the barcode.
ps.DrawPOSTNET( g, new System.Drawing.Point( 0, 0 ) );
// Handle any other drawing necessary.
// Clean up.
g.Dispose( );
Postnet
类提供的第二个功能是以位图形式创建条形码。要创建位图,请创建 Postnet
类的实例,并将邮政编码传递给构造函数。然后,调用 CreateBitmap
函数,并将要创建的位图的宽度和高度作为参数传递。
// Create an instance of the Postnet class and send it
// the zip code, +4, and delivery point. The Postnet class will
// calculate the correction character.
Postnet ps = new Postnet( "12345", "6789", "01" );
// Call the CreateBitmap function passing in the width and height for the
// newly created bitmap.
pictureBox1.Image = ps.CreateBitmap( this.pictureBox1.Width,
this.pictureBox1.Height );
代码工作原理
Postnet
类相对简单。它提供了几种用于不同创建方式的构造函数;几个用于设置和获取类数据的属性/特性;上面讨论的两个公共函数,以及一些处理繁重工作的私有函数。
创建类的实例时,它会通过调用 InitBarSpecification
函数来初始化条形码规格。此函数设置多项信息,这些信息控制条形码的各个方面,并初始化 DRAWING_INFO
结构(见下面的代码)。
private void InitBarSpecifications( )
{
// Set the Bar specifications with the default values.
di = new DRAWING_INFO( );
_fBarWidth = .022f;
_fTallBarHeight = 0.125f;
_fShortBarHeight = 0.05f;
_fBarSpacing = 0.02f;
}
DRAWING_INFO
包含用于绘制条形码的画笔实例、当前 x 位置和当前 y 位置。
private struct DRAWING_INFO
{
public System.Drawing.SolidBrush brush;
public float xStart;
public float yStart;
}
DrawPOSTNET
函数使用 CalculateCorrectionCharacter
函数来计算校验和,渲染起始/结束码,并调用 DrawBars
函数来渲染邮政编码、+4 码、投递点和校验码。除了这些功能外,DrawPOSTNET
函数还会保存 Graphics
对象的 GraphicsState
,并在完成条形码绘制后恢复它。一个有趣的项目是使用 g.PageUnit
和 g.PageScale
;如果这些未设置或未正确获取,条形码可能会过大或过小。PageUnit
和 PageScale
用于自动将渲染从像素调整为英寸。PageUnit
是一个 System.Drawing.GraphicsUnit
枚举类型,它告诉 GDI+ 对象将绘图转换为哪种单位。PageScale
用于缩放渲染;因此,如果 PageScale
设置为 .5,则绘图中的一英寸将按比例缩小到实际设备(显示器、打印机等)上的半英寸。
public void DrawPOSTNET( System.Drawing.Graphics g,
System.Drawing.Point startPt )
{
// Calculate the Check Sum.
CalculateCorrectionCharacter( );
// Save the user's graphics state, just in case they are doing
// something special.
System.Drawing.Drawing2D.GraphicsState gs = g.Save( );
// Failure to set the PageUnit and PageScale will result
// in odd results.
g.PageUnit = System.Drawing.GraphicsUnit.Inch;
g.PageScale = 1f;
di.brush = new System.Drawing.SolidBrush( System.Drawing.Color.Black );
di.xStart = startPt.X;
di.yStart = startPt.Y;
// Print Frame Bar
g.FillRectangle( di.brush, di.xStart, di.yStart,
_fBarWidth, _fTallBarHeight );
di.xStart += ( _fBarWidth + _fBarSpacing );
// Print Zip Code
string sTempValue = ZipCode.ToString( );
DrawBars( g, sTempValue, ref di );
// Print Plus4
if( Plus4.Length == 4 )
{
sTempValue = Plus4.ToString( );
DrawBars( g, sTempValue, ref di );
// Print Delivery Point
if( this.DeliveryPoint.Length > 0 && this.DeliveryPoint.Length < 3 )
{
sTempValue = DeliveryPoint.ToString( );
DrawBars( g, sTempValue, ref di );
}
}
// Print Correction Character
sTempValue = this.CorrectionCharacter.ToString( );
DrawBars( g, sTempValue, ref di );
// Print Frame Bar
g.FillRectangle( di.brush, di.xStart, di.yStart,
_fBarWidth, _fTallBarHeight );
// Restore the saved user's graphics state, just incase they are doing
// something special.
g.Restore( gs );
}
CalculateCorrectionCharacter
函数简单地将邮政编码、+4 码和投递点码中的数字相加;然后,它将总和的数字取模 10;从 10 中减去该数字,然后再次取模 10。
private void CalculateCorrectionCharacter( )
{
string sZipCode;
sZipCode = ZipCode.ToString( );
int iCorrectionCharacter = 0;
for( int i = 0; i < sZipCode.Length; i++ )
{
iCorrectionCharacter +=
Convert.ToInt32( sZipCode.Substring( i, 1 ) );
}
if( this.Plus4.Length == 4 )
{
string sPlus4 = Plus4.ToString( );
for( int i = 0; i < sPlus4.Length; i++ )
{
iCorrectionCharacter +=
Convert.ToInt32( sPlus4.Substring( i, 1 ) );
}
if( this.DeliveryPoint.Length > 0
&& this.DeliveryPoint.Length < 3 )
{
string sDeliveryPoint = this.DeliveryPoint.ToString( );
for( int i = 0; i < sDeliveryPoint.Length; i++ )
{
iCorrectionCharacter +=
Convert.ToInt32( sDeliveryPoint.Substring( i, 1 ) );
}
}
}
int iLeftOver = iCorrectionCharacter % 10;
this._iCorrectionCharacter = ( 10 - iLeftOver ) % 10;
}
DrawBars
函数使用 sNumber
参数和 _aBarcodeValues
数组来确定条形码的绘制方式。_aBarcodeValues
数组包含数字格式;0 是短条,1 是长条。
string [] _aBarcodeValues = { "11000", // 0
"00011", // 1
"00101", // 2
"00110", // 3
"01001", // 4
"01010", // 5
"01100", // 6
"10001", // 7
"10010", // 8
"10100" }; // 9
...
private void DrawBars( System.Drawing.Graphics g,
string sNumber, ref DRAWING_INFO di )
{
string sTempValue;
for( int i = 0; i < sNumber.Length; i++ )
{
sTempValue =
_aBarcodeValues[Convert.ToInt32( sNumber.Substring( i, 1 ) )];
for( int j = 0; j < sTempValue.Length; j++ )
{
if( sTempValue.Substring( j, 1 ) == "0" )
g.FillRectangle( di.brush, di.xStart, di.yStart +
( _fTallBarHeight - _fShortBarHeight ),
_fBarWidth, _fShortBarHeight );
else
g.FillRectangle( di.brush, di.xStart, di.yStart,
_fBarWidth, _fTallBarHeight );
di.xStart += ( _fBarWidth + _fBarSpacing );
}
}
}
最后一个函数是 CreateBitmap
函数。此函数接受所需的宽度和高度来创建新的位图。它从 Bitmap
创建一个 Graphics
对象,绘制条形码,然后返回 Bitmap
对象。
public System.Drawing.Bitmap CreateBitmap( int width, int height )
{
System.Drawing.Bitmap bmp = new System.Drawing.Bitmap( width, height );
System.Drawing.Graphics g = System.Drawing.Graphics.FromImage( bmp );
this.DrawPOSTNET( g, new System.Drawing.Point( 0, 0 ) );
g.Dispose( );
return bmp;
}
完成了!
好了,这就是 Postnet
类的内容了,我probably 应该回去工作了。虽然这可能不是一个热门话题,但我确实希望它能帮助到一些人,至少是通过分享一些知识。
历史
- 版本 1.0.0 - 2004 年 12 月 1 日 - 初始版本。
- 版本 1.1.0 - 2004 年 12 月 7 日 - 修正了校验码计算 - 感谢 je_gonzalez。