Java对接Zebra斑马打印机打印条形码相关

        最近在公司里面做了个业务,主要是对接工业打印机打印条形码,然后在CSDN和稀土掘金看了一下其他的方案很久嘛,然后自己又总结了一些,加入了进来,方法可能有点low,大家有更好的方案推荐,可以评论区call下。

        在这里主要是对接的一台比较老的机型,Zebra S4M机型 203Pi。

        用到的亚银标签纸格式是60mm*38mm , 碳带也是60mm的,不过其他型号应该也是倒差不差的,差不了太多。

        本文参考了本文Java调用Zebra800条码打印机_ts24.lib_fmwind的博客-CSDN博客

        话不多说,直接上代码!

package com.south.framework.web.testPrint;

import javax.print.*;
import javax.print.attribute.standard.PrinterName;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;

//import sun.awt.AppContext;

/**
 * 采用点阵字库ts24.lib
 * @author Labrador
 *
 */
public class ZplPrinter {
    private String printerURI = null;			//打印机完整路径
    private PrintService printService = null;	//打印机服务
    private byte[] dotFont;
    private String darkness = "~SD22";	//Set Darkness设置色带颜色的深度 0-30
    private String width = "^PW1200";	//Print Width打印宽度0-1500
    private String length = "^LL800";	//Label Length标签长度0-x(暂无作用)
    private String begin = "^XA" + darkness + width;	//标签格式以^XA开始
    private String end = "^XZ";			//标签格式以^XZ结束
    private String content = "";		//打印内容
    private String message = "";		//打印的结果信息

