ZPL命令 实现打印中文

最近用C#结合ZPL指令实现了打印中文的功能,在这里对其中的代码以及一些资源,分享一下.

一.直接使用ZPL打印

对于直接使用ZPL命令打印中文,首先需要明确几个概念:

1.码表文件: 字符编码文件,打印中文需要制定的码表,常用中文码表为 GB.DAT,GB8BIT.DAT,GB2312.DAT,GB18030.DAT, 其中 GB.DAT,GB8BIT.DAT为较早的机型使用编码表文件,码表可以自行下载,使用ANSI编码时必须配置编码表.

命令:SE,例子:SEE:GB18030.DAT^FS,其中E:为默认存储位置,大多数机器都默认存储在E盘,

值得注意的是,下面这些盘符都是软盘,需要通过软件点此查看将字体烧录到打印机硬件中,才能实现中文打印,比较麻烦,所以还是推荐最后的终极解决方案

存储盘符包括:

R: DRAM
B: PCMCIA Card
E: Flash Memory

2.字库文件: 我们常说的字体,打印中文需要中文字库文件,字库文件后缀为FNT或TTF,字库文件需要相应工具来转换。机器默认的字库文件可以到打印机官网查询,字库文件也可以自行下载,需要注意的是,由于字库文件需要一定的存储空间,最好选择合适的字库文件.

命令:CW/A,例子:CW1,E:SIMSUN.FNTA1,20,20FS,其中CW为定义字体,^A为调用SIMSUN.FNT为字体名称,1为定义的字体标识名称.

3.字符集,打印中文需要选取中文字符集,常用的有

14 = 双字节亚洲编码 a

26 = 包含 ASCII Transparency a 和 c 的多字节亚洲编码

28 = Unicode (UTF-8 编码) - Unicode 字符集

很多文章里提到了CI17,官方文档上标注CI17 命令已弃用,同时弃用的还有 ^CI17 命令正常工作所需的 ^F8 和 ^F16 命令。建议您改用 ^CI28-30 命令。我的建议是找跟自己打印机固件匹配的指令,打印机的固件版本可以到官网上获取.

官网:https://www.zebra.com/us/en/support-downloads/printers/industrial/zm400.html

中文SimSun字体在斑马打印机的应用-敏用数码|专注于条码数据处理 (chongshang.com.cn)

命令:CI,例子:CI28

友情提示:

Encoding编码为ANSI时,需要码表文件和字库文件,而Unicode编码时,只需要字库文件即可.

可以使用 WD*😗.*命令进行查询打印机的码表,WD为打印目录标签命令,你也可以使用^WDE:*.DAT,直接查询E:盘下后缀为DAT的有哪些.

代码例子:

1.使用 ANSI Encoding编码模式输出时,需要中文码表支持,ZPL命令如下:

^XA
^SEE:GB18030.DAT^FS
^CWJ,E:MSUNG.FNT^FS
^FO10,10^AJ,24,24^CI26^FD中文打印测试ANSI码^FS
^PQ1
^XZ

2.Encoding编码为UTF-8时,只要字库文件,此时改变国际字符集指令使用CI17加F8,或^CI28,如:

^XA
^CWJ,E:MSUNG.FNT^FS
^FO10,10^AJN,24,24^CI17^F8^FD中文打印测试UTF码^FS
^PQ1
^XZ
或:
^XA
^CWJ,E:MSUNG.FNT^FS
^FO10,10^AJN,24,24^CI28^FD中文打印测试UTF码^FS
^PQ1
^XZ

要注意编码表,字库文件和字符集三者都正确才能打印出中文,负责可能出现乱码的情况.

二.使用第三方库文件Fnthex32.dll转换为图像后打印,Fnthex32.dll 并没有找到官网下载地址,各位看官网上自己搜吧...该库文件分为8参和9参两个版本,此处以9参为例进行介绍,直接上代码

 public class ZebraPrintHelper
    {
        [DllImport("Fnthex32.dll")]
        public static extern int GETFONTHEX(
        string BarcodeText,//转换的文本
        string FontName,//打印字体
        string FileName,//存储的变量名称
        int Orient,//方向
        int Height,//字体高度,点阵高度
        int Width,//点阵宽度
        int IsBold,//是否加粗0,1
        int IsItalic,//是否斜体0,1
        StringBuilder ReturnBarcodeCMD);//存储的内容
 
        /// <summary>
        /// 转换中文
        /// </summary>
        /// <param name="chStr">转换的字符</param>
        /// <param name="tempName">存储的变量名称</param>
        /// <param name="font">使用的字体</param>
        /// <returns></returns>
        public static string ConvertChineseToHex(string chStr, string tempName, string font = "Microsoft YaHei")
        {
            StringBuilder cBuf = new StringBuilder(chStr.Length * 1024);
            int nCount = GETFONTHEX(chStr, font, tempName, 0, 25, 15, 1, 0, cBuf);
            string temp = " " + cBuf.ToString();
            temp = temp.Substring(0, nCount);
            return temp;
        }
    }

调用类库方法ConvertChineseToHex获取ZPL指令

