上一篇文章说到了.NET中的打印机,在PrintDocument类也暴露一些本质上上的问题,前面也提到过了,虽然使用PrintDcoument打印很方便。对应条码打印机比如斑马等切刀指令,不依赖打印机驱动等等PrintDocuent显得无能为力。在开发吉特仓储管理系统(开源托管在github: https://github.com/hechenqingyuan/gitwms 有兴趣可以加本人QQ 821865130 或者Q群 88718955, 142050808 了解)的过程中遇到了各种打印上的问题,本篇文章主要记录利用串口接收ZPL指令来驱动斑马打印机打印。
一. 使用场景
1. 使用斑马条码打印机打印标签或票据
2. 要支持条码,二维码,图片,中文的打印
3. 能够自定义打印模板
4. 使用串口(COM口)通信
5. 不要安装斑马打印机驱动
6. 斑马打印机自动切纸
以上场景和上一篇文章的大同小异,重点提到了支持COM口以及不要安装斑马打印机驱动,并且要能够在斑马打印机上启动切纸,这个和上一篇文章的不同之处在于此,也就理解为不同需求。PrintDocument 也是支持串口的,只要将打印机连接通信方式修改为串口也就可以,但是提到了不使用驱动以及切刀自动切纸,PrintDocument也就无能为力了。
仍然以以上订单票据为案例,以上效果是今天用ZPL指令打印出来的效果图,基本和PrintDocument打印的效果差不多,具体可以详看上一篇文章。
二.ZPL 是个什么鬼
ZPL是个什么东西,不用惊慌,是斑马打印机上的一种机器语言,更多关于ZPL的信息可以百度搜索一下。 机器语言老套,哥对此恨之入骨,奥涩难懂。做一个打印有这么麻烦么。
^XA^MMT^LS0^BY4,3,41^FT40,41^BCN,,Y,N^FD>;123456^FS^PQ1,0,1,Y^XZ
以上是ZPL指令语言的一个样本,能看懂么?第一眼看过去我就不想往下看了,你也不得不相信他的神奇之处,这段文字你使用doc命令就可以直接调用斑马打印机打印。使用ZPL指令打印就必须先了解ZPL语言特性,了解各种指令的意思,奥涩难懂也是没有办法的,只有了解了才能正确的使用。
ZPL指令详解推荐文件:
对于想学ZPL指令的我也只能帮你到这些了,慢慢 研究吧,更多详细内容可以参考官网文档,英文也够难读的。
几个重要的指令:
1. 开始指令 ^XA
2. 结束指令 ^XZ
3. 打印边距指令 ^LH
4. 打印纸张大小指令 ^LH
5. 切刀指令 ^MM
6. 设置字符位置指令 ^FO
7. 设置字符结束指令 ^FS
8. 下载图像指令 ^DG
9. 调用图像指令 ^XG
10. 二维码指令 ^BQ
11. 条码指令 ^BC
ZPL中使用到的指令太多,这里不过多的讲解,要了解指令的参考推荐的文章。
三. 自定义模板
为了兼容上一篇文章中所用到的模板,在模板设置上我们保持不变,在打印程序运行解析的过程中仍然使用该模板。
{{Logo}}预定凭条保税区1店No.150 page.1{{OrderCode}}单据号:{{OrderCode}}提货时间:{{DtReceive}}提货点:{{ReceiveAddress}}联系人:{{ReceiveUser}}联系电话:{{ReceiverPhone}}时间:{{DtCreate}}-------------序号货号品名数量单价金额-------------{{Index}}{{StrID}}{{StrName}}{{DCount}}*{{DPrice}}={{DAmount}}-------------联机刷卡人民币{{DAmount}}--------------商品数:{{DCount}}总金额:{{DAmount}}{{OrderCode}}--------------谢谢惠顾,欢迎再次光临提货凭据,请妥善保管客服热线:*******
模板文件模板的解析方式仍然不变,这里要注意一下使用ZPL打印的时候,在计算字体大小使用的单位和PrintDocument中GDI+画图的单位是不一样的,具体是怎样一种转换比例目前还没有完全弄明白,所以在打印的时候要调整模板中的相应值。
四.代码详解
不多说直接上代码,一下是ZPL指令转换的核心代码,在网上也可以看到,自己修改了一部分,拿去用即可。
ZplPrintControl { public string ZPL_Start() { StringBuilder builder = new StringBuilder(); builder.AppendLine(); //指令块的开始 builder.AppendLine(); builder.AppendLine(); builder.AppendLine(); //MD是设置色带颜色的深度 builder.AppendLine(); builder.AppendLine(); builder.AppendLine(); builder.AppendLine(); builder.AppendLine(); return builder.ToString(); } public string ZPL_End() { StringBuilder builder = new StringBuilder(); builder.AppendLine(); builder.ToString(); } 设置打印标签纸边距 ZPL_PageSet(int printX, int printY) { StringBuilder builder = new StringBuilder(); builder.AppendLine(+ printX + + printY); builder.ToString(); } 打印凭条设置 ZPL_SetLabel(int width, int height) { sReturn = ; return string.Format(sReturn, width, height); } 打印矩形 ZPL_DrawRectangle(int px, int py, int thickness, int width, int height) { sReturn = ; return string.Format(sReturn, px, py, thickness, width, height); } 打印英文 ZPL_DrawENText(string EnText, string ZebraFont, int px, int py, string Orient, int Height, int Width) { sReturn = + ZebraFont + ; return string.Format(sReturn, EnText, px, py, Orient, Height, Width); } 中文处理,返回ZPL命令 ZPL_DrawCHText(string ChineseText, string FontName, int startX, int startY, int Orient, int Height, int Width, int IsBold, int IsItalic) { StringBuilder sResult = new StringBuilder(); StringBuilder hexbuf = new StringBuilder(21 * 1024); int count = ZplPrintControl.GETFONTHEX(ChineseText, FontName, Orient, Height, Width, IsBold, IsItalic, hexbuf); if (count > 0) { + startX.ToString() + + startY.ToString() + + ; sResult.AppendLine(hexbuf.ToString().Replace(, ) + sEnd); } return sResult.ToString(); } 打印条形码(128码) ZPL_DrawBarcode(int px, int py, int width, int ratio, int barheight, string barcode) { sReturn = ; return string.Format(sReturn, px, py, width, ratio, barheight, barcode); } 打印二维码 ZPL_DrawQRCode(int px, int py, int cl, int bch, string qrCode) { StringBuilder sb = new StringBuilder(); sb.AppendFormat(, px, py); sb.Append(); sb.AppendFormat(, qrCode); return sb.ToString(); } }
ZPL指令转换代码以上代码缺少打印图片部分的代码,这个在后续单独讲解为什么
中文打印有点特殊,斑马打印机本身对中文支持性不好,这里我们需要使用到动态链接库fnthex32.dll,可以到网上搜索下载一下此链接库,并且可以注册到系统中