    /**
     * 构造方法
     * @param printerURI 打印机路径
     */
    public ZplPrinter(String printerURI){
        this.printerURI = printerURI;
        //加载字体  点阵图文件
        File file = new File("D:\\ts24.lib");
        if(file.exists()){
            FileInputStream fis;
            try {
                fis = new FileInputStream(file);
                dotFont = new byte[fis.available()];
                fis.read(dotFont);
                fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }else{
            System.out.println("D://ts24.lib文件不存在");
        }
        //初始化打印机
        PrintService[] services = PrintServiceLookup.lookupPrintServices(null,null);
        if (services != null && services.length > 0) {
            for (PrintService service : services) {
                if (printerURI.equals(service.getName())) {
                    printService = service;
                    break;
                }
            }
        }
        if (printService == null) {
            System.out.println("没有找到打印机:["+printerURI+"]");
            //循环出所有的打印机
            if (services != null && services.length > 0) {
                System.out.println("可用的打印机列表:");
                for (PrintService service : services) {
                    System.out.println("["+service.getName()+"]");
                }
            }
        }else{
            System.out.println("找到打印机:["+printerURI+"]");
            System.out.println("打印机名称:["+printService.getAttribute(PrinterName.class).getValue()+"]");
        }
    }
    /**
     * 设置条形码
     * @param barcode 条码字符
     * @param zpl 条码样式模板
     */
    public void setBarcode(String barcode,String zpl) {
        content += zpl.replace("${data}", barcode);
    }

    /**
     * 中文字符、英文字符(包含数字)混合
     * @param str 中文、英文
     * @param x x坐标
     * @param y y坐标
     * @param eh 英文字体高度height
     * @param ew 英文字体宽度width
     * @param es 英文字体间距spacing
     * @param mx 中文x轴字体图形放大倍率。范围1-10,默认1
     * @param my 中文y轴字体图形放大倍率。范围1-10,默认1
     * @param ms 中文字体间距。24是个比较合适的值。
     */
    public void setText(String str, int x, int y, int eh, int ew, int es, int mx, int my, int ms) {
        byte[] ch = str2bytes(str);
        for (int off = 0; off < ch.length;) {
            if (((int) ch[off] & 0x00ff) >= 0xA0) {//中文字符
                try {
                    int qcode = ch[off] & 0xff;
                    int wcode = ch[off + 1] & 0xff;
                    content += String.format("^FO%d,%d^XG0000%01X%01X,%d,%d^FS\n", x, y, qcode, wcode, mx, my);
                    begin += String.format("~DG0000%02X%02X,00072,003,\n", qcode, wcode);
                    qcode = (qcode + 128 - 32) & 0x00ff;
                    wcode = (wcode + 128 - 32) & 0x00ff;
                    int offset = ((int) qcode - 16) * 94 * 72 + ((int) wcode - 1) * 72;
                    for (int j = 0; j < 72; j += 3) {
                        qcode = (int) dotFont[j + offset] & 0x00ff;
                        wcode = (int) dotFont[j + offset + 1] & 0x00ff;
                        int qcode1 = (int) dotFont[j + offset + 2] & 0x00ff;
                        begin += String.format("%02X%02X%02X\n", qcode, wcode, qcode1);
                    }
                    x = x + ms * mx;
                    off = off + 2;
                } catch (Exception e) {
                    e.printStackTrace();
                    //替换成X号
                    setChar("X", x, y, eh, ew);
                    x = x + es;//注意间距更改为英文字符间距
                    off = off + 2;
                }
            } else if (((int) ch[off] & 0x00FF) < 0xA0) {//英文字符
                setChar(String.format("%c", ch[off]), x, y, eh, ew);
                x = x + es;
                off++;
            }
        }
    }
    /**
     * 英文字符串(包含数字)
     * @param str 英文字符串
     * @param x	x坐标
     * @param y y坐标
     * @param h 高度
     * @param w 宽度
     */
    public void setChar(String str, int x, int y, int h, int w) {
        content += "^FO" + x + "," + y + "^A0," + h + "," + w + "^FD" + str + "^FS";
    }
    /**
     * 英文字符(包含数字)顺时针旋转90度
     * @param str 英文字符串
     * @param x	x坐标
     * @param y y坐标
     * @param h 高度
     * @param w 宽度
     */
    public void setCharR(String str, int x, int y, int h, int w) {
        content += "^FO" + x + "," + y + "^A0R," + h + "," + w + "^FD" + str + "^FS";
    }

    /**
     * ZPL条形码边框指令设置
     * @param x         边框的最右侧X轴坐标
     * @param y         边框的最右侧y轴坐标
     * @param width     边框的宽度
     * @param height    边框的高度
     * @param thickness 边框的粗细程度
     * */
    public void setBox(int x, int y, int width, int height, int thickness) {
        content += "^FO" + x + "," + y + "^GB" + width + "," + height + "," + thickness + "B^FS";
    }

    /**
     * ZPL条形码边框指令设置
     * @param x     边框的最右侧X轴坐标
     * @param y     边框的最右侧y轴坐标
     * @param h     条形码的高度设置
     * @param w     条形码的宽度设置
     * @param hw    条形码的宽高比 指宽度是高的倍数,不过好像有点瓦
     * @param size  设置条形码条码格式,可以不填,不填就是打印机将自动根据条码数据的内容选择最适合的条码格式。
     * Y,N,N 分别表示 第一个参数 Y 表示显示校验码,第二个参数 N 表示不显示文字标签,第二个参数 N 表示不显示文字标签。
     * 他还有一种写法 FO30,230^BY2,2,50^BCN,32,Y,N,N^FD>;EDEzj200303170006^FS 这里的>;起始符是为了告诉打印机这是Code 128条形码的起始位置
     * */
    public String setZPLGrammer(int x,int y,double h,int w,int hw,int size){
        return "^FO"+x+","+y+"^BY"+h+","+w+","+hw+"^BCN,"+size+",Y,N,N^FD${data}^FS";
    }
    /**
     * 获取完整的ZPL
     * @return
     */
    public String getZpl() {
        return begin + content + end;
    }
    /**
     * 重置ZPL指令,当需要打印多张纸的时候需要调用。
     */
    public void resetZpl() {
        begin = "^XA" + darkness + width;
        end = "^XZ";
        content = "";
    }
    /**
     * 打印
     * @param zpl 完整的ZPL
     */
    public boolean print(String zpl){
        if(printService==null){
            message = "打印出错:没有找到打印机["+printerURI+"]";
            System.out.println("打印出错:没有找到打印机["+printerURI+"]");
            return false;
        }
        DocPrintJob job = printService.createPrintJob();
        byte[] by = zpl.getBytes();
        DocFlavor flavor = DocFlavor.BYTE_ARRAY.AUTOSENSE;
        Doc doc = new SimpleDoc(by, flavor, null);
        try {
            job.print(doc, null);
            message = "已打印";
            System.out.println("已打印");
            return true;
        } catch (PrintException e) {
            message = "打印出错:"+e.getMessage();
            System.out.println("打印出错:"+e.getMessage());
            e.printStackTrace();
            return false;
        }
    }
    public String getMessage(){
        return message;
    }
    /**
     * 字符串转byte[]
     * @param s
     * @return
     */
    private byte[] str2bytes(String s) {
        if (null == s || "".equals(s)) {
            return null;
        }
        byte[] abytes = null;
        try {
            abytes = s.getBytes("gb2312");
        } catch (UnsupportedEncodingException ex) {
            ex.printStackTrace();
        }
        return abytes;
    }
    /**
     *
     * @param unit 单位名称
     * @param orderId 工单号
     * @param type 类别
     */
    public static boolean printPicking(String unit,String orderId,String type){
        ZplPrinter p = new ZplPrinter("ZDesigner S4M-203dpi ZPL");
        p.setText(unit, 253, 26, 40, 40, 20, 1, 1, 24);
        p.setChar(orderId, 253, 76, 20, 20);
        p.setText(type, 253, 120, 53, 53, 20, 1, 1, 24);
        String zpl = p.getZpl();
        //System.out.println(zpl);
        boolean flag=p.print(zpl);
        return flag;
    }

}

        这个是调用打印机的工具类代码,之看到CSDN别人的,然后可能加了些其他功能上去。

        再来看测试类,封装了一个对象传进去在main方法里面进行测试。

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Objects;

public class ZplPrinterTest {
	public static void main(String[] args) throws ParseException {
		// 选择自己的打印机
		ZplPrinter zplPrinter = new ZplPrinter("ZDesigner S4M-203dpi ZPL");

		PrintGoods printGoods = new PrintGoods(
				"测试打印电脑标签纸",
				"戴尔主机",
				"1234567890",
				"222222A22M2222B222JH",
				new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()),
				"DEzj200303170006");