string zplCode=ZebraPrintHelper.ConvertChineseToHex("打印测试ASD", "tempName", "Microsoft YaHei")

指令获取结果:

 ~DGtempName,00200,008,j03FC1FE0HF07F8I07FE3HF1HF8HFCI041F20F907C83EK0FH07803C01
EK0FH07803C01EJ03E01FH0F807CJ07C03E01FH0F8J0FH07803C01EJ01EH0FH07803CJ01EH0FH078
03CJ01EH0FH07803Cg01FH0F807C03EJ01FH0F807C03Ek0

这里~DG指令只是创建了一个名称为tempName的图像,我们还需要附加一条指令来调用它,如下

^FO15,5^XGtempName,1,1^FS

完整的ZPL命令应该是:

^XA
 ~DGtempName,00200,008,j03FC1FE0HF07F8I07FE3HF1HF8HFCI041F20F907C83EK0FH07803C01
EK0FH07803C01EJ03E01FH0F807CJ07C03E01FH0F8J0FH07803C01EJ01EH0FH07803CJ01EH0FH078
03CJ01EH0FH07803Cg01FH0F807C03EJ01FH0F807C03Ek0
^FO15,5^XGtempName,1,1^FS
^PQ1
^XZ

最后将ZPL命令以RAW模式发送至给印机即可.

最后在这里分享几个不错的网站:

1.在线调试网址,对于ZPL指令执行的结果可以进行调试.

http://labelary.com/viewer.html

2.资料网站,前查资料的时候发现的网站,有很多ZPL中文打印相关的问题和解答

http://www.winfuture.net/bbs/index.asp

