|
|
@ -8,6 +8,17 @@ import lombok.extern.slf4j.Slf4j; |
|
|
import java.math.BigDecimal; |
|
|
import java.math.BigDecimal; |
|
|
import java.util.List; |
|
|
import java.util.List; |
|
|
|
|
|
|
|
|
|
|
|
import com.google.zxing.*; |
|
|
|
|
|
import com.google.zxing.client.j2se.MatrixToImageWriter; |
|
|
|
|
|
import com.google.zxing.common.BitMatrix; |
|
|
|
|
|
|
|
|
|
|
|
import javax.imageio.ImageIO; |
|
|
|
|
|
import java.awt.image.BufferedImage; |
|
|
|
|
|
import java.io.ByteArrayInputStream; |
|
|
|
|
|
import java.io.ByteArrayOutputStream; |
|
|
|
|
|
import java.util.HashMap; |
|
|
|
|
|
import java.util.Map; |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* ZPL代码生成器 |
|
|
* ZPL代码生成器 |
|
|
* 统一处理不同打印方向的ZPL代码生成 |
|
|
* 统一处理不同打印方向的ZPL代码生成 |
|
|
@ -382,32 +393,83 @@ public class ZplGenerator { |
|
|
* 生成二维码ZPL代码 |
|
|
* 生成二维码ZPL代码 |
|
|
*/ |
|
|
*/ |
|
|
private String generateQRCodeZPL(ReportLabelList element, int x, int y) { |
|
|
private String generateQRCodeZPL(ReportLabelList element, int x, int y) { |
|
|
String orientation = config.getQrcodeOrientation(); |
|
|
|
|
|
String data = element.getData() != null ? element.getData() : ""; |
|
|
String data = element.getData() != null ? element.getData() : ""; |
|
|
|
|
|
|
|
|
// 将毫米转换为ZPL尺寸单位 |
|
|
// 将毫米转换为ZPL尺寸单位 |
|
|
int sizeInDots = Math.max(1, Math.round((element.getHeight() != null ? element.getHeight() : 10) * this.dpi / 25.4f)); |
|
|
int sizeInDots = Math.max(1, Math.round((element.getHeight() != null ? element.getHeight() : 10) * this.dpi / 25.4f)); |
|
|
int size = Math.max(1, Math.min(10, Math.round(sizeInDots / 25f))); |
|
|
|
|
|
|
|
|
|
|
|
// 根据数据长度自动调整最小尺寸 |
|
|
|
|
|
if (data.length() > 300) { |
|
|
|
|
|
size = Math.max(size, 8); |
|
|
|
|
|
} else if (data.length() > 200) { |
|
|
|
|
|
size = Math.max(size, 6); |
|
|
|
|
|
} else if (data.length() > 100) { |
|
|
|
|
|
size = Math.max(size, 4); |
|
|
|
|
|
} else { |
|
|
|
|
|
size = Math.max(size, 2); |
|
|
|
|
|
|
|
|
try { |
|
|
|
|
|
return generateZplQRCode(data, sizeInDots, x, y); |
|
|
|
|
|
} catch (Exception e) { |
|
|
|
|
|
throw new RuntimeException(e); |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// 根据数据类型选择模式 |
|
|
|
|
|
if (data.matches("^\\d+$")) { |
|
|
|
|
|
// 纯数字内容,使用数字模式 |
|
|
|
|
|
return String.format("^FO%d,%d^BQ%s,2,%d^FDMN,%s^FS", x, y, orientation, size, data); |
|
|
|
|
|
} else { |
|
|
|
|
|
// 混合内容,使用自动模式 |
|
|
|
|
|
return String.format("^FO%d,%d^BQ%s,2,%d^FDMA,%s^FS", x, y, orientation, size, data); |
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* 生成二维码并转为 ZPL |
|
|
|
|
|
* |
|
|
|
|
|
* @param content 二维码内容(支持中文) |
|
|
|
|
|
* @param size 二维码宽高(像素 == dots) |
|
|
|
|
|
* @param x 打印起点 X 坐标(单位:dots) |
|
|
|
|
|
* @param y 打印起点 Y 坐标(单位:dots) |
|
|
|
|
|
* @return ZPL 字符串 |
|
|
|
|
|
*/ |
|
|
|
|
|
public String generateZplQRCode(String content, int size, int x, int y) throws Exception { |
|
|
|
|
|
byte[] qrBytes = generateQRCode(content, size, size); |
|
|
|
|
|
return convertToZpl(qrBytes, x, y); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 1. 生成二维码(支持中文) |
|
|
|
|
|
private static byte[] generateQRCode(String content, int width, int height) throws Exception { |
|
|
|
|
|
Map<EncodeHintType, Object> hints = new HashMap<>(); |
|
|
|
|
|
hints.put(EncodeHintType.CHARACTER_SET, "UTF-8"); |
|
|
|
|
|
hints.put(EncodeHintType.MARGIN, 1); |
|
|
|
|
|
BitMatrix bitMatrix = new MultiFormatWriter().encode( |
|
|
|
|
|
content, |
|
|
|
|
|
BarcodeFormat.QR_CODE, |
|
|
|
|
|
width, |
|
|
|
|
|
height, |
|
|
|
|
|
hints |
|
|
|
|
|
); |
|
|
|
|
|
BufferedImage image = MatrixToImageWriter.toBufferedImage(bitMatrix); |
|
|
|
|
|
ByteArrayOutputStream baos = new ByteArrayOutputStream(); |
|
|
|
|
|
ImageIO.write(image, "png", baos); |
|
|
|
|
|
return baos.toByteArray(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 2. 转换 PNG 图片为 ZPL ^GF 指令 |
|
|
|
|
|
private static String convertToZpl(byte[] imageBytes, int x, int y) throws Exception { |
|
|
|
|
|
BufferedImage image = ImageIO.read(new ByteArrayInputStream(imageBytes)); |
|
|
|
|
|
int widthBytes = (image.getWidth() + 7) / 8; // 每行字节数 |
|
|
|
|
|
int totalBytes = widthBytes * image.getHeight(); |
|
|
|
|
|
StringBuilder zpl = new StringBuilder(); |
|
|
|
|
|
zpl.append("^FO").append(x).append(",").append(y).append("\n"); |
|
|
|
|
|
zpl.append("^GFA,").append(totalBytes).append(",").append(totalBytes).append(",").append(widthBytes).append(","); |
|
|
|
|
|
StringBuilder imageData = new StringBuilder(); |
|
|
|
|
|
for (int yPos = 0; yPos < image.getHeight(); yPos++) { |
|
|
|
|
|
int bit = 0; |
|
|
|
|
|
int currentByte = 0; |
|
|
|
|
|
for (int xPos = 0; xPos < image.getWidth(); xPos++) { |
|
|
|
|
|
int rgb = image.getRGB(xPos, yPos); |
|
|
|
|
|
int gray = (rgb >> 16 & 0xff) * 299 + (rgb >> 8 & 0xff) * 587 + (rgb & 0xff) * 114; |
|
|
|
|
|
gray = gray / 1000; |
|
|
|
|
|
|
|
|
|
|
|
currentByte <<= 1; |
|
|
|
|
|
if (gray < 128) { // 黑色点 |
|
|
|
|
|
currentByte |= 1; |
|
|
|
|
|
} |
|
|
|
|
|
bit++; |
|
|
|
|
|
if (bit == 8) { |
|
|
|
|
|
imageData.append(String.format("%02X", currentByte)); |
|
|
|
|
|
bit = 0; |
|
|
|
|
|
currentByte = 0; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
if (bit > 0) { |
|
|
|
|
|
currentByte <<= (8 - bit); |
|
|
|
|
|
imageData.append(String.format("%02X", currentByte)); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
zpl.append(imageData); |
|
|
|
|
|
return zpl.toString(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
|