Java ZXing合成带文字的复杂二维码图片实现详解
通过 Java ZXing 生成标准二维码后,利用 Graphics2D API 可轻松实现图文与背景的复杂合成。本文总结从生成位图到最终输出高清图片的完整流程,重点解析动态字体适配算法,并修复服务器部署环境下因缺少物理字体和包内资源加载方式不当导致的乱码及找图失败问题。
整体实现思路
合成带描述信息的复杂二维码主要包含两个阶段:首先利用成熟的 ZXing 库生成标准化的二维码位图;随后使用 Java 原生图像处理能力(BufferedImage 和 Graphics2D)进行排版与合成。根据设计需求,可以选择在二维码上下方添加说明文字,或在左侧添加标题右侧放置二维码。整个流程遵循“准备画布 → 绘制元素 → 导出文件”的操作顺序。
第一步:生成基础二维码图片
使用 MultiFormatWriter 编码内容生成 BitMatrix,并转换为图片路径或流。此步骤需重点关注字符编码与纠错等级,确保后续识别率。
HashMap<EncodeHintType, Object> hints = new HashMap();
//指定字符编码为utf-8
hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
//指定二维码的纠错等级为中级(H)
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
//设置图片的边距
hints.put(EncodeHintType.MARGIN, 1);
try {
BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, QRCODE_WIDTH, QRCODE_HEIGHT, hints);
Path file = new File(filePath).toPath();
MatrixToImageWriter.writeToPath(bitMatrix, format, file);
} catch (Exception e) {
log.error("二维码生成出错:/permitDownload: error", e);
}
第二步:为二维码添加动态适配的文字
为了保证合成的图片在不同分辨率下依然清晰且布局合理,需要根据文字长度动态调整字体大小,避免文字溢出或被挤压。此操作涉及创建新的画布、计算居中坐标以及处理字体度量。
2.1 核心绘制逻辑
在代码中定义一个方法,接受原始二维码图片和待添加的上/下文内容。通过计算文字像素宽度来动态确定字号,并在预留空间内进行居中绘制。
private static BufferedImage addNote(BufferedImage image, String topText, String downText) {
Image src = image.getScaledInstance(QRCODE_WIDTH, QRCODE_HEIGHT, Image.SCALE_DEFAULT);
// 创建足够高度的画布容纳文字与二维码
BufferedImage tag = new BufferedImage(QRCODE_WIDTH, IMAGE_HEIGHT, BufferedImage.TYPE_INT_RGB);
Graphics2D g2 = tag.createGraphics();
g2.setColor(Color.BLACK);
g2.setBackground(Color.WHITE);
g2.clearRect(0, 0, QRCODE_WIDTH, IMAGE_HEIGHT);
// --- 处理顶部文字 ---
FontMetrics fm = getFontByWidth(new Font("宋体", Font.PLAIN, DEFAULT_FONT_SIZE), topText, g2);
int fontWidth = fm.stringWidth(topText);
int fontHeight = fm.getHeight();
// 水平居中绘制
g2.drawString(topText, (QRCODE_WIDTH - fontWidth) / 2, (TEXT_DEFAULT_HEIGHT - fontHeight) / 2 + fm.getFont().getSize());
// --- 绘制中间二维码 ---
g2.drawImage(src, 0, TEXT_DEFAULT_HEIGHT, null);
// --- 处理底部文字 ---
fm = getFontByWidth(new Font("宋体", Font.PLAIN, DEFAULT_FONT_SIZE), downText, g2);
fontWidth = fm.stringWidth(downText);
fontHeight = fm.getHeight();
// 计算底部文字垂直位置,确保位于二维码下方
int bottomY = QRCODE_HEIGHT + TEXT_DEFAULT_HEIGHT + (TEXT_DEFAULT_HEIGHT - fontHeight) / 2 + fm.getFont().getSize();
g2.drawString(downText, (QRCODE_WIDTH - fontWidth) / 2, bottomY);
g2.dispose();
return tag;
}
2.2 动态修改字体大小
关键类 FontMetrics 用于获取字体实际占用的像素宽度。当文字长度超过画布宽度时,按比例缩小字号直到 fit。
private static FontMetrics getFontByWidth(Font font, String note, Graphics2D g2) {
FontMetrics fm = g2.getFontMetrics(font);
int textWidth = fm.stringWidth(note);
if (textWidth > QRCODE_WIDTH) {
// 动态缩减字号,TEMP_PARAM 为经验阈值参数
int fontSize = (int) ((TEMP_PARAM / textWidth) * font.getSize());
font = new Font(font.getName(), font.getStyle(), fontSize);
}
g2.setFont(font);
return g2.getFontMetrics(font);
}
第三步:合成背景图片(可选)
若需将带文字的二维码叠加至特定设计的背景图上,需引入背景素材。这里以将二维码插入固定模板为例,说明如何调整坐标以匹配设计要求。
private static void createNewPng(File qrPic, BufferedImage backImage) {
try {
if (!qrPic.isFile()) {
log.error("二维码临时路径不存在!");
}
// 获取绘图对象
Graphics2D g = backImage.createGraphics();
// 读取带文字的二维码
BufferedImage qrcodeImage = ImageIO.read(qrPic);
// 将二维码绘制到背景图的指定坐标(48, 120)
g.drawImage(qrcodeImage, 48, 120, qrcodeImage.getWidth(), qrcodeImage.getHeight(), null);
g.dispose();
// 保存最终结果
ImageIO.write(backImage, "png", qrPic);
} catch (Exception e) {
log.error("绘制二维码出错!");
}
}
常见问题排查:踩过的坑
1. Linux 服务器部署后中文乱码
在 Windows 本地开发时系统自带中文字体(如宋体),但 CentOS 等 Linux 服务器上通常不包含。直接部署会导致中文字符渲染为空框或乱码。
- 现象: 生成的图片中所有中文不可见或非预期符号。
- 原因: JVM 无法找到指定的物理字体文件。
- 解决: 从 Windows 系统的
C:\Windows\Fonts\simsun.ttc拷贝字体文件至服务器的JAVA_HOME/jre/lib/fonts目录下,然后重启应用即可。
2. Spring Boot 打包后找不到背景图片
本地开发时,通过 ClassPathResource.getFile()resources/template/down.png 路径,但在打成的 Jar 包中运行时,该接口可能返回临时文件或失效路径。
- 错误写法:
File file = new ClassPathResource("template/down.png").getFile(); - 正确写法: 始终使用 InputStream 读取资源流:
BufferedImage bi = ImageIO.read(new ClassPathResource("template/down.png").getInputStream());
简要总结
利用 Java 合成定制化二维码不仅限于简单的图像拼接,更涉及对字体度量、画布坐标以及部署环境差异的综合处理。采用 ZXing 结合 BufferedImage 能够灵活应对多种业务场景,只需确保字体文件的跨平台一致性与资源加载的正确性,即可稳定输出高质量成品。
以上就是java zxing合成复杂二维码图片示例详解的详细内容,更多关于java zxing合成复杂二维码的资料请关注本站其它相关文章!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













