斑马打印机

560 阅读6分钟

斑马打印机

斑马打印机程序调用

1.设备说明

斑马ZT610R

2.技术语言

JAVA开发

ZPL语言(斑马自主语言)

ZebraDesigner 3 设计器

3.设计器开发

设计器可以直接去斑马的网站直接下载,通过拖拉的方式可以进行设计。

设计器可以直接连接数据库,进行批量打印。

Untitled.png

4.JAVA调用开发

斑马网站上有相关的 java程序 示例代码

www.zebra.cn/cn/zh/suppo…

techdocs.zebra.com/link-os/2-1…

具体调用程序,

其中ZPL语言 需要单独学习,但是可以通过设计器通过打印到 文件进行获取

package com.easycomp.utils;

import com.easycomp.entity.PrintEnt;
import com.zebra.sdk.comm.*;
import com.zebra.sdk.printer.*;
import com.zebra.sdk.printer.discovery.*;

import java.awt.image.BufferedImage;

public class PrintHandler {

    //单次打印只给一个对象,防止打印机线程堵塞
    public static void initPrinter(PrintEnt printEnt) throws Exception {
        DiscoveredPrinter[] printers = null;
        Connection connection = null;

        printers = UsbDiscoverer.getZebraUsbPrinters(new ZebraPrinterFilter());
        connection = printers[0].getConnection();
        connection.open();
//            zebraPrinter = ZebraPrinterFactory.getInstance(connection);
//            System.out.println("获取到实例---" + zebraPrinter.toString());

        String context = printEnt.getCode();
        BufferedImage orginalImage = CreateQrCodeUtil.encode(context, "", printEnt.getCodeimgw(), printEnt.getCodeimgh(),printEnt.getCodeimgw(), printEnt.getCodeimgh());
        ZPLConveterUtil zp = new ZPLConveterUtil();
        zp.setCompressHex(true);
        zp.setBlacknessLimitPercentage(50);
        String imgZpl = zp.convertfromImg(orginalImage,printEnt.getCodeimgx(),printEnt.getCodeimgy());

        byte[] configLabel = null;
        /*
        configLabel = ("^XA\n" +   //标签开始
                "^JMA\n" +
                "^CI28\n" +  //^CI28:调用用来打印的国际字符集14:只能打印每行都是中文26:可以打印每行既有中文也有英文28:代表UTF-8字符,中文打印一般用这个字符集经过试验,打印中文的话只有28有用,用其他字符集可能会乱码。
                "^CW1,E:SIMSUN.FNT\n" + // ^CW1,E:SIMSUN.FNT:使用SIMSUN.FNT作为打印的字体,并且把这个字体用数字1标识
                "^PW2362\n" +  //标签宽度
                "^LL709\n" +  //标签长度
                "^LH0,0\n" +  //标签左上角的坐标(x轴,y轴)
                "^MD10\\n\n" + //打印标签的颜色深度(范围0~30)

                //^FO50,50:代表这段文字左上角的坐标
                // ^A0,55,55
                //^A:用来选择字体,有两种方式。
                //^A@字体名,这种方式一般不用,至于字体名有哪些,你可以打印打印机的配置信息,里面包含了打印机当前安装了哪些字体,至于怎么打印可以看上面介绍安装打印机的部分。
                //^A数字或字母(A-Z,0-9):^A后面默认跟的是数字0,代表默认字体,上面的例子用的就是0。后面跟的数字我们是可以自定义的,需要用^CW命令。    比如^CW1,E:SIMSUN.FNT,此时使用^A1就代表后面的文字使用E:SIMSUN.FNT字体,我们给数字1赋值了一个字体。后面讲中文字体的时候会着重介绍
                //第一个55:让字符沿Y轴拉伸
                //第二个55:让字体沿X轴拉伸
                // ^FD:后面跟着你需要打印的文字
                // ^FS:用来分割ZPL指令
                "^FO50,50^A1,80,80^FD资产编号:"+printEnt.getCode()+"^FS\n" +
                "^FO50,150^A1,80,80^FD资产类别:"+printEnt.getType()+"^FS\n" +
                "^FO50,250^A1,80,80^FD资产名称:"+printEnt.getName()+"^FS\n" +
                "^FO50,350^A1,80,80^FD资产别名:"+printEnt.getAnotherName()+"^FS\n" +
                "^FO50,450^A1,80,80^FD使用单位:"+printEnt.getDept1()+"^FS\n" +
                "^FO450,530^A1,80,80^FD"+printEnt.getDept2()+"^FS\n" +
                "^FO50,630^A1,80,80^FD安置位置:"+printEnt.getAddress()+"^FS\n" +

                imgZpl +
                "^RFW,H,2,12,1^FD"+printEnt.getCode()+"^FS\n" +
                "^XZ\n").getBytes();  //标签结束
         */
        int fontsize = printEnt.getFontsize();
        configLabel = ("^XA\n" +   //标签开始
                "^JMA\n" +
                "^CI28\n" +
                "^CW1,E:SIMSUN.FNT\n" +
                "^PW"+printEnt.getTagw()+"\n" +
                "^LL"+printEnt.getTagh()+"\n" +
                "^LH0,0\n" +
                "^MD5\n" +
                "^FO"+printEnt.getCodex()+","+printEnt.getCodey()+"^A1,"+fontsize+","+fontsize+"^FD资产编码:"+printEnt.getCode()+"^FS\n" +
                "^FO"+printEnt.getTypex()+","+printEnt.getTypey()+"^A1,"+fontsize+","+fontsize+"^FD资产类别:"+printEnt.getType()+"^FS\n" +
                "^FO"+printEnt.getNamex()+","+printEnt.getNamey()+"^A1,"+fontsize+","+fontsize+"^FD资产名称:"+printEnt.getName()+"^FS\n" +
                "^FO"+printEnt.getAnotherNamex()+","+printEnt.getAnotherNamey()+"^A1,"+fontsize+","+fontsize+"^FD资产别名:"+printEnt.getAnotherName()+"^FS\n" +
                "^FO"+printEnt.getDept1x()+","+printEnt.getDept1y()+"^A1,"+fontsize+","+fontsize+"^FD使用单位:"+printEnt.getDept1()+"^FS\n" +
                "^FO"+printEnt.getDept2x()+","+printEnt.getDept2y()+"^A1,"+fontsize+","+fontsize+"^FD"+printEnt.getDept2()+"^FS\n" +
                "^FO"+printEnt.getAddressx()+","+printEnt.getAddressy()+"^A1,"+fontsize+","+fontsize+"^FD安置位置:"+printEnt.getAddress()+"^FS\n" +

                imgZpl +
                "^RFW,H,2,12,1^FD"+printEnt.getCode()+"^FS\n" +
                "^XZ\n").getBytes();  //标签结束

        connection.write(configLabel);
    }

}