		// 打印抬头
		zplPrinter.setText(printGoods.getTitileName(), 125, 10,40, 40, 20, 1, 1, 24);
		// 打印边框
		// 设置左边框
		zplPrinter.setBox(15,40,550,40,3);
		zplPrinter.setBox(15,80,550,40,3);
		zplPrinter.setBox(15,120,550,40,3);
		zplPrinter.setBox(15,160,550,40,3);
		zplPrinter.setBox(15,200,550,80,3);
		// 设置右边框
		zplPrinter.setBox(460,40,550,40,3);
		zplPrinter.setBox(460,80,550,40,3);
		zplPrinter.setBox(460,120,550,40,3);
		zplPrinter.setBox(460,160,550,40,3);
		zplPrinter.setBox(460,160,550,40,3);
		zplPrinter.setBox(460,200,550,80,3);
		// 打印字段
		zplPrinter.setText("设备编码", 50, 50, 40, 40, 20, 1, 1, 24);
		zplPrinter.setChar(printGoods.getCoding(), 170, 55, 20, 20);

		zplPrinter.setText("资产名称", 50, 90, 40, 40, 20, 1, 1, 24);
		zplPrinter.setText(printGoods.getGoodsName(), 170, 90, 40, 40, 20, 1, 1, 24);

		zplPrinter.setText("设备", 50, 130, 40, 40, 20, 1, 1, 24);
		zplPrinter.setChar("S/N", 100, 135, 20, 20);
		zplPrinter.setText("码", 130, 130, 40, 40, 20, 1, 1, 24);
		zplPrinter.setChar(printGoods.getSn(), 170, 135, 20, 20);

		zplPrinter.setText("购买时间", 50, 170, 53, 53, 20, 1, 1, 24);
		zplPrinter.setChar(printGoods.getShopTime(), 170, 175, 20, 20);
		// ZPL解析语句
		String bar2Pap = "^FO30,215^BY1.5,30,100^BCN,32,Y,N,N^FD${data}^FS";//条码样式模板
		zplPrinter.setZPLGrammer(30,215,1.5,30,100,32);
		// 将${data}替换成扫描二维码后展示的数据
		zplPrinter.setBarcode(printGoods.getBarCode(),bar2Pap);
		// 执行打印方法
		zplPrinter.print(zplPrinter.getZpl());
	}

static class PrintGoods {
	private String titileName;
	private String goodsName;
	private String coding;
	private String sn;
	private String shopTime;
	private String barCode;

	public PrintGoods() {}

	public PrintGoods(String titileName, String goodsName, String shopTime, String coding, String sn,String barCode) {
		this.titileName = titileName;
		this.goodsName = goodsName;
		this.coding = coding;
		this.sn = sn;
		this.shopTime = shopTime;
		this.barCode = barCode;
	}

	public String getTitileName() {
		return titileName;
	}

	public void setTitileName(String titileName) {
		this.titileName = titileName;
	}

	public String getGoodsName() {
		return goodsName;
	}

	public void setGoodsName(String goodsName) {
		this.goodsName = goodsName;
	}

	public String getShopTime() {
		return shopTime;
	}

	public void setShopTime(String shopTime) {
		this.shopTime = shopTime;
	}

	public String getCoding() {
		return coding;
	}

	public void setCoding(String coding) {
		this.coding = coding;
	}

	public String getSn() {
		return sn;
	}

	public void setSn(String sn) {
		this.sn = sn;
	}

	public String getBarCode() {
		return barCode;
	}

	public void setBarCode(String barCode) {
		this.barCode = barCode;
	}
	@Override
	public String toString() {
		return "PrintGoods{" +
				"titileName='" + titileName + '\'' +
				", goodsName='" + goodsName + '\'' +
				", shopTime='" + shopTime + '\'' +
				", coding='" + coding + '\'' +
				", sn='" + sn + '\'' +
				'}';
	}

	@Override
	public boolean equals(Object o) {
		if (this == o) return true;
		if (!(o instanceof PrintGoods)) return false;
		PrintGoods that = (PrintGoods) o;
		return Objects.equals(titileName, that.titileName) &&
				Objects.equals(goodsName, that.goodsName) &&
				Objects.equals(shopTime, that.shopTime) &&
				Objects.equals(coding, that.coding) &&
				Objects.equals(sn, that.sn);
	}

	@Override
	public int hashCode() {
		return Objects.hash(titileName, goodsName, shopTime, coding, sn);
	}
}

}

详细的讲解也写在里面的注释了,反正就是对于中文和英文数字是有格式要求的,中文要用setText指令来执行,英文和数字要用setChar指令执行

在这里可能需要用到一个点阵图ts24.lib,这个文件的链接我就放在下方了,不出意外就是长期有效了

链接:https://pan.baidu.com/s/1mUpF6xEzbiZRtADzQNTP3w?pwd=yyds
提取码:yyds

  • 13
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值