天天看点

条形码生成

  javascript:void(0)

执行本示例,需要 SQL Server 的 Northwind 数据库,以及 VS 2008 或 IIS,另还需要 Crystal Reports 2008 标准版 (SAP 公司的网站可下载完整的安装程序,无使用限制,但安装前需要输入安装序号)。

若是 VS 2005/2008 内置的免费简易版 Crystal Reports,由于不具备「动态截取网络图片」的功能、无法抓取既有的条码图片,因此不适用本帖的教学。

---------------------------------------------------

日前做 ASP.NET 的项目用到 Crystal Reports 水晶报表,必须要能在浏览器中的报表显示和打印条码。原本我采用「字体 (font)」的方式产生条码 (水晶报表内置将某个数据库字段,直接转成条形码的功能),但后来发现这种做法,布署时必须在每一台客户端的 Windows 上安装特定的条码字体,如:free3of9 (可免费下载),才能在客户端浏览器正确显示和打印条码。因此后来弃用这种做法,改用「图片」的方式产生条码。

做法是先用 C# 和 .NET 的绘图 API,搭配一维条码里最普遍的 Code 39 编码其规则,写一个可创建条码图片的 .ashx (HttpHandler) 或 .aspx,(这个文件放在报表的同一个 ASP.NET 项目里即可,不必发布成 service)。接着在 Crystal Reports 文件里,随便插入一张图片,透过水晶报表标准版才有的「动态截取网络图片」功能 (Visual Studio 内置的免费版水晶报表无此功能),去抓取这张已创建的条码图片,并要能动态传入参数,以让报表在换页时,条码可跟着变动内容。

首先用 C# 和 .NET 的绘图 API,搭配一维条码里最普遍的 Code 39 编码其规则,写一个可创建条码图片的组件。请参考本帖的下载示例,直接执行 Code39Handler.ashx,并透过浏览器的 URL 地址栏,手动输入条码的参数作测试。执行结果和源代码 (这种组件通常是要钱的) 如下:

条形码生成

图 1 用 C# 和 .NET 的绘图 API,搭配 Code 39 编码规则产生的条码图片

以下代码,是用 C# 和 .NET 的绘图 API,搭配 Code 39 编码规则产生条码图片。

条形码生成
条形码生成

Code39Handler

<%@ WebHandler Language="C#" Class="Code39Handler" %>

using System;

using System.Web;

using System.Drawing;

using System.Drawing.Imaging;

using System.Drawing.Text;

/// <summary>

/// 用 .NET 繪圖 API,搭配條碼最普遍的 Code 39 編碼規則 (一般超商的讀條碼機都可讀),產生條碼圖檔

/// </summary>

public class Code39Handler : IHttpHandler {

public void ProcessRequest (HttpContext context) {

//context.Response.ContentType = "text/plain";

//context.Response.Write("Hello World");

//Logic to retrieve the image file

//context.Response.ContentType = "image/jpeg";

//context.Response.WriteFile("MyImage01.jpg");

string mycode = context.Request["code"];

string 字串;

string 字元;

//字串 = "*-%$*"

        字串 = "*" + mycode + "*";  //Code 39 的特性是前、後置碼會標識「星號(*)」,表示開始和結束

int 畫布高 = 35;

int 畫布寬 = 0;

int 筆x = 0;

int 筆y = 20;

//int 筆寬 = 0;

if (!string.IsNullOrEmpty(mycode))

        {

            畫布寬 = 字串.Length * 13;

            Bitmap BMP = new Bitmap(畫布寬, 畫布高, System.Drawing.Imaging.PixelFormat.Format32bppPArgb);

            Graphics G = Graphics.FromImage(BMP);

            G.TextRenderingHint = TextRenderingHint.AntiAlias;

            G.Clear(Color.White);

            Brush 筆刷1 = new SolidBrush(Color.White);

            G.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;

            G.FillRectangle(筆刷1, 0, 0, 畫布寬, 畫布高);

for (int i = 0; i < 字串.Length; i++)

            {

//取得 Code 39 碼的規則

                字元 = this.genBarcode(字串.Substring(i, 1).ToUpper());

for (int j = 0; j < 4; j++)

                {

if (字元.Substring(j, 1).Equals("0"))

                    {

                        G.DrawLine(Pens.Black, 筆x, 0, 筆x, 筆y);

                    }

else

                        G.DrawLine(Pens.Black, 筆x + 1, 0, 筆x + 1, 筆y);

                        筆x += 1;

                    筆x += 1;

if (字元.Substring(j + 5, 1).Equals("0"))

                        G.DrawLine(Pens.White, 筆x, 0, 筆x, 筆y);

                        G.DrawLine(Pens.White, 筆x + 1, 0, 筆x + 1, 筆y);

                } //end of loop

if (字元.Substring(4, 1).Equals("0"))

                    G.DrawLine(Pens.Black, 筆x, 0, 筆x, 筆y);

                }

                    G.DrawLine(Pens.Black, 筆x + 1, 0, 筆x + 1, 筆y);

                筆x += 2;

            } //end of loop

int x = 0;

int addx = 13;

            G.DrawString("-", new Font("Arial", 10, FontStyle.Italic), SystemBrushes.WindowText, new PointF(x, 20));

            x += addx;

for (int k = 0; k < mycode.Length; k++)

                G.DrawString(mycode.Substring(k, 1), new Font("Arial", 10, FontStyle.Italic), SystemBrushes.WindowText, new PointF(x, 20));

                x = x + addx;

            }

            BMP.Save(context.Response.OutputStream, ImageFormat.Jpeg);

            G.Dispose();

            BMP.Dispose();

        }

            畫布寬 = 100;

