前两天遇到了一个需要浏览器打印条码的需求,因为目前的管理系统是基于B/S的,在生产管理员用户那里需要将订单转为生产指令单,与此同时需要将订单中的产品批量打印出来条码纸来,以便生产完毕后贴到产品上面方便扫码入库和标注产品。
先从打印机开始
提供给我的是一台科诚打印机G500,实际使用效果还不错。目前很多的条码打印机厂商提供了可视化的条码打印软件,可以直接打印出来条码,还可以生成相应的EZPL指令,方便开发者使用指令来开发条码打印,当然还提供了基础的二次开发包和文档。
下图是科诚官网下载的GO-LABLE打印设计软件。
使 用非常简单,摆弄一会儿就明白怎么玩了,这款打印软件提供了基础的条码图形,文字和图像图形工具,拖动到设计界面即可,这里需要注意的是,在使用字体的时 候有两种可以选择,一种是打印机内建字体,一种是windows字体,如果你条码上的文字不需要改变了,那就建议使用windows字体,这样打印出来的 文字清晰度很高,如果文字需要动态改变,比如我遇到的这个需求,那么就必须使用内建字体了,双击条码上的文字,会出现文字设定:
这里我选择了亚洲字体,使用前需要先下载亚洲字体到打印机,其实就是把本机的中文字体下载到打印机。其他的文字来源我试过了,但是只有这个选项可以打印出来中文而不出现乱码。
设计完成后,我们可以输出指令到右面的命令视窗,多观察一下,你会发现其实这就是按照一定的规则生产的一串配置信息,告诉打印机纸张的大小信息,要 出现一个什么样的图像,什么文本的文字,文字的字体类型,以及所有的这些元素的位置坐标信息,有了这些信息,打印机便可以按照要求输出打印图像了。我们可 以试着改变命令窗口的信息,然后输入回到设计界面,你就会发现设计效果已经按照你的修改发生了改变。
大家可能已经发现了,我在所有需要动态更改的地方,用@+相应的字段表示,目的就是为了以此为模板,通过替换模版的元素达到动态输出的效果。
这里着重讲一下二维码配置信息
W30,22,5,2,M,8,10,5,0
@单号
其中“@单号”是二维码的文本信息,上面配置信息倒数第二个,也就是那个“5”,是二维码信息的长度,,一个中文是两个字节,所以“@单号”的长度就是5了,如果文本信息换成其他的了,这里的“5”,也要做相应的改变。
制作ActiveX控件
如 果是做成winform,程序,那应该说是非常的简单了,直接调用提供的dll就行了,可现在要求在浏览器中完成这个任务,浏览器想调用dll,那就得用 的ActiveX控件了。关于ActiveX控件的开发和安装部署,网上有一些教程,其实和做winform差不多,只是添加一下guid,修改一下控件 属性就行了,真的是非常方便。下面把核心代码贴出来
//Trace.dll是官方提供的,放到bin文件夹下面<br>[DllImport("Trace.dll")] public static extern void sendcommand( [MarshalAs(UnmanagedType.LPArray)] byte[] command); public void printdata(string danhao,string kehu,string guige,string houdu,string yanse,string kuandu,string gaodu,string pingmi) {<br> //获取程序集的文件夹目录,也就是安装后控件程序集所在的目录 string sApplicationPath = Assembly.GetExecutingAssembly().Location;<br>//找到Data.cmd,这里是命令窗口中生成的那些指令信息,放到bin文件下,安装程序会把控件的dll和这个Data.cmd一起打包输出,这里就要求安装程//序务必吧Data.cmd包含进去。如果是调试状态,程序或到obj/debug文件下寻找Data.cmd,所以为了调试不出错,也放到那里一份Data.cmd sApplicationPath = sApplicationPath.Replace("CodexPrint.dll","Data.cmd"); using (StreamReader sr = new StreamReader(sApplicationPath, Encoding.GetEncoding("GB2312"))) { StringBuilder sb = new StringBuilder(); string sLine = ""; while (sLine != null) { sLine = sr.ReadLine(); if (sLine != null && !sLine.Equals("")) {<br> //特别要注意必须每次读一行后添加上换行符,否则待会还原成字节数组的时候发给打印机,打印机不懂你在讲什么 sLine += Environment.NewLine; sb.Append(sLine); } } sr.Close();<br> //去除空的部分 string temp = sb.ToString().Trim(); //获取单号的字节长度,替换"@单号"的长度5,一个汉字两个长度 string erweimapeizhixinxi=temp.Substring(temp.IndexOf("W30"),(temp.LastIndexOf("@单号") -temp.IndexOf("W30") -1)); string[] arraytemp=erweimapeizhixinxi.Split(new char[]{','}); arraytemp[arraytemp.Length - 2] = Encoding.GetEncoding("GB2312").GetBytes(danhao ).Length.ToString(); temp = temp.Replace(erweimapeizhixinxi,string.Join(",",arraytemp)); //开始替换数据 temp = temp.Replace("@单号", danhao); temp = temp.Replace("@客户", kehu); temp = temp.Replace("@规格", guige); temp = temp.Replace("@厚度", houdu); temp = temp.Replace("@颜色", yanse); temp = temp.Replace("@宽度", kuandu); temp = temp.Replace("@高度", gaodu); temp = temp.Replace("@平米", pingmi); byte[] buffer = Encoding.GetEncoding("GB2312").GetBytes(temp); openport("6"); //Ex:USB try { sendcommand(buffer); closeport(); } catch (Exception error) { MessageBox.Show(error.Message); return; } } }
这样ActiveX控件的开发就基本完成了,然后就可以在PC安装了,类似工行网站在使用之前必须安装控件一样。
页面使用
ActiveX控件安装完毕后,页面的使用就简单了
在startprint方法里,我们可以通过js来调用控件中的printdata方法了。这里我循环了表格中的数据,然后逐行打印
<script type="text/javascript"> function startprint() { var p = document.getElementById("BarCodePrint"); var tableObj = document.getElementById("data"); for (var i = 1; i < tableObj.rows.length; i++) { var rowcells = tableObj.rows[i].cells; var jsondata = { "danhao": rowcells[0].innerHTML, "kehu": rowcells[11].innerHTML, "guige": rowcells[1].innerHTML + rowcells[2].innerHTML, "yanse": rowcells[3].innerHTML, "houdu": rowcells[4].innerHTML, "kuandu": rowcells[5].innerHTML, "gaodu": rowcells[6].innerHTML, "pingmi": rowcells[10].innerHTML }; //也可以省去定义json的过程,直接将数据传入下面的方法 p.printdata(jsondata.danhao, jsondata.kehu, jsondata.guige, jsondata.houdu, jsondata.yanse, jsondata.kuandu, jsondata.gaodu, jsondata.pingmi); } } </script>
这样整个工作就完成了,实测效果良好。ActiveX控件只能在IE下使用,谷歌浏览器还得使用其他插件配合,不过作为生产环节上的一环,要求工作人员使用IE就行了,呵呵。如果有一天突然想改变标签上的布局了,那么在GO-LABLE中重新设计好后生成新的指令,找到ActiveX控件的安装目录,找到Data.cmd,替换掉原来的的指令就可以了。但是这里面的模版替换元素必须形式一样,而且不能增加新的字段,如果增加的话,那就得重新开发升级ActiveX控件了。其实还有更灵活的方法,比如只传入方法一个字符串,里面包含了需要替换的标签和标签数据,通过分隔符区分,比如“@单号:0000001|@颜色:红色|………”,然后进行字符串处理就行了。当然页面的调用形式也相应做出改变就行。