话不多说,直接上效果:
这个是效果图,可以铺下两类文字,每类文字最多两三行,要铺更多的字可以直接调参数
上代码:
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import javax.imageio.ImageIO;
import cn.hutool.core.img.ImgUtil;
import com.google.zxing.*;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import lombok.extern.slf4j.Slf4j;
/**
@date 2024年3月5日17:07:23
@description 二维码打印工具类
*/
@Slf4j
public class QRCodePrinterUtils {
public static void main(String[] args) {
String qrText = "Your QR Code Text";
String text1 = "测试1测试1测试1测试1测试1测试1测试1测试1测试1测试1测试1测试1";
String text2 = "测试2测试2测试2测试2测试2测试2测试2测试2测试2测试2测试2测试2";
try {
BufferedImage extendedImage = realize(qrText, text1, text2);
/* String result = ImgUtil.toBase64DataUri(qrCodeImage, "png");
System.out.println(result);*/
// Save QR code with text
File outputFile = new File("output.png");
ImageIO.write(extendedImage, "png", outputFile);
// Open the saved file
Desktop.getDesktop().open(outputFile);
} catch (Exception e) {
e.printStackTrace();
}
}
public static BufferedImage realize(String qrText,String text1, String text2) throws WriterException {
BufferedImage qrCodeImage = generateQRCodeImage(qrText, 400, 400);
BufferedImage extendedImage = new BufferedImage(qrCodeImage.getWidth(), 500, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = extendedImage.createGraphics();
// Fill the background with white color
g2d.setColor(Color.WHITE);
g2d.fillRect(0, 0, extendedImage.getWidth(), extendedImage.getHeight());
// Draw the QR code image onto the extended image
g2d.drawImage(qrCodeImage, 0, 0, null);
addTextBelowQRCode(extendedImage, text1, text2);
return extendedImage;
}
public static String realizeToBase64(String qrText,String text1, String text2) throws WriterException {
BufferedImage extendedImage = realize(qrText, text1, text2);
String result = ImgUtil.toBase64DataUri(extendedImage, "png");
return result;
}
private static BufferedImage generateQRCodeImage(String qrCodeText, int width, int height) throws WriterException {
Hashtable<EncodeHintType, String> hints = new Hashtable<>();
hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
BitMatrix bitMatrix = new MultiFormatWriter().encode(qrCodeText, BarcodeFormat.QR_CODE, width, height, hints);
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
image.setRGB(x, y, bitMatrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF);
}
}
return image;
}
private static void addTextBelowQRCode(BufferedImage image, String text1, String text2) {
Graphics2D g2d = image.createGraphics();
g2d.setColor(Color.BLACK);
// Load a TrueType font that supports Chinese characters
// 加载支持中文字符的 TrueType 字体,并加粗
Font font1 = new Font("宋体", Font.BOLD, 24); // text1字体加粗且比text2大
Font font2 = new Font("宋体", Font.PLAIN, 20); // text2字体
g2d.setFont(font1);
// Calculate text1 position and handle text wrapping
FontMetrics fm1 = g2d.getFontMetrics();
int maxWidth = 400; // Image width
List<String> linesText1 = wrapText(text1, fm1, maxWidth);
int text1Y = image.getHeight() - 95; // Initial position below QR code
int lineHeight = fm1.getHeight();
// Draw text1
for (String line : linesText1) {
int text1Width = fm1.stringWidth(line);
int text1X = (image.getWidth() - text1Width) / 2;
g2d.drawString(line, text1X, text1Y);
text1Y += lineHeight; // Move to next line (downwards)
}
g2d.setFont(font2);
FontMetrics fm2 = g2d.getFontMetrics();
// Calculate text2 position and handle text wrapping
int text2X = (image.getWidth() - fm2.stringWidth(text2)) / 2;
int text2Y = text1Y + 5; // Place text2 below text1 with a small gap
List<String> linesText2 = wrapText(text2, fm2, maxWidth);
// Draw text2
for (String line : linesText2) {
int text2Width = fm2.stringWidth(line);
g2d.drawString(line, (image.getWidth() - text2Width) / 2, text2Y);
text2Y += lineHeight; // Move to next line (downwards)
}
g2d.dispose();
}
private static List<String> wrapText(String text, FontMetrics fm, int maxWidth) {
List<String> lines = new ArrayList<>();
int textWidth = fm.stringWidth(text);
if (textWidth <= maxWidth) {
lines.add(text);
return lines;
}
StringBuilder currentLine = new StringBuilder();
int length = text.length();
int start = 0;
int end = 0;
while (start < length) {
while (end < length && fm.stringWidth(text.substring(start, end + 1)) <= maxWidth) {
end++;
}
if (end == length) {
lines.add(text.substring(start));
break;
} else {
int lastSpace = text.substring(start, end).lastIndexOf(" ");
if (lastSpace != -1 && start + lastSpace < end) {
lines.add(text.substring(start, start + lastSpace));
start += lastSpace + 1;
} else {
lines.add(text.substring(start, end));
start = end;
}
}
}
return lines;
}
}
这个是实现方法啦,里面也有主函数可以直接测试效果,并且这个兼容了中文。
这里说下参数,要调整两行文字的Y坐标
int text1Y = image.getHeight() - 95;
直接对这行代码修改就好了,因为第二行是根据第一行变的,当你减的数字越大就会越靠上,可以自己调整
另外
BufferedImage(qrCodeImage.getWidth(), 500, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = extendedImage.createGraphics();
这行代码可以调整二维码图片的长度,数字越大图片就会越长。
OK,结束啦