//未給參數時顯示的提示內容

            G.DrawString("無條碼產生", new Font("宋体", 12, FontStyle.Regular), SystemBrushes.WindowText, new PointF(0, 20));

    }

// 規則可參考網址 1:http://blog.csdn.net/xuzhongxuan/archive/2008/05/28/2489358.aspx

// 規則可參考網址 2:http://blog.163.com/zryou/blog/static/6903184200971704226450/

/// Code 39 碼的規則。

/// Code 39 碼可使用的字元如下:0~9、A~Z、+、-、*、/、%、$、. 及空白字元。    

/// <param name="code"></param>

/// <returns></returns>

public string genBarcode(string code)

    {

switch (code)

case "0":

                code = "001100100";

break;

case "1":

                code = "100010100";

case "2":

                code = "010010100";

case "3":

                code = "110000100";

case "4":

                code = "001010100";

case "5":

                code = "101000100";

case "6":

                code = "011000100";

case "7":

                code = "000110100";

case "8":

                code = "100100100";

case "9":

                code = "010100100";

case "A":

                code = "100010010";

case "B":

                code = "010010010";

case "C":

                code = "110000010";

case "D":

                code = "001010010";

case "E":

                code = "101000010";

case "F":

                code = "011000010";

case "G":

                code = "000110010";

case "H":

                code = "100100010";

case "I":

                code = "010100010";

case "J":

                code = "001100010";

case "K":

                code = "100010001";

case "L":

                code = "010010001";

case "M":

                code = "110000001";

case "N":

                code = "001010001";

case "O":

                code = "101000001";

case "P":

                code = "011000001";

case "Q":

                code = "000110001";

case "R":

                code = "100100001";

case "S":

                code = "010100001";

case "T":

                code = "001100001";

case "U":

                code = "100011000";

case "V":

                code = "010011000";

case "W":

                code = "110001000";

case "X":

                code = "001011000";

case "Y":

                code = "101001000";

case "Z":

                code = "011001000";

case "*":

                code = "001101000";

case "-":

                code = "000111000"; //好像辨識不出來

case "%":

                code = "100101000"; //好像辨識不出來

case "$":

                code = "010101000"; //好像辨識不出來

default:

                code = "010101000"; //都不是就印 $

return code;

public bool IsReusable {

get {

return false;

}

执行 Default.aspx 里的水晶报表,结果如下图 2。条码是图片,不是字型,不必担心客户端的浏览器或打印机无法辨识某种条码字体。另下图 2 里,Employees 表的 EmployeeID 字段是 int 类型,在水晶报表默认会被当作 Number 类型,而自动显示小数点及后两位数字。本文后续会提到解决方式。

条形码生成

图 2 报表换页时,会传入不同的参数内容到我们写的条码组件里,因此条码内容也会跟着变动

若您想测试本帖示例,可去 SAP 公司的官方网站,下载标准版的 Crystal Reports 2008 软件 (下载页面标识的 SP 版或 V1 版,表示已内置安装主程序 + 修补程序,并非只有修补程序)。该软件和 Oracle 数据库的策略一样,提供网络下载完整的安装主程序、无使用时间限制或功能限制,但安装 Crystal Reports 前需要输入安装序号 (怎么找序号本文不再赘述)。安装过程如下图 3,加选「数据访问」的 ADO.NET 功能,以配合本帖示例的 ASP.NET 报表做法,透过网站 App_Code 文件夹里,事先定义好要访问的数据库内容的 .xsd (DataSet) 文件,作为设计 Crystal Reports 报表时的数据来源。

条形码生成

图 3 Crystal Reports 2008 安装过程,加选「数据访问」的 ADO.NET 选项

如下图 4、图 5,在新建的水晶报表文件里,随便插入一个图片,在上面单击右键选择「设置图形格式」,再选择 Crystal Reports 标准版才有的「图形位置」功能。

条形码生成

图 4 在水晶报表里先随便插入一张图片

条形码生成

图 5 Crystal Reports 标准版才有的「图形位置」功能,VS 2005/2008 内置的版本无此功能

如下图 6,在水晶报表的「公式编辑器」里,输入以下内容和参数。此处动态传入的参数,会传入上图 1 里,我们事先用 C# 写好的条码生成组件。此例中,参数内容是 Employees 表的 EmployeeID 字段。若您报表里的条码,无法正确透过浏览器呈现,多半是这里的地址、端口号或内容打错,或此创建条码的服务未正确启用,此时浏览器只会显示原始插入报表的图片,而非条码。

条形码生成

图 6 公式编辑器里的语法,较类似 VB 或 VB.NET

另在上图 2 里,我们提到数据库里的 EmployeeID 字段,类型是 int,在水晶报表里会被当作 Number 类型,而在条码里自动加上小数点及后两位数字。解决方式如下图 7,用 水晶报表自带的 CStr 函数,将该字段转型成字符串即可。

条形码生成

图 7 若报表里的条码,无法正确透过浏览器呈现,多半是这里的地址或内容打错,或这里未改成您 VS 2008 内置 Web server 或 IIS 执行时的正确地址、端口号

附带一提,在布署 ASP.NET 水晶报表至 IIS 时,必须将 IIS 默认目录:

C:\Inetpub\wwwroot\

底下的 aspnet_client 文件夹和里面的文件 (图 8),一并拷贝至我们的 ASP.NET 网站底下 (图 9),这样透过 IIS 执行的水晶报表,才能正确显示报表 Toolbar 里的 icon,并正确展示相关的功能。

条形码生成

图 8 此文件夹在安装完 Crystal Reports 主程序后,内容会自动增加