[Fnt字体制作_weixin_43932081的博客-程序员宝宝_fnt字体制作 - 程序员宝宝 (cxybb.com)

[Fnt字体制作_weixin_43932081的博客-CSDN博客_fnt字体制作](https://www.cxybb.com/article/weixin_43932081/101716387)

生成fnt字体工具BMFontTool工具_MOMO实验室的博客-CSDN博客_ttf转fnt

碰到斑马打印机下载字体问题

最近手里有一台斑马打印机(Zebra GT800 EPL),要求打印出Arial 7号字体,然后就开始各种摸索,从网上查资料,

然后就找到了这个http://www.chongshang.com.cn/manual/ZPL_font.shtml,写的够详细,但是我按照这个步骤来怎么也找不到我字体下载到哪去啦!!

终于,发现不是步骤的问题,是驱动的问题,其实seagull和斑马自带的驱动都能实现字体下载的功能,只是好像有一个差别。

因为一开始打印机标明是EPL语言打印机,我就直接装了个EPL驱动,两个驱动都试过!!然后下载进去各种找不到。

后来就想了下换成ZPL的试试,没想到还真的下载进去啦。。

斑马自带驱动下载进去后,如果不改字体名字的话,默认是ARI000.FNT,然后直接调用就可以!原文链接:https://blog.csdn.net/u013366966/article/details/46011323

终极解决方案:图片转ZPL实现打印

Java How to Convert Image to ZPL Zebra printer format Example (jcgonzalez.com)

源码部分

import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javax.imageio.ImageIO;
public class ZPLConveter {
    private int blackLimit = 380;
    private int total;
    private int widthBytes;
    private boolean compressHex = false;
    private static Map<Integer, String> mapCode = new HashMap<Integer, String>();
    {
        mapCode.put(1, "G");
        mapCode.put(2, "H");
        mapCode.put(3, "I");
        mapCode.put(4, "J");
        mapCode.put(5, "K");
        mapCode.put(6, "L");
        mapCode.put(7, "M");
        mapCode.put(8, "N");
        mapCode.put(9, "O");
        mapCode.put(10, "P");
        mapCode.put(11, "Q");
        mapCode.put(12, "R");
        mapCode.put(13, "S");
        mapCode.put(14, "T");
        mapCode.put(15, "U");
        mapCode.put(16, "V");
        mapCode.put(17, "W");
        mapCode.put(18, "X");
        mapCode.put(19, "Y");
        mapCode.put(20, "g");
        mapCode.put(40, "h");
        mapCode.put(60, "i");
        mapCode.put(80, "j");
        mapCode.put(100, "k");
        mapCode.put(120, "l");
        mapCode.put(140, "m");
        mapCode.put(160, "n");
        mapCode.put(180, "o");
        mapCode.put(200, "p");
        mapCode.put(220, "q");
        mapCode.put(240, "r");
        mapCode.put(260, "s");
        mapCode.put(280, "t");
        mapCode.put(300, "u");
        mapCode.put(320, "v");
        mapCode.put(340, "w");
        mapCode.put(360, "x");
        mapCode.put(380, "y");        
        mapCode.put(400, "z");            
    }
    public String convertfromImg(BufferedImage image) throws IOException {
        String cuerpo = createBody(image);
        if(compressHex)
           cuerpo = encodeHexAscii(cuerpo);
        return headDoc() + cuerpo + footDoc();        
    }
    private String createBody(BufferedImage orginalImage) throws IOException {
        StringBuffer sb = new StringBuffer();
        Graphics2D graphics = orginalImage.createGraphics();
        graphics.drawImage(orginalImage, 0, 0, null);
        int height = orginalImage.getHeight();
        int width = orginalImage.getWidth();
        int rgb, red, green, blue, index=0;        
        char auxBinaryChar[] =  {'0', '0', '0', '0', '0', '0', '0', '0'};
        widthBytes = width/8;
        if(width%8>0){
            widthBytes= (((int)(width/8))+1);
        } else {
            widthBytes= width/8;
        }
        this.total = widthBytes*height;
        for (int h = 0; h<height; h++)
        {
            for (int w = 0; w<width; w++)
            {
                rgb = orginalImage.getRGB(w, h);
                red = (rgb >> 16 ) & 0x000000FF;
                green = (rgb >> 8 ) & 0x000000FF;
                blue = (rgb) & 0x000000FF;
                char auxChar = '1';
                int totalColor = red + green + blue;
                if(totalColor>blackLimit){
                    auxChar = '0';
                }
                auxBinaryChar[index] = auxChar;
                index++;
                if(index==8 || w==(width-1)){
                    sb.append(fourByteBinary(new String(auxBinaryChar)));
                    auxBinaryChar =  new char[]{'0', '0', '0', '0', '0', '0', '0', '0'};
                    index=0;
                }
            }
            sb.append("\n");
        }
        return sb.toString();
    }
    private String fourByteBinary(String binaryStr){
        int decimal = Integer.parseInt(binaryStr,2);
        if (decimal>15){
            return Integer.toString(decimal,16).toUpperCase();
        } else {
            return "0" + Integer.toString(decimal,16).toUpperCase();
        }
    }
    private String encodeHexAscii(String code){
        int maxlinea =  widthBytes * 2;        
        StringBuffer sbCode = new StringBuffer();
        StringBuffer sbLinea = new StringBuffer();
        String previousLine = null;
        int counter = 1;
        char aux = code.charAt(0);
        boolean firstChar = false; 
        for(int i = 1; i< code.length(); i++ ){
            if(firstChar){
                aux = code.charAt(i);
                firstChar = false;
                continue;
            }
            if(code.charAt(i)=='\n'){
                if(counter>=maxlinea && aux=='0'){
                    sbLinea.append(",");
                } else     if(counter>=maxlinea && aux=='F'){
                    sbLinea.append("!");
                } else if (counter>20){
                    int multi20 = (counter/20)*20;
                    int resto20 = (counter%20);
                    sbLinea.append(mapCode.get(multi20));
                    if(resto20!=0){
                        sbLinea.append(mapCode.get(resto20) + aux);    
                    } else {
                        sbLinea.append(aux);    
                    }
                } else {
                    sbLinea.append(mapCode.get(counter) + aux);
                    if(mapCode.get(counter)==null){
                    }
                }
                counter = 1;
                firstChar = true;
                if(sbLinea.toString().equals(previousLine)){
                    sbCode.append(":");
                } else {
                    sbCode.append(sbLinea.toString());
                }                
                previousLine = sbLinea.toString();
                sbLinea.setLength(0);
                continue;
            }
            if(aux == code.charAt(i)){
                counter++;                
            } else {
                if(counter>20){
                    int multi20 = (counter/20)*20;
                    int resto20 = (counter%20);
                    sbLinea.append(mapCode.get(multi20));
                    if(resto20!=0){
                        sbLinea.append(mapCode.get(resto20) + aux);    
                    } else {
                        sbLinea.append(aux);    
                    }
                } else {
                    sbLinea.append(mapCode.get(counter) + aux);
                }
                counter = 1;
                aux = code.charAt(i);
            }            
        }
        return sbCode.toString();
    }
    private String headDoc(){
        String str = "^XA " +
                        "^FO0,0^GFA,"+ total + ","+ total + "," + widthBytes +", ";
        return str;
    }
    private String footDoc(){
        String str = "^FS"+
                        "^XZ";        
        return str;
    }
    public void setCompressHex(boolean compressHex) {
        this.compressHex = compressHex;
    }
    public void setBlacknessLimitPercentage(int percentage){
        blackLimit = (percentage * 768 / 100);
    }
    public static void main(String[] args) throws Exception {
        BufferedImage orginalImage = ImageIO.read(new File("/tmp/logo.jpg"));
        ZPLConveter zp = new ZPLConveter();
        zp.setCompressHex(true);
        zp.setBlacknessLimitPercentage(50);        
        System.out.println(zp.convertfromImg(orginalImage));        
    }
}

标签打印机图片转ZPL指令 - 佳博云打印 (poscom.cn)

Java绘图: 使用 Graphics 类绘制线段、矩形、椭圆/圆弧/扇形、图片、文本_xietansheng的博客-CSDN博客_graphics画矩形

源码部分

测试通过——zebra-api: java编写图片转ZPL指令,斑马打印机打印中文标签纸

未测试

posted @ 2022-10-08 13:44  Journey&Flower  阅读(5745)  评论(3编辑  收藏  举报