二维码生成,由于zpl自带的二维码 只能放大10 无法满足要求,所以使用图片进行转换

package com.easycomp.utils;

import cn.hutool.extra.qrcode.QrConfig;
import org.apache.commons.lang3.StringUtils;

import java.awt.*;
import java.awt.image.BufferedImage;

/**
 * 创建二维码工具类
 */
public class CreateQrCodeUtil {

    /**
     * 生成二维码--返回BufferedImage
     *
     * @param context       二维码内容
     * @param imgLogoPath   logo路径
     * @param modelImgWidth 模板宽度
     * @param modelHeight   模板高度
     * @param codeWidth     二维码宽度
     * @param codeHeight    二维码高度
     * @return
     */
    public static BufferedImage encode(String context, String imgLogoPath, int modelImgWidth, int modelHeight,
                                       int codeWidth, int codeHeight) throws Exception {

        // 创建主模板图片
        BufferedImage image = new BufferedImage(modelImgWidth, modelHeight, BufferedImage.TYPE_INT_RGB);
        Graphics2D graphics2DModel = image.createGraphics();
        // 设置图片的背景色
        graphics2DModel.setColor(Color.white);
        graphics2DModel.fillRect(0, 0, modelImgWidth, modelHeight);

        //描绘的y轴
        int y = 0;
        //中间二维码
        if (StringUtils.isNotBlank(context)) {
            Graphics2D graphics2DCode = image.createGraphics();
            //hutool的QrConfig配置
            QrConfig qrConfig = new QrConfig();
            qrConfig.setHeight(codeWidth);
            qrConfig.setWidth(codeHeight);
            qrConfig.setBackColor(Color.WHITE);
            if (StringUtils.isNotBlank(imgLogoPath)) {
                qrConfig.setImg(imgLogoPath);
            }
            BufferedImage bufferedImage = cn.hutool.extra.qrcode.QrCodeUtil.generate(context, qrConfig);
            int x = (modelImgWidth - qrConfig.getWidth()) / 2;
            graphics2DCode.drawImage(bufferedImage, x, y, qrConfig.getWidth(), qrConfig.getHeight(), null);
        }
        return image;
    }

}

图片转ZPL代码

package com.easycomp.utils;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * 图片转ZPL语言工具类
 */
public class ZPLConveterUtil {
    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,int x, int y) throws IOException {
        String cuerpo = createBody(image);
        if (compressHex)
            cuerpo = encodeHexAscii(cuerpo);
        return headDoc(x,y) + 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(int x,int y) {
//        String str = "^XA " +
//                "^FO0,0^GFA,"+ total + ","+ total + "," + widthBytes +", ";
//        String str = "^FO1550,350^GFA," + total + "," + total + "," + widthBytes + ", ";
        String str = "^FO"+x+","+y+"^GFA," + total + "," + total + "," + widthBytes + ", ";
        return str;
    }

    private String footDoc() {
//        String str = "^FS"+
//                "^XZ";
        String str = "^FS";
        return str;
    }

    public void setCompressHex(boolean compressHex) {
        this.compressHex = compressHex;
    }

    public void setBlacknessLimitPercentage(int percentage) {
        blackLimit = (percentage * 768 / 100);
    }

}

5.资料

ZPL相关指令说明

6.参考地址

JAVA连接斑马打印机(ZPL) - pxlsdz - 博客园 (cnblogs.com)

用Python操控斑马打印机的技术总结 - 掘金 (juejin.cn)

Labelary Online ZPL Viewer