一:先画出要打印的小票
这里算出整个画图的内容高度,方便调打印机
private int drawByGraphics(PrintSmallTicketTemplateConfig req, Graphics2D g){
try {
Map<String, Object> map = req.getMapList();
List<PrintSmallTicketTemplateConfig.Draw> draws = req.getPrintConfig();
int width = Integer.parseInt(draws.get(0).getForm().getWidth());
draws = draws.stream().sorted(Comparator.comparing(i -> Integer.parseInt(i.getForm().getPositionTop()))).collect(Collectors.toList());
g.setBackground(Color.white);
int allHeight = 0;
for (PrintSmallTicketTemplateConfig.Draw draw : draws) {
//总高度
if (draw.getType().equals("taodi")) {
// Color color = new Color(Integer.parseInt(draw.getFont().getColor().replaceAll("#", ""), 16));
// g.setColor(color);
// Font font = new Font("Microsoft YaHei", Font.PLAIN, draw.getFont().getSize());
// g.setFont(font);
// String value;
// g.setStroke(new BasicStroke(1.5f));
// g.setColor(Color.black);
// g.drawLine(0, 0, Integer.parseInt(draw.getForm().getWidth()), 0);
// g.drawLine(0, 0, 0, Integer.parseInt(draw.getForm().getHeight()));
// g.drawLine(0, Integer.parseInt(draw.getForm().getHeight()), Integer.parseInt(draw.getForm().getWidth()), Integer.parseInt(draw.getForm().getHeight()));
// g.drawLine(Integer.parseInt(draw.getForm().getWidth()), 0, Integer.parseInt(draw.getForm().getWidth()), Integer.parseInt(draw.getForm().getHeight()));
} else if (draw.getType().equals("line")) {
int currentY = Integer.parseInt(draw.getForm().getPositionTop());
if (allHeight != 0) {
currentY += allHeight;
}
int currentX = Integer.parseInt(draw.getForm().getPositionLeft());
float[] dash1 = {2f, 0f, 2f};
if ("solid".equals(draw.getForm().getBorStyle())) {
g.setStroke(new BasicStroke(1.5f));
} else {
g.setStroke(new BasicStroke(2f, BasicStroke.CAP_BUTT,
BasicStroke.JOIN_ROUND,
1.0f,
dash1,
2f));
}
g.setColor(new Color(Integer.parseInt(draw.getForm().getBorColor().replaceAll("#", ""), 16)));
g.drawLine(Integer.parseInt(draw.getForm().getPositionLeft()), currentY, Integer.parseInt(draw.getForm().getPositionLeft()) + Integer.parseInt(draw.getForm().getWidth()), currentY);
}else if (draw.getType().equals("text")) {
Color color = new Color(Integer.parseInt(draw.getForm().getTextColor().replaceAll("#", ""), 16));
g.setColor(color);
Font font = new Font("Microsoft YaHei", Font.PLAIN, Integer.parseInt(draw.getForm().getSize()));
FontDesignMetrics metrics = FontDesignMetrics.getMetrics(font);
g.setFont(font);
String value;
String content="";
int staticStrWidth = 0;
int strWidth =0;
if ("static".equals(draw.getForm().getState())) {
value = draw.getForm().getContent();
if(!StringUtils.isEmpty(value)) {
strWidth = getWordWidth(font, value);
}
} else if ("onlyDynamic".equals(draw.getForm().getState())) {
value = (String) map.get(draw.getForm().getDynamicKey());
if(!StringUtils.isEmpty(value)) {
strWidth = getWordWidth(font, value);
}
} else {
value = draw.getForm().getContent() + (String) map.get(draw.getForm().getDynamicKey());
content=(String) map.get(draw.getForm().getDynamicKey());
if(!StringUtils.isEmpty(value)) {
staticStrWidth = getWordWidth(font, draw.getForm().getContent());
}if(!StringUtils.isEmpty(content)) {
strWidth = getWordWidth(font, content);
}
}
if (!StringUtils.isEmpty(value)) {
//静态内容宽度
System.out.println("字符总宽度:" + strWidth);
//第一行字符宽度
int ww = width - Integer.parseInt(draw.getForm().getPositionLeft())-staticStrWidth;
int rowstrnum = 0;
rowstrnum = (ww * value.length()) / strWidth;
System.out.println("每行的字符数:" + rowstrnum);
int rows = 0;
if (strWidth % ww > 0) {
rows = strWidth / ww + 1;
} else {
rows = strWidth / ww;
}
System.out.println("行数:" + rows);
int height1 = g.getFontMetrics().getHeight();
System.out.println("字符高度:" + height1);
g.setFont(font);
//当前y坐标
int currentY = Integer.parseInt(draw.getForm().getPositionTop());
if (allHeight != 0) {
currentY += allHeight;
}
if (strWidth > ww) {
String temp = "";
for (int i = 0; i < rows; i++) {
//获取各行的String
if (i == rows - 1) {
//最后一行
temp = value.substring(i * rowstrnum);
} else {
temp = value.substring(i * rowstrnum, i * rowstrnum + rowstrnum);
}
if (i > 0) {
//第一行不需要增加字符高度,以后的每一行在换行的时候都需要增加字符高度
currentY = currentY + height1;
}if(i==0) {
g.drawString(temp, Integer.parseInt(draw.getForm().getPositionLeft()) , currentY + metrics.getAscent());
}else{
g.drawString(temp, Integer.parseInt(draw.getForm().getPositionLeft())+ staticStrWidth, currentY + metrics.getAscent());
}
}
} else {
//
g.setFont(font);
g.drawString(value, Integer.parseInt(draw.getForm().getPositionLeft()), currentY + metrics.getAscent());
}
if (rows > 1) {
allHeight += height1 * (rows-1);
}
}
} else if (draw.getType().equals("table")) {
int x = Integer.parseInt(draw.getForm().getPositionLeft());
int currentY = Integer.parseInt(draw.getForm().getPositionTop());
if (allHeight != 0) {
currentY += allHeight;
}
g.setColor(Color.black);
Font font = new Font("Microsoft YaHei", Font.BOLD, Integer.parseInt(draw.getForm().getHeaderFsize()));
FontDesignMetrics metrics = FontDesignMetrics.getMetrics(font);
int tableWidth = Integer.parseInt(draw.getForm().getPositionLeft());
for (int i = 0; i < draw.getForm().getTableColumn().size(); i++) {
if (i != 0) {
x += Integer.parseInt(draw.getForm().getTableColumn().get(i - 1).getWidth());
}
tableWidth += Integer.parseInt(draw.getForm().getTableColumn().get(i).getWidth());
String tableLabel = draw.getForm().getTableColumn().get(i).getLabel();
int wordWidth = getWordWidth(font, tableLabel);
// 添加字体的属性设置
g.setFont(font);
g.drawString(draw.getForm().getTableColumn().get(i).getLabel(), x + (Integer.parseInt(draw.getForm().getTableColumn().get(i).getWidth()) - wordWidth) / 2, currentY + metrics.getAscent());
}
if ("true".equals(draw.getForm().getIsBorder())) {
g.setStroke(new BasicStroke(1.5f));
g.drawLine(Integer.parseInt(draw.getForm().getPositionLeft()), currentY + metrics.getAscent() + metrics.getDescent(), tableWidth, currentY + metrics.getAscent() + metrics.getDescent());
}
currentY += 2 * metrics.getAscent() + metrics.getDescent();
int tableY = currentY;
g.setFont(new Font("Microsoft YaHei", Font.PLAIN, 15));
java.util.List<Object> table = (List<Object>) map.get(draw.getForm().getTableName());
if (!CollectionUtils.isEmpty(table)) {
// 循环表格内容
for (Object o : table) {
font = new Font("Microsoft YaHei", Font.PLAIN, Integer.parseInt(draw.getForm().getCellFsize()));
g.setFont(font);
x = Integer.parseInt(draw.getForm().getPositionLeft());
Map<String, String> objectMap = (Map<String, String>) o;
int maxHeight = 0;
//循环表格每一行的数据
for (PrintSmallTicketTemplateConfig.Draw.Column s : draw.getForm().getTableColumn()) {
String value = objectMap.get(s.getProp());
char[] strcha = value.toCharArray();
int strWidth = g.getFontMetrics().charsWidth(strcha, 0, value.length());
int ww = Integer.parseInt(s.getWidth());
int rowstrnum = 0;
rowstrnum = (ww * value.length()) / strWidth;
System.out.println("每行的字符数:" + rowstrnum);
int hang = 0;
int rows = 0;
if (strWidth % ww > 0) {
rows = strWidth / ww + 1;
} else {
rows = strWidth / ww;
}
System.out.println("行数:" + rows);
int height1 = g.getFontMetrics().getHeight();
//一行高度
hang = height1 * (rows);
if (maxHeight < hang) {
maxHeight = hang;
}
System.out.println("行数:" + rows);
int hei = g.getFontMetrics().getHeight();
System.out.println("字符高度:" + height1);
if (strWidth > ww) {
String temp = "";
for (int j = 0; j < rows; j++) {
//获取各行的String
if (j == rows - 1) {
//最后一行
temp = value.substring(j * rowstrnum);
} else {
temp = value.substring(j * rowstrnum, j * rowstrnum + rowstrnum);
}
if (j > 0) {
//第一行不需要增加字符高度,以后的每一行在换行的时候都需要增加字符高度
currentY = currentY + hei;
}
g.drawString(temp, x, currentY);
}
currentY = tableY;
x += Integer.parseInt(s.getWidth());
} else {
int wordWidth = getWordWidth(font, value);
g.drawString(value, x + (Integer.parseInt(s.getWidth()) - wordWidth) / 2, currentY);
// g.drawString(value, x, currentY);
x += Integer.parseInt(s.getWidth());
}
}
currentY += maxHeight;
allHeight += maxHeight;
tableY += maxHeight;
}
}
if ("true".equals(draw.getForm().getIsBorder())) {
g.setStroke(new BasicStroke(1f));
g.drawLine(Integer.parseInt(draw.getForm().getPositionLeft()), currentY, tableWidth, currentY);
}
} else if (draw.getType().equals("images")) {
int currentY = Integer.parseInt(draw.getForm().getPositionTop());
if (allHeight != 0) {
currentY += allHeight;
}
//定义一个URL对象,就是你想下载的图片的URL地址
URL url = new URL(draw.getForm().getSrc());
//打开连接
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
//设置请求方式为"GET"
conn.setRequestMethod("GET");
//超时响应时间为10秒
conn.setConnectTimeout(10 * 1000);
//通过输入流获取图片数据
InputStream is = conn.getInputStream();
Image chop = ImageIO.read(is);
log.info("画一次图片...");
g.drawImage(chop, Integer.parseInt(draw.getForm().getPositionLeft()), currentY, Integer.parseInt(draw.getForm().getWidth()), Integer.parseInt(draw.getForm().getHeight()), null);
} else if (draw.getType().equals("qrcode")) {
String drawImg = QRCodeTool.createQRCodeToBase64(draw.getForm().getText(), 300, ErrorCorrectionLevel.L);
Image chop;
if (drawImg.contains("base64,")) {
String base64 = drawImg.replaceAll("data:image/jpeg;base64,", "");
base64 = base64.replaceAll("data:image/jpg;base64,", "");
String tmp = "E:\\xx.png";
Files.write(Paths.get(tmp), Base64.getDecoder().decode(base64), StandardOpenOption.CREATE);
ImageIcon imgIcon = new ImageIcon(tmp);
chop = imgIcon.getImage();
File tmpFile = new File(tmp);
tmpFile.delete();
log.info("画一次图片...");
int y = Integer.parseInt(draw.getForm().getPositionTop());
if (allHeight != 0) {
y = y + allHeight;
}
g.drawImage(chop, Integer.parseInt(draw.getForm().getPositionLeft()), y, Integer.parseInt(draw.getForm().getWidth()), Integer.parseInt(draw.getForm().getHeight()), null);
}
} else if (draw.getType().equals("barcode")) {
int currentY = Integer.parseInt(draw.getForm().getPositionTop());
if (allHeight != 0) {
currentY += allHeight;
}
Pattern pattern = Pattern.compile("[\u4e00-\u9fa5]");
String s = draw.getForm().getText();
Matcher m = pattern.matcher(s);
if (!m.find()) {
// 如果字符串中含有中文,m.find()判断为true
/* 转换开始 */
byte[] bytes = BarCodeUtils.generateBarCode128(
draw.getForm().getText(), 10.00, 0.3, true, false);
if (!org.springframework.util.StringUtils.isEmpty(bytes)) {
ImageIcon imgIcon = new ImageIcon(bytes, "Miho");
Image chop = imgIcon.getImage();
log.info("画条形码...");
g.drawImage(chop, Integer.parseInt(draw.getForm().getPositionLeft()), currentY, 100, 50, null);
}
}
}
}
g.dispose();
int w = Integer.parseInt(draws.get(draws.size() - 1).getForm().getPositionTop()) + allHeight+20;
if(draws.get(draws.size() - 1).getType().equals("qrcode")||draws.get(draws.size() - 1).getType().equals("barcode")){
w+=Integer.parseInt(draws.get(draws.size() - 1).getForm().getHeight());
}
return w;
} catch (IOException e) {
e.printStackTrace();
}
return 0;
}
二,调用打印机打印图片
@Override
public void sync(PrintSmallTicketTemplateConfig req, CompletableFuture<ApiResp> future) {
if(LocalPluginApplication.ifPrinting) {
System.out.println("1111111");
future.completeExceptionally(new RuntimeException(String.valueOf(RespEnum.PRINTER_PING_BUSY)));
return;
}
//获取本地主机
try{
InetAddress net=InetAddress.getLocalHost();
//输出
System.out.println(net);
log.info("局域网地址ip--------------------------------------{}",net);
}catch(UnknownHostException e){
e.printStackTrace();
}
LocalPluginApplication.ifPrinting = true;
// BufferedImage bimage = new BufferedImage(200, 550, BufferedImage.TYPE_INT_RGB);
// Graphics2D g2d = bimage.createGraphics();
// g2d.setPaint(Color.white);
// g2d.fillRect(0,0,200,550);
// g2d.setColor(Color.BLACK);
// g2d.setFont(new Font("Serif", Font.PLAIN, 20));
// g2d.drawString("测试测试1212", 10,30);
// g2d.drawString("测试测试3331", 10,120);
// g2d.drawString("测试测试6611", 10,120);
// g2d.dispose();
// future.complete(bimage);
//
// log.info(">>> 1111111111111111111111111111111");
Book book = new Book();
// 打印格式
PageFormat pf = new PageFormat();
// 原点在纸张的左上方,x 指向右方,y 指向下方。
pf.setOrientation(PageFormat.PORTRAIT);
// 通过Paper设置页面的空白边距和可打印区域。必须与实际打印纸张大小相符。
Paper p = new Paper();
int width = Integer.parseInt(req.getPrintConfig().get(0).getForm().getWidth());
// 页面宽度 页面高度
p.setSize(width, 100000);
// x轴 y轴 宽度 高度
p.setImageableArea(0, 0, width, 100000);
pf.setPaper(p);
book.append((graphics, pageFormat, pageIndex) -> {
int height = drawByGraphics(req, (Graphics2D) graphics);
if(height > 0) {
BufferedImage bimage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics2D gimg = bimage.createGraphics();
gimg.fillRect(0,0,width, height);
drawByGraphics(req, gimg);
gimg.dispose();
ByteArrayOutputStream baos = new ByteArrayOutputStream();//io流
try {
ImageIO.write(bimage, "png", baos);//写入流中
} catch (IOException e) {
e.printStackTrace();
}
byte[] bytes = baos.toByteArray();//转换成字节
BASE64Encoder encoder = new BASE64Encoder();
String png_base64 = encoder.encodeBuffer(bytes).trim();//转换成base64串
png_base64 = png_base64.replaceAll("\n", "").replaceAll("\r", "");//删除 \r\n
Map<String,String> resultMap = new HashMap<>();
resultMap.put("image", "data:image/png;base64," + png_base64);
future.complete(ApiResp.buildSuccess(null, null, resultMap));
}
return Printable.PAGE_EXISTS;
}, pf);
// 指定打印机打印(printerName打印机名称)
HashAttributeSet hs = new HashAttributeSet();
String printerName = "XP-80C";
hs.add(new PrinterName(printerName, null));
javax.print.PrintService[] pss = PrintServiceLookup.lookupPrintServices(null, hs);
if (pss.length == 0) {
System.out.println("无法找到打印机:" + printerName);
try {
throw new PrinterException(String.valueOf(RespEnum.PRINT_EXCEPTION));
} catch (PrinterException e) {
e.printStackTrace();
}
return;
}
// 获取打印服务对象
PrinterJob job = PrinterJob.getPrinterJob();
job.setJobName("测试打印明");
// 写入书
job.setPageable(book);
try {
// 添加指定的打印机
job.setPrintService(pss[0]);
// 打印执行
job.print();
//
} catch (PrinterException e) {
try {
throw new PrinterException(String.valueOf(RespEnum.PRINT_EXCEPTION));
} catch (PrinterException printerException) {
printerException.printStackTrace();
}
}
LocalPluginApplication.ifPrinting = false;
}
算出内容的宽度
public static int getWordWidth(Font font, String content) {
FontDesignMetrics metrics = FontDesignMetrics.getMetrics(font);
int width = 0;
for (int i = 0; i < content.length(); i++) {
width += metrics.charWidth(content.charAt(i));
}
return width;
}
三.异步返回图片和打印小票
@PostMapping(value = "/image")
public DeferredResult<ApiResp> sync(@RequestBody PrintSmallTicketTemplateConfig req){
DeferredResult<ApiResp> deferredResult = new DeferredResult<>(30000l);
CompletableFuture<ApiResp> future = new CompletableFuture<>();
printService.sync(req, future);
future.whenComplete((result, error) -> {
if(error == null) {
deferredResult.setResult(result);
}else {
deferredResult.setErrorResult(null);
}
});
return deferredResult;
}