一起谈.NET技术,以 .NET 创建 Code 39 条码图片 供水晶报表打印

教导如何用 C# 创建 Code 39 编码的「条码 (barcode)」图片,以供 ASP.NET + Crystal Reports 水晶报表呈现和打印此条码。本帖提供 ASP.NET 3.5 示例下载。

本帖的示例下载点:http://files.cnblogs.com/WizardWu/100914.zip

执行本示例,需要 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, 0, 筆x, 筆y);
                        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);
                    }
                    else
                    {
                        G.DrawLine(Pens.White, 筆x, 0, 筆x, 筆y);
                        G.DrawLine(Pens.White, 筆x + 1, 0, 筆x + 1, 筆y);
                        筆x += 1;
                    }

                    筆x += 1;
                } //end of loop

                if (字元.Substring(4, 1).Equals("0"))
                {
                    G.DrawLine(Pens.Black, 筆x, 0, 筆x, 筆y);
                }
                else
                {
                    G.DrawLine(Pens.Black, 筆x, 0, 筆x, 筆y);
                    G.DrawLine(Pens.Black, 筆x + 1, 0, 筆x + 1, 筆y);
                    筆x += 1;
                }

                筆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;
            }

            G.DrawString("-", new Font("Arial", 10, FontStyle.Italic), SystemBrushes.WindowText, new PointF(x, 20));
            BMP.Save(context.Response.OutputStream, ImageFormat.Jpeg);
            G.Dispose();
            BMP.Dispose();

        }
        else
        {
            畫布寬 = 100;

            Bitmap BMP = new Bitmap(畫布寬, 畫布高, System.Drawing.Imaging.PixelFormat.Format32bppPArgb);
            Graphics G = Graphics.FromImage(BMP);
            G.TextRenderingHint = TextRenderingHint.AntiAlias;
            G.Clear(Color.White);
            
            //未給參數時顯示的提示內容
            G.DrawString("無條碼產生", new Font("宋体", 12, FontStyle.Regular), SystemBrushes.WindowText, new PointF(0, 20));

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

    // 規則可參考網址 1:http://blog.csdn.net/xuzhongxuan/archive/2008/05/28/2489358.aspx
    // 規則可參考網址 2:http://blog.163.com/zryou/blog/static/6903184200971704226450/
    /// <summary>
    /// Code 39 碼的規則。
    /// Code 39 碼可使用的字元如下:0~9、A~Z、+、-、*、/、%、$、. 及空白字元。    
    /// </summary>
    /// <param name="code"></param>
    /// <returns></returns>
    public string genBarcode(string code)
    {
        switch (code)
        {
            case "0":
                code = "001100100";
                break;
            case "1":
                code = "100010100";
                break;
            case "2":
                code = "010010100";
                break;
            case "3":
                code = "110000100";
                break;
            case "4":
                code = "001010100";
                break;
            case "5":
                code = "101000100";
                break;
            case "6":
                code = "011000100";
                break;
            case "7":
                code = "000110100";
                break;
            case "8":
                code = "100100100";
                break;
            case "9":
                code = "010100100";
                break;
            case "A":
                code = "100010010";
                break;
            case "B":
                code = "010010010";
                break;
            case "C":
                code = "110000010";
                break;
            case "D":
                code = "001010010";
                break;
            case "E":
                code = "101000010";
                break;
            case "F":
                code = "011000010";
                break;
            case "G":
                code = "000110010";
                break;
            case "H":
                code = "100100010";
                break;
            case "I":
                code = "010100010";
                break;
            case "J":
                code = "001100010";
                break;
            case "K":
                code = "100010001";
                break;
            case "L":
                code = "010010001";
                break;
            case "M":
                code = "110000001";
                break;
            case "N":
                code = "001010001";
                break;
            case "O":
                code = "101000001";
                break;
            case "P":
                code = "011000001";
                break;
            case "Q":
                code = "000110001";
                break;
            case "R":
                code = "100100001";
                break;
            case "S":
                code = "010100001";
                break;
            case "T":
                code = "001100001";
                break;
            case "U":
                code = "100011000";
                break;
            case "V":
                code = "010011000";
                break;
            case "W":
                code = "110001000";
                break;
            case "X":
                code = "001011000";
                break;
            case "Y":
                code = "101001000";
                break;
            case "Z":
                code = "011001000";
                break;
            case "*":
                code = "001101000";
                break;
            case "-":
                code = "000111000"; //好像辨識不出來
                break;
            case "%":
                code = "100101000"; //好像辨識不出來
                break;
            case "$":
                code = "010101000"; //好像辨識不出來
                break;
            default:
                code = "010101000"; //都不是就印 $
                break;
        }
        
        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 主程序后,内容会自动增加


图 9 ASP.NET 网站布署至 IIS 时,必须一并将 aspnet_client 文件夹拷贝至网站的根目录

 

 

附带一提,水晶报表的打印方式分两种,一是透过报表 Toolbar 自带的打印按钮 (参考上图 2),二是自己撰码调用 ReportDocument 类的 PrintToPrinter 方法。

      第一种打印方式,才能突破浏览器的安全限制,自动下载 ActiveX 程序以呈现打印预览的窗体,并能自动抓取到客户端的打印机名称。这种做法适合跨互联网打印的用户。
      第二种打印方式,虽然客制能力较强,但只能抓取服务器端的打印机名称,因此报表只能在服务器端打印。这种做法只适合同一个 LAN 或 Intranet 共用打印机的用户。 

时间: 2024-09-17 04:53:18

一起谈.NET技术,以 .NET 创建 Code 39 条码图片 供水晶报表打印的相关文章

以 .NET 创建 Code 39 条码图片 供水晶报表打印

教导如何用 C# 创建 Code 39 编码的「条码 (barcode)」图片,以供 ASP.NET + Crystal Reports 水晶报表呈现和打印此条码.本帖提供 ASP.NET 3.5 示例下载. 本帖的示例下载点:http://files.cnblogs.com/WizardWu/100914.zip 执行本示例,需要 SQL Server 的 Northwind 数据库,以及 VS 2008 或 IIS,另还需要 Crystal Reports 2008 标准版 (SAP 公司的

一起谈.NET技术,.Net创建Excel文件(插入数据、修改格式、生成图表)的方法

1.添加Excel引用 可以在.Net选项卡下添加Microsoft.Office.Interop.Excel引用,或在COM下添加Microsoft Excel 12.0 Object Library.它们都会生成Microsoft.Office.Interop.Excel.dll. 2.创建Excel. 有两种方法创建一个Excel Workbook实例. 1.需要一个模板文件,使用Open方法,参数较多: 1 object miss = Missing.Value;2 Applicatio

一起谈.NET技术,.NET程序员必备参考图片

昨天我讲到对.NET Framework的一点理解,今天又有所收获,马上来和大家分享.大家平时大都是参考MSDN,其实这足够了,那么我今天要分享的是什么呢?大家平时用过多少namespace?或者说用过多少FCL?我本人喜欢更加直观的图片,所以找到了FCL的图片.哈哈,比较壮观!这是.NET Framework 3.5的FCL概念图,囊括了几乎所有FCL,我想可以做个桌面背景,或是打出来贴墙上,用过那些可以标记上,看看你最后能学到多少?可以到Microsoft下载PDF版和打印版.   这张是.

java做水晶报表一般都用那些技术,能否提供些demo

问题描述 java做水晶报表一般都用那些技术,能否提供些demo 解决方案 解决方案二:水晶报表mark

《创业家》牛文文:少谈点模式多谈点技术

"模式"如同当年的"主义",流行于各种创业大赛.创业励志节目.论坛的"街头"式秀场 文/创业家 牛文文 "美国某某公司你知道吧?就是刚被戴尔.惠普.思科十几亿美元抢购的那家.我们的模式和它的一样,现在还没赢利,可将来起码有十几亿人民币的市值." "我开了小煤矿,但煤运不出去,上商学院之后受到启发,想搞模式创新,具体讲就是想在铁路边上搞个煤炭物流开发区,建一个大的物流和信息流平台,把分散的煤炭集中在我这个园区,这样和铁

一起谈.NET技术,WPF 员工卡条形码

     大家都知道条形码(Barcode)是一种可以由机器识别的特殊编码,在生产.生活中也常常会见到并使用它.条形码的类型和种类很多感兴趣的朋友可以详细了解一下.其中Code 39 可以说是一种最为常见并广泛使用的字符与数字结合的编码类型,本篇也将利用它制作一个带有条形码的员工卡应用程序.      在公司内部员工卡是员工身份唯一的识别工具,同时也是考勤及门禁系统的主要信息来源.首先在WPF 中设计一个简单的员工卡样式,具备员工卡标识.员工相片.员工姓名等. <Border CornerRad

一起谈.NET技术,在MVC2.0使用Lodop为WEB打印提出完美解决方案

通过好友CallHot介绍Lodopweb打印控件.由于是国人开发的,故这两天认真了研究下,打算在未来的项目中使用.现将学习成果与园友分享.如果存在不足的地方,希望您指出. 具体的实现步骤如下: 一.准备工作   1.MVC2.0 + jQuery1.4.1 开发环境. 2.Lodop web 打印控件,官方地址:http://mtsoftware.v053.gokao.net/download.html  (注:国人开发,免费软件). 3.StringTemplate,C#开源模板引擎.官方地

一起谈.NET技术,关于ASP.NET页面打印技术的总结

B/S结构导致了Web应用程序中打印的特殊性. • 程序运行在浏览器中,打印机在本地,而文件确可能在服务器上,导致了打印控制不是很灵活. • 格式如何控制和定制等,是我们开发中可能会面对的问题. 打印文档的生成 • 1.客户端脚本方式 一般情况下,主要使用JS 可以分析源页面的内容,将欲打印的页面元素提取出来,实现打印.通过分析源文档的内容,可以生成打印目标文档. 优点:客户端独立完成打印目标文档的生成,减轻服务器负荷; 缺点:源文档的分析操作复杂,并且源文档中的打印内容要有约定. • 2.服务

一起谈.NET技术,用Dojo实现Ajax请求:XHR、跨域、及其他

在任何浏览器上方便地实现Ajax请求是每一个Ajax框架的初衷.Dojo在这方面无疑提供了非常丰富的支持.除了XMLHttpRequest之外,动态script.iframe.RPC也应有尽有,并且接口统一,使用方便,大多数情况下都只需要一句话就能达到目的,从而免除重复造轮子的麻烦.而且,Dojo一贯追求的概念完整性也在这里有所体现,换句话说,在使用Dojo的Ajax工具的过程中不会感到任何的不自然,相反更容易有触类旁通的感觉,因为API的模式是统一的,而且这里涉及到的某些概念(如Deferre