65.9K
CodeProject 正在变化。 阅读更多。
Home

GenCode128 - Code128 条形码生成器

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.95/5 (95投票s)

2006年6月10日

CPOL

7分钟阅读

viewsIcon

878244

downloadIcon

56643

为 WinForms 或 ASP.NET 创建 Code128 条形码。

Sample Image - GenCode128.png

引言

这是一个简单的库,可让您非常轻松地完成一件事:通过一行代码生成 Code128 条形码的 Image。此图像适用于在 WinForms 应用程序中打印或显示,甚至适用于 ASP.NET。

背景

支持其他条形码符号(barcode symbologies)很容易找到,因为它们很容易创建。例如,使用简单的字体就可以生成基本的 Code39 条形码,而且似乎到处都可以找到 Code39 字体或图像集供下载。

然而,Code39 存在不足。基于字体的简单输出不提供任何错误检查。在标准配置下,大多数扫描仪只能识别 43 个不同的符号(配置更改可以解决此问题,但您可能无法在用户的硬件配置选择中享有此便利)。而且 Code39 相当冗长,需要大量空间来表示给定消息。

另一方面,Code128 开箱即用地支持所有 128 个低位 ASCII 字符。它内置了字符和消息级别的错误检测,并且非常简洁。不幸的是,在此符号中生成合理的编码是一个“主动”过程。您必须分析消息以确定最佳编码策略,并且必须计算整个消息的校验和。

在我的情况下,编码控制字符是绝对必要的。我的应用程序设计要求用户能够通过扫描页面上的条形码来触发某些菜单快捷键。但由于我无法控制用户正在使用的扫描仪,因此 Code39EXT 符号不是一个好的选择。

搜索结果显示了几个 Code128 控件,但这些控件有两个重要的缺陷。首先,它们是控件。如果我只是想在页面上生成条形码,那没问题,但我想将它们用作网格中的图像,因此我需要一种获取原始 GDI+ Image 对象的方法。其次,它们相当昂贵——以至于覆盖我们所有开发人员的许可证费用比我自行开发的成本还要高。

使用代码

基本用法

正如所承诺的,生成条形码 Image 就像一行代码一样简单。当然,您仍然需要必要的代码行将该 Image 放置到它需要去的位置。

这是示例应用程序中的一段代码。在该代码中,我响应按钮点击,根据一些输入文本生成条形码,并将结果放入 PictureBox 控件中。

private void cmdMakeBarcode_Click(object sender, System.EventArgs e)
{
   try
   {
      Image myimg = Code128Rendering.MakeBarcodeImage(txtInput.Text, 
                                         int.Parse(txtWeight.Text), true);
      pictBarcode.Image = myimg;
   }
   catch (Exception ex)
   {
      MessageBox.Show(this, ex.Message, this.Text);
   }
}

显然,这段代码的精髓是 `try` 后面的第一行。对于调用者来说,整个库中只有一个有趣的方法。

GenCode128.Code128Rendering.MakeBarcodeImage( string InputData, 
                              int BarWeight, bool AddQuietZone )

(那是 `GenCode128` 命名空间中的一个静态类,名为 `Code128Rendering`)。由于这是一个静态类,您甚至不必担心实例化对象。

有三个参数:

  • string InputData

    要编码的消息。

  • int BarWeight

    输出条形码中条形的基线宽度。通常,1 或 2 就足够了。

  • bool AddQuietZone

    如果为 `false`,则省略条形码开头和结尾必需的空白区域。如果您的布局已为 Image 提供良好的边距,则应使用 `true`。

通过玩弄示例应用程序,您可以大致了解这些值的影响。同时,请尝试打印一些样本,以验证您的扫描仪是否可以读取您计划生成的条形码。

打印

条形码库如果您不用于打印,几乎是无用的。您无法扫描屏幕。我从 Windows 应用程序打印东西已经很久了,花了一点时间才想起来怎么做。如果您像我一样需要快速回顾一下,可以看看演示应用程序的“打印”按钮调用的事件。

您应该注意的事项

首先,库本身没有内置任何异常处理。为了您自己的安全,您应该将 `try/catch` 块放在对库的任何调用周围。

该解决方案包括三个项目。一个是库本身,一个是演示应用程序,还有一个是单元测试代码。我通过 TestDriven.net 使用了 NUnit。如果您没有它,Visual Studio 将会抱怨。由于这只是测试代码,您可以安全地删除它,仍然可以成功使用该库。

另一点是条形码所需的垂直高度。规范要求图像的高度为 1/4 英寸或整体宽度的 15%,以较大者为准。由于我无法控制您输出图像时的缩放比例,因此我没有实现 1/4 英寸的最小值。这意味着对于非常短的条形码,高度可能非法地小。

Code128 的高信息密度部分来自于在几种备用编码集之间智能切换。据我所知,获得最佳编码是一个“难”问题(在离散数学的非多项式问题,如旅行商问题中)。最佳解决方案与我的相当好的解决方案之间的差异应该很小,并且似乎不值得付出努力。

我用于获得“相当好”编码的算法涉及对单个字符进行前瞻。

  • 如果当前字符可以在当前编码集中编码,那么它就继续这样做。
  • 否则,如果下一个字符在此编码集中是合法的,它将暂时切换到备用编码集,仅针对该字符。
  • 否则,当前字符和下一个字符都需要切换,因此它会更改编码集以避免切换。

关于从哪个编码集开始编码也需要做出类似的决定。为了解决这个问题,我检查字符串的前两个字符,让它们“投票”以查看它们偏好哪个编码集。如果偏好一个编码集,我就会选择它;否则,我默认为编码集 B。这是因为编码集 A 允许大写字母数字字符加上控制字符,而编码集 B 允许大写和小写字母数字字符;我假设您更可能想要小写字母而不是控制字符。

最后,Code128 规范中有一个针对仅数字输出的优化,我没有利用它。长串的数字可以在双密度编码集中进行编码。在我的已经很糟糕的前瞻算法中考虑这一点需要更多的精力——但对于我不需要的功能。但是,如果您有大量的数字并且空间很紧张,您可能需要考虑增强这一点。

关注点

我想任何查看我源代码的人都会想知道,我的条形宽度表为什么会有两个额外的列。在一个合理的宇宙中,应该有六列而不是八列。这是为了适应非标准的 STOP 代码,它有七个条形而不是六个。我本可以为这个代码实现一个特殊情况,但这太令人厌恶了。

相反,我在所有其他项中添加了额外的零宽度列,从而使所有情况下的数据都等效。对于宽度为零的每个条形,都不会输出任何内容,因此不会造成任何损害。

当然,六列或八列的选择引出了一个问题:为什么不是七列?这是为了适应渲染代码中的一项优化。通过将整个图像预初始化为白色,我可以避免绘制白色条形。因此,我成对地获取条形宽度。第一个是黑色的,我正常绘制它(除非其宽度为零)。第二个是白色的,但那里已经有白色了,所以我可以跳过它本应占据的区域。

如果有人在记分,这是我第二次尝试真正的测试驱动开发。总的来说,我认为这次效果相当不错。尤其是在较低的代码级别上,我对代码非常有信心。然而,最高级别——输出只是一个 Image——似乎无法通过这种方式进行测试。

不过,TDD 的一个问题是代码可见性。理想情况下,这个库应该只有一个公共可见类,带有一个公共方法。然而,我的测试代码迫使我公开所有最终调用者不应该知道的底层内容。如果 C# 中的 TDD 已经找到了一个很好的答案,我还没有遇到过。

历史

  • 1.0.0.0 - 2006-06-10

    初始发布。

© . All rights reserved.