Browse Source

斑马打印测试

zhuhao 2 years ago
parent
commit
9781a612bc

+ 5 - 1
imcs-admin-boot/imcs-business-biz/pom.xml

@@ -102,7 +102,11 @@
             <artifactId>hutool-all</artifactId>
             <version>5.3.9</version>
         </dependency>
-
+        <dependency>
+            <groupId>cn.zebra</groupId>
+            <artifactId>QRCode</artifactId>
+            <version>1.3.0</version>
+        </dependency>
         <!--<dependency>-->
             <!--<groupId>com.matlab.tool</groupId>-->
             <!--<artifactId>javabuilder</artifactId>-->

+ 190 - 144
imcs-admin-boot/imcs-business-biz/src/main/java/com/github/zuihou/business/util/ZplPrinter.java

@@ -1,51 +1,127 @@
 package com.github.zuihou.business.util;
 
-import org.apache.commons.lang3.StringUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import com.github.zuihou.business.util.qRcode.Image2Zpl;
+import com.github.zuihou.business.util.qRcode.ImageProducerUtil;
+import com.github.zuihou.business.util.qRcode.TwoDimensionCode;
+import lombok.Data;
 
 import javax.print.*;
 import javax.print.attribute.standard.PrinterName;
+import java.awt.image.BufferedImage;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.UnsupportedEncodingException;
 
 
+@Data
 public class ZplPrinter {
-    private static Logger log = LoggerFactory.getLogger(ZplPrinter.class);
-    private String printerURI = null;           //打印机完整路径
-    private PrintService printService = null;   //打印机服务
-    private byte[] font;
-    private String darkness = "~SD22";          //设置色带颜色的深度 0~30
-    private String width = "^PW1200";           //打印宽度 0~1500
-    private String begin = "^XA" + darkness + width;    //标签格式以^XA开始
-    private String end = "^XZ";
-    private String content = "";                //打印内容
-    private String message = "";                //打印的结果信息
+    private String printerURI = null;// 打印机完整路径
+    private PrintService printService = null;// 打印机服务
+    private byte[] dotFont;
+    private String begin = "^XA"; // 标签格式以^XA开始
+    private String end = "^XZ"; // 标签格式以^XZ结束
+    private String content = "";
+
+    public static void main(String[] args) {
+
+        ZplPrinter p = new ZplPrinter("\\\\192.168.11.247\\ZDesigner ZT210-200dpi ZPL");
+        String zpl2 = p.getZpl();
+
+        printBarcode(p,"K&DD_202221390963&TASK_20222139490279&kT_DH001&KT001&000002");
+        boolean result2 = p.print(zpl2);
+        System.out.println("result2=======" + result2);
+
+
+        //  printBarcode();
+        // printQRCOde();
+
+    }
+
+    public static boolean printBarcode(ZplPrinter p,String uniqueCode){
+        String zpl2 = "";
+        try {
+            //String uniqueCode = "K&DD_202221390963&TASK_20222139490279&kT_DH001&KT001&000002";
+            BufferedImage labelImg = ImageProducerUtil.createImage(uniqueCode);
+            zpl2 = Image2Zpl.image2Zpl2(labelImg);
+            System.out.println("zpl2======="+zpl2);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return  p.print(zpl2);
+    }
+    public static void printBarcode() {
+        String electronicCode = "123457FFFFEEEB";
+
+        ZplPrinter zplPrinter = new ZplPrinter("\\\\192.168.11.247\\ZDesigner ZT210-200dpi ZPL");
+        String productName = "product.getName";
+        productName = productName.replace(",", ",");
+        productName = productName.replace("(", "(");
+        productName = productName.replace(")", ")");
+        productName = productName.replace("×", "*");
+        productName = "product.getName";
+        if (productName.length() < 25) {
+            zplPrinter.setText(productName, 15, 10, 25, 25, 15, 1, 1, 24);
+        } else if (productName.length() > 25) {
+            if (productName.length() > 50) {
+                productName = productName.substring(0, 50) + "...";
+            }
+            zplPrinter.setText(productName.substring(0, 25), 15, 10, 25, 25, 15, 1, 1, 24);
+            zplPrinter.setText(productName.substring(25, productName.length()), 15, 40, 25, 25, 15, 1, 1, 24);
+        }
+        String bar0Zpl = "^FO25,80^BY3,3.0,150^BCN,,Y,N,N^FD${data}^FS";//条码样式模板
+        zplPrinter.setBarcode(electronicCode, bar0Zpl);
+        System.out.println(zplPrinter.getZpl());
+        zplPrinter.print(zplPrinter.getZpl());
+    }
+
+    public static void printQRCOde() {
+        // 打印二维码
+        String stockCode = "123457FFFFEEEB";
+
+        ZplPrinter codeZplPrinter = new ZplPrinter("\\\\192.168.11.247\\ZDesigner ZT210-200dpi ZPL");
+        TwoDimensionCode handler = new TwoDimensionCode();
+        BufferedImage bufferedImage = handler.encoderQRCode(stockCode, "png", 9);
+        String codeBegin = Image2Zpl.image2Zpl(bufferedImage);
+
+        codeZplPrinter.setBegin(codeZplPrinter.getBegin() + codeBegin);
+        codeZplPrinter.setContent(codeZplPrinter.getContent() + "^FO50,70^XG" + Image2Zpl.imgLength + ",1,1^FS\n");
+
+        codeZplPrinter.setChar(stockCode, 250, 135, 22, 22);
+
+//        content += "^PQ2";//打印2张
+        codeZplPrinter.print(codeZplPrinter.getZpl());
+
+        codeZplPrinter.print(codeZplPrinter.getZpl());
+    }
+
+
+
 
     /**
      * 构造方法
+     *
+     * @param printerURI 打印机路径
      */
     public ZplPrinter(String printerURI) {
         this.printerURI = printerURI;
-        //加载字体
+        // 加载点阵字库 汉字需要
         String relativelyPath = System.getProperty("user.dir");
         File file = new File(relativelyPath + "//ts24.lib");
         if (file.exists()) {
             FileInputStream fis;
             try {
                 fis = new FileInputStream(file);
-                font = new byte[fis.available()];
-                fis.read(font);
+                dotFont = new byte[fis.available()];
+                fis.read(dotFont);
                 fis.close();
-            } catch (Exception e) {
-                log.info(e.getMessage());
+            } catch (IOException e) {
+                e.printStackTrace();
             }
         } else {
-            log.info("D://lib//ts24.lib 文件不存在");
+            System.out.println("d://ts24.lib文件不存在");
         }
-        //初始化打印机
+        // 初始化打印机
         PrintService[] services = PrintServiceLookup.lookupPrintServices(null, null);
         if (services != null && services.length > 0) {
             for (PrintService service : services) {
@@ -56,27 +132,28 @@ public class ZplPrinter {
             }
         }
         if (printService == null) {
-            log.info("没有找到打印机:[" + printerURI + "]");
+            System.out.println("没有找到打印机:[" + printerURI + "]");
+            // 循环出所有的打印机
             if (services != null && services.length > 0) {
-                log.info("可用的打印机列表:");
+                System.out.println("可用的打印机列表:");
                 for (PrintService service : services) {
-                    log.info("[" + service.getName() + "]");
+                    System.out.println("[" + service.getName() + "]");
                 }
             }
         } else {
-            log.info("找到打印机:[" + printerURI + "]");
-            log.info("打印机名称:[" + printService.getAttribute(PrinterName.class).getValue() + "]");
+            System.out.println("找到打印机:[" + printerURI + "]");
+            System.out.println("打印机名称:[" + printService.getAttribute(PrinterName.class).getValue() + "]");
         }
     }
 
     /**
      * 设置条形码
      *
-     * @param barCode 条码字符
+     * @param barcode 条码字符
      * @param zpl     条码样式模板
      */
-    public void setBarCode(String barCode, String zpl) {
-        content += zpl.replace("${data}", barCode);
+    public void setBarcode(String barcode, String zpl) {
+        content += zpl.replace("${data}", barcode);
     }
 
     /**
@@ -95,38 +172,31 @@ public class ZplPrinter {
     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) font[j + offset] & 0x00ff;
-                        wcode = (int) font[j + offset + 1] & 0x00ff;
-                        int qcode1 = (int) font[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;
+            if (((int) ch[off] & 0x00ff) >= 0xA0) {//ASCII码值"0xa0"表示汉字的开始
+                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;//区码:或qcode = (qcode - 128 - 32) & 0x00ff;(一般这样用)可达到减去0xA0的效果
+                wcode = (wcode + 128 - 32) & 0x00ff;//位码:或wcode = (wcode - 128 - 32) & 0x00ff;(一般这样用)可达到减去0xA0的效果
+                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  --- 以十六进制显示,不足两位则补零
                 }
-            } else if (((int) ch[off] & 0x00FF) < 0xA0) {//英文字符
+                x = x + ms * mx;
+                off = off + 2;//中文包含两个字节
+            } else if (((int) ch[off] & 0x00FF) < 0xA0) {
                 setChar(String.format("%c", ch[off]), x, y, eh, ew);
                 x = x + es;
-                off++;
+                off++;//英文包含一个字节
             }
         }
     }
 
+
     /**
      * 英文字符串(包含数字)
      *
@@ -140,17 +210,54 @@ public class ZplPrinter {
         content += "^FO" + x + "," + y + "^A0," + h + "," + w + "^FD" + str + "^FS";
     }
 
+
     /**
-     * 重置ZPL指令,多张标签同时打印时需要调用
+     * BQ 二维码 ^BQa,b,c,d,e
+     *
+     * @param data
+     * @param x    x坐标
+     * @param y    y坐标
+     * @param b    模型 默认值:2(增强) 推荐 其他值:1
+     * @param c    放大倍数 默认值:1在150 dpi打印机 2在200 dpi打印机 3在300 dpi打印机 其他值:4至10
+     * @param d    校验等级,H Q M L L级:约可纠错7%的数据码字 M级:约可纠错15%的数据码字 Q级:约可纠错25%的数据码字
+     *             H级:约可纠错30%的数据码字
      */
-    public void resetZpl() {
-        begin = "^XA" + darkness + width;
-        end = "^XZ";
-        content = "";
+    public void setCodeByBQ(String data, int x, int y, int b, int c, String d) {
+        content += "^FT" + x + "," + y + "^BQ," + b + "," + c + "," + d + "^FDQA," + data + "^FS";
+    }
+
+
+    /**
+     * 打印方框
+     * ^FO10,10\n^GB50,760,3,B^FS
+     *
+     * @param x x坐标
+     * @param y y坐标
+     * @param w 方框宽度
+     * @param h 方框高度
+     * @param t 线宽
+     */
+    public void setBox(int x, int y, int w, int h, int t) {
+        content += "^FO" + x + "," + y + "^GB" + w + "," + h + "," + t + "^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指令
+     * 获取完整的ZPL
      *
      * @return
      */
@@ -159,22 +266,12 @@ public class ZplPrinter {
     }
 
     /**
-     * 字符串转换为byte[]
-     *
-     * @param s
-     * @return
+     * 重置ZPL指令,当需要打印多张纸的时候需要调用。
      */
-    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;
+    public void resetZpl() {
+        begin = "^XA";
+        end = "^XZ";
+        content = "";
     }
 
     /**
@@ -184,7 +281,7 @@ public class ZplPrinter {
      */
     public boolean print(String zpl) {
         if (printService == null) {
-            log.info("打印出错:没有找到打印机[" + printerURI + "]");
+            System.out.println("打印出错:没有找到打印机:[" + printerURI + "]");
             return false;
         }
         DocPrintJob job = printService.createPrintJob();
@@ -193,83 +290,32 @@ public class ZplPrinter {
         Doc doc = new SimpleDoc(by, flavor, null);
         try {
             job.print(doc, null);
-            log.info("已打印");
+            System.out.println("已打印");
             return true;
         } catch (PrintException e) {
-            log.info("打印出错:" + e.getMessage());
             e.printStackTrace();
             return false;
         }
     }
 
-    public static boolean printBarcode(ZplPrinter printer, String uniqueCode) {
-        if (StringUtils.isNotEmpty(uniqueCode)) {
-            String[] uniqueCodeArray = uniqueCode.split("&");
-            if (uniqueCodeArray.length > 4) {
-                printer.setChar("Order: " + uniqueCodeArray[0] + uniqueCodeArray[1], 40, 20, 30, 30);
-                printer.setChar("Task: " + uniqueCodeArray[2], 40, 70, 30, 30);
-                printer.setChar("SN0: " + uniqueCodeArray[3], 40, 120, 30, 30);
-                printer.setChar("SN: " + uniqueCodeArray[4], 40, 170, 30, 30);
-                printer.setText("生产日期: 2022-11-29", 40, 220, 30, 30, 20, 1, 1, 22);
-                //		printer.setText("生产日期:", 40, 220, 56, 56, 30, 2, 2, 24);
-                //		printer.setChar("2019", 120, 230, 40, 40);
-                //条码
-                //		String data = "9Y203CCNW9A019396";//条码内容
-                //		String dataZpl = "^FO260,250^BY2,11.0,10,40^BCC,80,N^FD${data}^FS";//条码样式模板
-                //		printer.setBarcode(data, dataZpl);
-                //二维码
-                String ewm = "9Y203CCNW9A019396";//条码内容
-                String ewmZpl = "^FO430,50^BQ,2,6^CI26^FH^FDQA^FD${data}^FS";//条码样式模板
-                printer.setBarCode(ewm, ewmZpl);
-                printer.resetZpl();
-                printer.setText("批号:", 20, 550, 56, 56, 30, 2, 2, 24);
-                printer.setChar("78787878788", 200, 560, 40, 40);
-                //下边的条码
-                String bar2 = "00000999990018822969";//20位
-                String bar2Paper = "^FO260,250^BY2,3.0,66^BCN,,Y,N,N^FD${data}^FS";//条码样式模板
-                printer.setBarCode(bar2, bar2Paper);
-                String zpl = printer.getZpl();
-                return printer.print(zpl);
-            }
+    /**
+     * 字符串转byte[]
+     *
+     * @param s
+     * @return
+     */
+    private static byte[] str2bytes(String s) {
+        if (null == s || "".equals(s)) {
+            return null;
         }
-        return false;
-
+        byte[] abytes = null;
+        try {
+            abytes = s.getBytes("gb2312");
+        } catch (UnsupportedEncodingException ex) {
+            ex.printStackTrace();
+        }
+        return abytes;
     }
 
-    public static void main(String[] args) {
-//        ZplPrinter printer = new ZplPrinter("\\\\192.168.11.247\\ZDesigner ZT210-200dpi ZPL");
-//        printBarcode(printer, "K&DD_202221390963&TASK_20222139490279&kT_DH001&KT001&000002");
-        ZplPrinter printer = new ZplPrinter("\\\\192.168.11.247\\ZDesigner ZT210-200dpi ZPL");
-        /**
-         * 文本
-         */
-        printer.setChar("SN: 9Y203CCNW9A19396", 40, 20, 30, 30);
-        printer.setChar("MAC: 74EE2AEB1A52", 40, 70, 30, 30);
-        printer.setChar("DID: 9FCNY21EZJ460B190916", 40, 120, 30, 30);
-        printer.setChar("CMIIT: 2016DP9142", 40, 170, 30, 30);
-//		printer.setText("生产日期:2019", 40, 220 ,30, 30, 20, 1 , 1, 22);
-//		printer.setText("生产日期:", 40, 220, 56, 56, 30, 2, 2, 24);
-//		printer.setChar("2019", 120, 230, 40, 40);
-        //条码
-//		String data = "9Y203CCNW9A019396";//条码内容
-//		String dataZpl = "^FO260,250^BY2,11.0,10,40^BCC,80,N^FD${data}^FS";//条码样式模板
-//		printer.setBarcode(data, dataZpl);
-        //二维码
-        String ewm = "9Y203CCNW9A019396";//条码内容
-        String ewmZpl = "^FO430,50^BQ,2,6^CI26^FH^FDQA^FD${data}^FS";//条码样式模板
-        printer.setBarCode(ewm, ewmZpl);
-        printer.resetZpl();
-        printer.setText("批号:", 20, 550, 56, 56, 30, 2, 2, 24);
-        printer.setChar("78787878788", 200, 560, 40, 40);
-//		printer.setText("批号:", 20, 220, 56, 56, 30, 1, 1, 24);
-//		printer.setChar("78787878788", 120, 230, 40, 40);
-        //下边的条码
-        String bar2 = "00000999990018822969";//20位
-        String bar2Paper = "^FO260,250^BY2,3.0,66^BCN,,Y,N,N^FD${data}^FS";//条码样式模板
-        printer.setBarCode(bar2, bar2Paper);
-        String zpl = printer.getZpl();
-//		System.out.println(zpl);
-        printer.print(zpl);
-    }
-}
 
+}

+ 171 - 0
imcs-admin-boot/imcs-business-biz/src/main/java/com/github/zuihou/business/util/qRcode/Image2Zpl.java

@@ -0,0 +1,171 @@
+package com.github.zuihou.business.util.qRcode;
+
+import javax.imageio.ImageIO;
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.awt.image.DataBufferByte;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * 实现思路:
+ * 1、获取图片的二值化字节数组 这一步是关键
+ * 2、将字节数组转为十六进制
+ * 3、压缩十六进制字符串 结尾为1、0或者与上一行相同的;相同的连续字符压缩
+ * 4、拼凑ZPL编码,宽度需要扩大,因为需要时8个点(1字节)的整数倍
+ */
+public class Image2Zpl {
+
+	public static int imgLength = 0;
+    static Pattern ZEROS=Pattern.compile("0+$"),ONES=Pattern.compile("1+$"),MULTI_W=Pattern.compile("([0-9A-Z])\\1{2,}");
+
+    public static void main(String[] args) throws IOException {
+        System.out.println(image2Zpl(ImageIO.read(new File("d://label1.png"))));
+    }
+
+    /**
+     * 第一种:只把二维码图片转换成相对应的zpl指令
+     * @param image
+     * @return
+     */
+    public static String image2Zpl(BufferedImage image) {
+        //获取图片的字节数组
+        DataBufferByte data=(DataBufferByte) getBinaryGrayImage(image).getRaster().getDataBuffer();
+        byte[] imgData=data.getData();
+        
+        System.out.println("image.getWidth(): "+image.getWidth());
+        int newW=(image.getWidth()+7)/8;//实际每行字节大小,8个点,每个点1位,共8位
+        String[] strs=byte2HexStr(imgData,newW);
+        int bytes=imgData.length;
+        imgLength = bytes;
+//        return String.format("^XA~DG%d,%d,%d,%s^FO50,50^XG%d,1,1^FS^XZ", bytes, bytes, newW, compress(strs),bytes);
+        return String.format("~DG%d,%d,%d,%s", bytes, bytes, newW, compress(strs));
+    }
+
+    /**
+     * 把整个标签图片转换成完成的zpl指令
+     * @param image
+     * @return
+     */
+    public static String image2Zpl2(BufferedImage image) throws Exception{
+
+        File file = new File("d://a2.jpg");
+        OutputStream out = new FileOutputStream(file);
+        ImageIO.write(image, "jpg", out);
+        out.close();
+
+        //获取图片的字节数组
+        DataBufferByte data=(DataBufferByte) getBinaryGrayImage(image).getRaster().getDataBuffer();
+        byte[] imgData=data.getData();
+        
+        System.out.println("image.getWidth(): "+image.getWidth());
+        int newW=(image.getWidth()+7)/8;//实际每行字节大小,8个点,每个点1位,共8位
+        String[] strs=byte2HexStr(imgData,newW);
+        int bytes=imgData.length;
+        imgLength = bytes;
+        return String.format("^XA~DG%d,%d,%d,%s^FO50,50^XG%d,1,1^FS^XZ", bytes, bytes, newW, compress(strs),bytes);
+//        return String.format("~DG%d,%d,%d,%s", bytes, bytes, newW, compress(strs));
+    }
+
+    /**
+     * 获取二值化图,并取反
+     * @param srcImage
+     * @return
+     */
+    private static BufferedImage getBinaryGrayImage(BufferedImage srcImage) {
+        BufferedImage dstImage = new BufferedImage(srcImage.getWidth(), srcImage.getHeight(), BufferedImage.TYPE_BYTE_BINARY);
+        dstImage.getGraphics().drawImage(srcImage, 0, 0, null);
+        for (int y = 0; y < dstImage.getHeight(); y++) {
+            for (int x = 0; x < dstImage.getWidth(); x++) {
+                Color color = new Color(dstImage.getRGB(x, y));
+                //获取该点的像素的RGB的颜色
+                Color newColor = new Color(255 - color.getRed(), 255 - color.getGreen(), 255 - color.getBlue());
+                dstImage.setRGB(x, y, newColor.getRGB());
+            }
+        }
+        return dstImage;
+    }
+
+    /**
+     * 压缩图片数据
+     * @param data
+     * @return
+     */
+    private static String compress(String[] data) {
+        StringBuffer sb=new StringBuffer();
+        String pre=null;
+        for(String d:data){
+            String a=d;
+            Matcher m=ZEROS.matcher(a);
+            if(m.find()){
+                a=m.replaceFirst(",");
+            }
+
+            m=ONES.matcher(a);
+            if(m.find()){
+                a=m.replaceFirst("!");
+            }
+
+            a=minimizeSameWord(a);
+
+            if(pre!=null && a.equals(pre)){
+                a=":";
+            }else{
+                pre=a;
+            }
+            sb.append(a);
+            sb.append("\n");
+        }
+        return sb.toString();
+    }
+
+    /**
+     * 十六进制串中相同字母压缩
+     * @param str
+     * @return
+     */
+    private static String minimizeSameWord(String str) {
+        Matcher matcher=MULTI_W.matcher(str);
+        while (matcher.find()){
+            String group=matcher.group();
+            int len=group.length();
+            String c="";
+            if(len>20){
+                c=Character.toString((char) ('f' + len / 20));
+            }
+            if(len%20>0){
+                c=c+Character.toString((char)('F'+len%20));
+            }
+
+            str=str.replaceFirst(group, c + group.charAt(0));
+        }
+        return str;
+    }
+
+
+
+    /**
+     * 字节数组转为十六进制
+     * @param b
+     * @param rowSize
+     * @return
+     */
+    private static String[] byte2HexStr(byte[] b,int rowSize) {
+        int len=b.length/rowSize;
+        String[] arr=new String[len];
+        for (int n=0;n<len;n++) {
+            StringBuffer hs=new StringBuffer();
+            for(int j=0;j<rowSize;j++){
+                String stmp=Integer.toHexString(b[n*rowSize+j] & 0XFF);
+                if (stmp.length()==1) hs.append("0");
+                hs.append(stmp);
+            }
+            arr[n]=hs.toString().toUpperCase();
+        }
+        return arr;
+    }
+}

+ 94 - 0
imcs-admin-boot/imcs-business-biz/src/main/java/com/github/zuihou/business/util/qRcode/ImageProducerUtil.java

@@ -0,0 +1,94 @@
+package com.github.zuihou.business.util.qRcode;
+
+import java.awt.*;
+import java.awt.image.BufferedImage;
+
+
+public class ImageProducerUtil {
+
+    public static void main(String[] args) throws Exception {
+        new ImageProducerUtil().createImage("");
+    }
+
+
+    /**
+     * 获取字体高度
+     *
+     * @param font
+     * @return
+     */
+    private static int getFontHeight(Font font) {
+        return sun.font.FontDesignMetrics.getMetrics(font).getHeight();
+    }
+
+
+    /**
+     * 先把整个标签做成图像缓存
+     *
+     * @throws Exception
+     */
+    public static BufferedImage createImage(String unqueCode) throws Exception {
+
+        Font font1 = new Font("黑体", Font.BOLD, 36);//标题字体
+        Font font2 = new Font("宋体", Font.BOLD, 28);//内容字体
+        Font font3 = new Font("宋体", Font.BOLD, 20);//编号字体
+
+        // 创建图片
+        BufferedImage image = new BufferedImage(480, 320, BufferedImage.TYPE_INT_BGR);// 创建图片画布
+        Graphics g = image.getGraphics();
+        g.setColor(Color.WHITE); // 先用白色填充整张图片,也就是背景
+        g.fillRect(0, 0, 480, 320);// 画出矩形区域,以便于在矩形区域内写入文字
+        g.setColor(Color.black);// 再换成黑色,以便于写入文字
+        //g.setFont(font1);// 设置画笔字体
+//		g.drawString("样品标识", 120, 42);// 画出一行字符串
+//		g.setFont(font2);
+//		g.drawString("产品名称:", 5, 74);
+        g.setFont(font3);
+        g.drawString("产品名称: 前格框", 20, 116);
+        g.setFont(font3);
+//		g.drawString("日期:", 5, 140);
+//		g.setFont(font3);
+        g.drawString("日期: 2022-11-30", 20, 180);
+        g.setFont(font3);
+        g.drawString("云箭集团", 35, 245);
+
+        //二维码
+        TwoDimensionCode handler = new TwoDimensionCode();
+        String encoderContentStr = "K&DD_202221390963&TASK_20222139490279&kT_DH001&KT001&000002";
+        BufferedImage codeImg = handler.encoderQRCode(encoderContentStr, "png", 11);
+        g.drawImage(codeImg, 260, 60, codeImg.getWidth(), codeImg.getHeight(), null);
+
+        g.dispose();
+
+        return image;
+    }
+
+    public static BufferedImage createImage1() throws Exception {
+
+        Font font1 = new Font("黑体", Font.BOLD, 36);//标题字体
+        Font font2 = new Font("宋体", Font.BOLD, 10);//内容字体
+        Font font3 = new Font("宋体", Font.BOLD, 24);//编号字体
+
+        int w = 700, h = 350;
+        // 创建图片
+        BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_BGR);// 创建图片画布
+        Graphics g = image.getGraphics();
+        g.setColor(Color.WHITE); // 先用白色填充整张图片,也就是背景
+        g.fillRect(0, 0, w, h);// 画出矩形区域,以便于在矩形区域内写入文字
+        g.setColor(Color.black);// 再换成黑色,以便于写入文字
+        g.setFont(font1);// 设置画笔字体
+        g.drawString("商品名称1234,,,,,,,,,,()()", 10, 30);// 画出一行字符串
+        g.setFont(font2);
+
+
+        //二维码
+        TwoDimensionCode handler = new TwoDimensionCode();
+        String encoderContentStr = "样品编号:TX2-18/03/29-003-123456-123\n委托编号:CEPR1-TX2-2018-130-1234567";
+        BufferedImage codeImg = handler.encoderQRCode(encoderContentStr, "png", 9);
+        g.drawImage(codeImg, 40, 50, codeImg.getWidth(), codeImg.getHeight(), null);
+        g.dispose();
+
+        return image;
+    }
+
+}

+ 261 - 0
imcs-admin-boot/imcs-business-biz/src/main/java/com/github/zuihou/business/util/qRcode/TwoDimensionCode.java

@@ -0,0 +1,261 @@
+package com.github.zuihou.business.util.qRcode;
+
+import com.swetake.util.Qrcode;
+import jp.sourceforge.qrcode.QRCodeDecoder;
+import jp.sourceforge.qrcode.exception.DecodingFailedException;
+
+import javax.imageio.ImageIO;
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+public class TwoDimensionCode {
+
+	/**
+	 * 生成二维码(QRCode)图片
+	 * 
+	 * @param content
+	 *            存储内容
+	 * @param imgPath
+	 *            图片路径
+	 */
+	public void encoderQRCode(String content, String imgPath) {
+		this.encoderQRCode(content, imgPath, "png", 7);
+	}
+
+	/**
+	 * 生成二维码(QRCode)图片
+	 * 
+	 * @param content
+	 *            存储内容
+	 * @param output
+	 *            输出流
+	 */
+	public void encoderQRCode(String content, OutputStream output) {
+		this.encoderQRCode(content, output, "png", 7);
+	}
+
+	/**
+	 * 生成二维码(QRCode)图片
+	 * 
+	 * @param content
+	 *            存储内容
+	 * @param imgPath
+	 *            图片路径
+	 * @param imgType
+	 *            图片类型
+	 */
+	public void encoderQRCode(String content, String imgPath, String imgType) {
+		this.encoderQRCode(content, imgPath, imgType, 7);
+	}
+
+	/**
+	 * 生成二维码(QRCode)图片
+	 * 
+	 * @param content
+	 *            存储内容
+	 * @param output
+	 *            输出流
+	 * @param imgType
+	 *            图片类型
+	 */
+	public void encoderQRCode(String content, OutputStream output,
+			String imgType) {
+		this.encoderQRCode(content, output, imgType, 10);
+	}
+
+	/**
+	 * 生成二维码(QRCode)图片
+	 * 
+	 * @param content
+	 *            存储内容
+	 * @param imgPath
+	 *            图片路径
+	 * @param imgType
+	 *            图片类型
+	 * @param size
+	 *            二维码尺寸
+	 */
+	public void encoderQRCode(String content, String imgPath, String imgType, int size) {
+		try {
+			BufferedImage bufImg = this.qRCodeCommon(content, imgType, size);
+
+			File imgFile = new File(imgPath);
+			// 生成二维码QRCode图片
+			ImageIO.write(bufImg, imgType, imgFile);
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+	}
+	/**
+	 * 生成二维码(QRCode)图像缓存
+	 * 
+	 * @param content
+	 *            存储内容
+	 * @param size
+	 *            二维码尺寸
+	 */
+	public BufferedImage encoderQRCode(String content, String imgType, int size) {
+		try {
+			BufferedImage bufImg = this.qRCodeCommon(content, imgType, size);
+			
+			return bufImg;
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+		return null;
+	}
+
+	/**
+	 * 生成二维码(QRCode)图片
+	 * 
+	 * @param content
+	 *            存储内容
+	 * @param output
+	 *            输出流
+	 * @param imgType
+	 *            图片类型
+	 * @param size
+	 *            二维码尺寸
+	 */
+	public void encoderQRCode(String content, OutputStream output,
+			String imgType, int size) {
+		try {
+			BufferedImage bufImg = this.qRCodeCommon(content, imgType, size);
+			// 生成二维码QRCode图片
+			ImageIO.write(bufImg, imgType, output);
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+	}
+
+	/**
+	 * 生成二维码(QRCode)图片的公共方法
+	 * 
+	 * @param content
+	 *            存储内容
+	 * @param imgType
+	 *            图片类型
+	 * @param size
+	 *            二维码尺寸
+	 * @return
+	 */
+	private BufferedImage qRCodeCommon(String content, String imgType, int size) {
+		BufferedImage bufImg = null;
+		try {
+			Qrcode qrcodeHandler = new Qrcode();
+			// 设置二维码排错率,可选L(7%)、M(15%)、Q(25%)、H(30%),排错率越高可存储的信息越少,但对二维码清晰度的要求越小
+			qrcodeHandler.setQrcodeErrorCorrect('L');
+			qrcodeHandler.setQrcodeEncodeMode('B');//注意版本信息 N代表数字 、A代表 a-z,A-Z、B代表 其他)
+			// 设置设置二维码尺寸,取值范围1-40,值越大尺寸越大,可存储的信息越大
+			qrcodeHandler.setQrcodeVersion(size);
+			// 获得内容的字节数组,设置编码格式
+			byte[] contentBytes = content.getBytes("utf-8");
+			// 图片尺寸
+			int imgSize = 67 + 12 * (size - 1);
+			bufImg = new BufferedImage(imgSize, imgSize, BufferedImage.TYPE_INT_RGB);
+			Graphics2D gs = bufImg.createGraphics();
+			// 设置背景颜色
+			gs.setBackground(Color.WHITE);
+			gs.clearRect(0, 0, imgSize, imgSize);
+
+			// 设定图像颜色> BLACK
+			gs.setColor(Color.BLACK);
+			// 设置偏移量,不设置可能导致解析出错
+			int pixoff = 2;
+			// 输出内容> 二维码
+			if (contentBytes.length > 0 && contentBytes.length < 800) {
+				boolean[][] codeOut = qrcodeHandler.calQrcode(contentBytes);
+				for (int i = 0; i < codeOut.length; i++) {
+					for (int j = 0; j < codeOut.length; j++) {
+						if (codeOut[j][i]) {
+							gs.fillRect(j * 3 + pixoff, i * 3 + pixoff, 3, 3);
+						}
+					}
+				}
+			} else {
+				throw new Exception("QRCode content bytes length = "
+						+ contentBytes.length + " not in [0, 800].");
+			}
+			gs.dispose();
+			bufImg.flush();
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+		return bufImg;
+	}
+
+	/**
+	 * 解析二维码(QRCode)
+	 * 
+	 * @param imgPath
+	 *            图片路径
+	 * @return
+	 */
+	public String decoderQRCode(String imgPath) {
+		// QRCode 二维码图片的文件
+		File imageFile = new File(imgPath);
+		BufferedImage bufImg = null;
+		String content = null;
+		try {
+			bufImg = ImageIO.read(imageFile);
+			QRCodeDecoder decoder = new QRCodeDecoder();
+			content = new String(decoder.decode(new TwoDimensionCodeImage(bufImg)), "utf-8");
+		} catch (IOException e) {
+			System.out.println("Error: " + e.getMessage());
+			e.printStackTrace();
+		} catch (DecodingFailedException dfe) {
+			System.out.println("Error: " + dfe.getMessage());
+			dfe.printStackTrace();
+		}
+		return content;
+	}
+
+	/**
+	 * 解析二维码(QRCode)
+	 * 
+	 * @param input
+	 *            输入流
+	 * @return
+	 */
+	public String decoderQRCode(InputStream input) {
+		BufferedImage bufImg = null;
+		String content = null;
+		try {
+			bufImg = ImageIO.read(input);
+			QRCodeDecoder decoder = new QRCodeDecoder();
+			content = new String(decoder.decode(new TwoDimensionCodeImage(
+					bufImg)), "utf-8");
+		} catch (IOException e) {
+			System.out.println("Error: " + e.getMessage());
+			e.printStackTrace();
+		} catch (DecodingFailedException dfe) {
+			System.out.println("Error: " + dfe.getMessage());
+			dfe.printStackTrace();
+		}
+		return content;
+	}
+
+	public static void main(String[] args) {
+
+		String imgPath = "d:\\code4.png";
+		String encoderContent = "样品编号:SGSIL-18/03/29-001-1-20 \n样品名称:一二三四五六七八九十一二三四五六七八九十一二三四五六七八九十一二三四五六七八九十一二三四五六七八九十一二 \n委托编号:CEPR1-SGSIL-2018-9999";
+//		String encoderContent = "样品编号:TX2-18/03/29-0003\n样品名称:生产制造执行系统生产制造执行生产制造执行系统生产制造执行系统生产制生产制造执行系统生产制造执行系统生产制\n委托编号:CEPR1-TX2-2018-1300";
+//		String encoderContent = "样品编号:TX2-18/03/29-003-123456-123\n委托编号:CEPR1-TX2-2018-130-1234567";
+
+		TwoDimensionCode handler = new TwoDimensionCode();
+
+		handler.encoderQRCode(encoderContent, imgPath, "png", 10);
+		System.out.println(encoderContent.length());
+		System.out.println("=============编码成功!图片为于:" + imgPath + "===============");
+
+		String decoderContent = handler.decoderQRCode(imgPath);
+		System.out.println("============解析结果如下:===============");
+		System.out.println(decoderContent);
+		System.out.println("=========解码成功===========");
+	}
+	
+}

+ 30 - 0
imcs-admin-boot/imcs-business-biz/src/main/java/com/github/zuihou/business/util/qRcode/TwoDimensionCodeImage.java

@@ -0,0 +1,30 @@
+package com.github.zuihou.business.util.qRcode;
+
+import jp.sourceforge.qrcode.data.QRCodeImage;
+
+import java.awt.image.BufferedImage;
+
+public class TwoDimensionCodeImage implements QRCodeImage {
+
+	BufferedImage bufImg;
+
+	public TwoDimensionCodeImage(BufferedImage bufImg) {
+		this.bufImg = bufImg;
+	}
+
+	@Override
+	public int getHeight() {
+		return bufImg.getHeight();
+	}
+
+	@Override
+	public int getPixel(int x, int y) {
+		return bufImg.getRGB(x, y);
+	}
+
+	@Override
+	public int getWidth() {
+		return bufImg.getWidth();
+	}
+
+}