基于 Java 编程生成二维码图片
0x01 准备
(1)软件版本
- IntelliJ IDEA 2023.1.3
- JDK 18
- Tomcat 10.1.11
- Maven 3.8.6
(2)技术栈
- servlet
- zxing
- 谷歌项目
- 生成黑白二维码并可以附上 logo
- qrcode
- github 开源项目
- 基于并拓展 zxing
(3)创建项目
-
创建空项目
-
在 菜单栏-文件-项目结构 中设置 JDK 及语言级别
-
在 菜单栏-文件-设置-构建-构建工具-Maven 中配置 Maven 路径与用户设置文件 \apache-maven-3.8.6\conf\settings.xml
-
在项目中创建新模块
-
在新模块中通过“添加框架支持”添加 Web Application 4.0
- 取消“创建 web.xml ”的选中
- 在项目结构中选择 模块-[模块名称]-Web-Web 资源目录,修改资源目录为项目中 web 的路径,如 [project_name]\[module_name]\web
-
修改 pom.xml
<!-- 打包方式 --> <packaging>war</packaging> <!-- 添加依赖 --> <dependencies> <!-- https://mvnrepository.com/artifact/jakarta.servlet/jakarta.servlet-api --> <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> <version>6.0.0</version> <scope>provided</scope> </dependency> <!-- zxing 依赖 --> <dependency> <groupId>com.google.zxing</groupId> <artifactId>javase</artifactId> <version>3.1.0</version> </dependency> <!-- zxing 需要 commons-lang 依赖 --> <dependency> <groupId>commons-lang</groupId> <artifactId>commons-lang</artifactId> <version>2.6</version> </dependency> </dependencies> -
在 菜单栏-运行-编辑配置 中配置 Tomcat 服务器
-
添加新配置,选择 Tomcat 本地服务器
-
在 部署栏 中选择添加工件,选择 [module_name]:war exploded
-
修改 应用上下文 为 /[module_name]
-
修改 Tomcat 目录下 /conf/logging.properties 文件的内容以避免调试日志乱码
java.util.logging.ConsoleHandler.encoding = GBK
-
0x02 zxing
(1)创建基础二维码图片
-
在 web/index.jsp 中编辑前端页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>QRCode</title> </head> <body> <p>输入文本:<input type="text" id="url" /><button onclick="generateQRCode()">生成二维码</button></p> <img id="qrcodeImg" /> <script type="text/javascript"> function generateQRCode() { document.getElementById("qrcodeImg").src = "/myqrcode/generate?url=" + document.getElementById("url").value } </script> </body> </html> -
新建 src/main/java/com.qrcode.servlets 包并新建 GenerateQRCode.java
package com.qrcode.servlets; public class GenerateQRCode extends HttpServlet { } -
在类中继承 HttpServlet 类并重写
doGet()
方法@WebServlet("/generate") public class GenerateQRCode extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // super.doGet(req, resp); } } -
在方法中创建 Map 集合来储存二维码相关属性
Map map = new HashMap(); // 设置二维码的误差校正级别 map.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); // 设置二维码的字符集 map.put(EncodeHintType.CHARACTER_SET, "utf-8"); // 设置二维码四周的留白 map.put(EncodeHintType.MARGIN, 1); -
校正级别(二维码中最大坏像素点占比):
L - 7% M - 15% Q - 25% H - 30%
-
-
获取文本对象
String url = req.getParameter("url"); -
创建 zxing 的核心对象
MultiFormatWriter writer = new MultiFormatWriter(); - MultiFormatWriter(多格式写入器)是一个便捷的二维码生成类,可以根据传入的 BarcodeFormat 参数,生成对应的二维码
-
传入二维码参数并获取宽高
BitMatrix bitMatrix = writer.encode(url, BarcodeFormat.QR_CODE, 300, 300, map); int height = bitMatrix.getHeight(); int width = bitMatrix.getWidth(); - BarcodeFormat(码格式)是枚举类,用来指定二维码格式
- QR_CODE:最常见二维码格式之一
- AZTEC:高密度高可靠二维码格式
- PDF_417:储存大量信息的二维码格式
- DATA_MATRIX:一种小巧的二维码格/式
- BitMatrix(位矩阵对象)是表示二维码矩阵的数据结构,实际上是一个紧凑型的布尔型二维数组,常用于将编码后的信息转化为矩阵类型,具有以下方法
getHeight()
:获取矩阵高度getWidth()
:获取矩阵宽度get(x, y)
:获取指定位置的坐标值,值为true
(黑色块)或false
(白色块)
- BarcodeFormat(码格式)是枚举类,用来指定二维码格式
-
生成二维码
// 创建图片对象 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); } } -
将图片返回到浏览器
ServletOutputStream servletOutputStream = resp.getOutputStream(); ImageIO.write(image, "png", servletOutputStream); servletOutputStream.flush(); servletOutputStream.close();
完整代码:
package com.qrcode.servlets; import com.google.zxing.BarcodeFormat; import com.google.zxing.EncodeHintType; import com.google.zxing.MultiFormatWriter; import com.google.zxing.common.BitMatrix; import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; import jakarta.servlet.ServletException; import jakarta.servlet.ServletOutputStream; import jakarta.servlet.annotation.WebServlet; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.IOException; import java.util.HashMap; import java.util.Map; @WebServlet("/generate") public class GenerateQRCode extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { try { String url = req.getParameter("url"); Map map = new HashMap(); map.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); map.put(EncodeHintType.CHARACTER_SET, "utf-8"); map.put(EncodeHintType.MARGIN, 1); MultiFormatWriter writer = new MultiFormatWriter(); BitMatrix bitMatrix = writer.encode(url, BarcodeFormat.QR_CODE, 300, 300, map); int height = bitMatrix.getHeight(); int width = bitMatrix.getWidth(); 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); } } ServletOutputStream servletOutputStream = resp.getOutputStream(); ImageIO.write(image, "png", servletOutputStream); servletOutputStream.flush(); servletOutputStream.close(); } catch (Exception e) { e.printStackTrace(); } } }
(2)带 logo 的二维码生成
-
修改前端页面 index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>QRCode</title> </head> <body> <form action="/myqrcode/generate" method="post" enctype="multipart/form-data"> 输入文本:<input type="text" name="url" /><br /> logo:<input type="file" name="logo" /><br /> <input type="submit" value="生成二维码"> </form> </body> </html> -
添加文件上传注释
@MultipartConfig(fileSizeThreshold = 1024 * 1024 * 2, maxFileSize = 1024 * 1024 * 10, maxRequestSize = 1024 * 1024 * 100) -
在 GenerateQRCode.java 中获取上传的 Logo
Part logoPart = req.getPart("logo"); InputStream inputStream = logoPart.getInputStream(); Image logoImage = ImageIO.read(inputStream); -
使用平滑缩放算法进行缩放
int logoWidth = logoImage.getWidth(null); int logoHeight = logoImage.getHeight(null); logoWidth = logoWidth > 60 ? 60 : logoWidth; logoHeight = logoHeight > 60 ? 60 : logoHeight; Image logoImageScaledInstance = logoImage.getScaledInstance(logoWidth, logoHeight, Image.SCALE_SMOOTH); -
获取 2D 画笔
Graphics2D graphics2D = image.createGraphics(); -
指定开始作画的坐标
int x = (300 - logoWidth) / 2; int y = (300 - logoHeight) / 2; -
绘制 Logo
graphics2D.drawImage(logoImageScaledInstance, x, y, null); -
绘制圆角矩形
Shape shape = new RoundRectangle2D.Float(x, y, logoWidth, logoHeight, 10, 10); graphics2D.setStroke(new BasicStroke(4f)); graphics2D.draw(shape);
-
-
释放画笔
graphics2D.dispose();
完整代码:
package com.qrcode.servlets; import com.google.zxing.BarcodeFormat; import com.google.zxing.EncodeHintType; import com.google.zxing.MultiFormatWriter; import com.google.zxing.common.BitMatrix; import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; import jakarta.servlet.ServletException; import jakarta.servlet.annotation.MultipartConfig; import jakarta.servlet.annotation.WebServlet; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.Part; import javax.imageio.ImageIO; import java.awt.*; import java.awt.geom.RoundRectangle2D; import java.awt.image.BufferedImage; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; import java.util.Map; @WebServlet("/generate") @MultipartConfig(fileSizeThreshold = 1024 * 1024 * 2, maxFileSize = 1024 * 1024 * 10, maxRequestSize = 1024 * 1024 * 100) public class GenerateQRCode extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { try { String url = req.getParameter("url"); Map map = new HashMap(); map.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); map.put(EncodeHintType.CHARACTER_SET, "utf-8"); map.put(EncodeHintType.MARGIN, 1); MultiFormatWriter writer = new MultiFormatWriter(); BitMatrix bitMatrix = writer.encode(url, BarcodeFormat.QR_CODE, 300, 300, map); int height = bitMatrix.getHeight(); int width = bitMatrix.getWidth(); 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); } } Part logoPart = req.getPart("logo"); InputStream inputStream = logoPart.getInputStream(); Image logoImage = ImageIO.read(inputStream); int logoWidth = logoImage.getWidth(null); int logoHeight = logoImage.getHeight(null); logoWidth = Math.min(logoWidth, 60); logoHeight = Math.min(logoHeight, 60); Image logoImageScaledInstance = logoImage.getScaledInstance(logoWidth, logoHeight, Image.SCALE_SMOOTH); Graphics2D graphics2D = image.createGraphics(); int x = (300 - logoWidth) / 2; int y = (300 - logoHeight) / 2; graphics2D.drawImage(logoImageScaledInstance, x, y, null); Shape shape = new RoundRectangle2D.Float(x, y, logoWidth, logoHeight, 10, 10); graphics2D.setStroke(new BasicStroke(4f)); graphics2D.draw(shape); graphics2D.dispose(); ImageIO.write(image, "png", resp.getOutputStream()); } catch (Exception e) { e.printStackTrace(); } } }
0x03 qrcode
在 pom.xml 中添加依赖
<dependency> <groupId>com.github.liuyueyi.media</groupId> <artifactId>qrcode-plugin</artifactId> <version>2.5.2</version> </dependency>
(1)黑白二维码
package com.qrcode.servlets; import com.github.hui.quick.plugin.qrcode.wrapper.QrCodeGenWrapper; import jakarta.servlet.ServletException; import jakarta.servlet.annotation.WebServlet; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.IOException; @WebServlet("/generate") public class GenerateQRCode extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { try { String url = req.getParameter("url"); BufferedImage image = QrCodeGenWrapper.of(url).asBufferedImage(); ImageIO.write(image, "png", resp.getOutputStream()); } catch (Exception e) { e.printStackTrace(); } } }
of()
:设置二维码内容asBufferedImage()
:生成二维码图片
(2)logo 二维码
package com.qrcode.servlets; import com.github.hui.quick.plugin.qrcode.wrapper.QrCodeGenWrapper; import com.github.hui.quick.plugin.qrcode.wrapper.QrCodeOptions; import jakarta.servlet.ServletException; import jakarta.servlet.annotation.MultipartConfig; import jakarta.servlet.annotation.WebServlet; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.IOException; @WebServlet("/generate") @MultipartConfig(fileSizeThreshold = 1024 * 1024 * 2, maxFileSize = 1024 * 1024 * 10, maxRequestSize = 1024 * 1024 * 100) public class GenerateQRCode extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { try { String url = req.getParameter("url"); BufferedImage image = QrCodeGenWrapper.of(url) .setLogo(req.getPart("logo").getInputStream()) .setLogoRate(7) .setLogoStyle(QrCodeOptions.LogoStyle.ROUND) .asBufferedImage(); ImageIO.write(image, "png", resp.getOutputStream()); } catch (Exception e) { e.printStackTrace(); } } }
setLogo()
:设置 Logo 文件setLogoRate(x)
:设置 Logo 缩放比,logo 宽高占二维码宽高的 x 分之一setLogoStyle()
:设置 Logo 样式
(3)彩色二维码
BufferedImage image = QrCodeGenWrapper.of(url) .setDrawPreColor(Color.BLUE) .asBufferedImage();
setDrawPreColor()
:设置前景色
(4)背景图二维码
BufferedImage image = QrCodeGenWrapper.of(url) .setBgImg(req.getPart("logo").getInputStream()) .setBgOpacity(0.7F) .asBufferedImage();
setBgImg()
:设置背景图setBgOpacity()
:设置背景图透明度
(5)特殊形状二维码
BufferedImage image = QrCodeGenWrapper.of(url) .setDrawEnableScale(true) .setDrawStyle(QrCodeOptions.DrawStyle.DIAMOND) .asBufferedImage();
setDrawEnableScale(true)
:启用二维码绘制时的缩放功能setDrawStyle()
:设置绘制样式
(6)图片填充二维码
BufferedImage image = QrCodeGenWrapper.of(url) .setErrorCorrection(ErrorCorrectionLevel.H) .setDrawStyle(QrCodeOptions.DrawStyle.IMAGE) .addImg(1, 1, req.getPart("logo").getInputStream()) .asBufferedImage();
-
setErrorCorrection()
:设置二维码的错误校正级别 -
setDrawStyle()
:绘制二维码时采用图片填充 -
addImg()
:添加图片
-End-
本文作者:SRIGT
本文链接:https://www.cnblogs.com/SRIGT/p/17659924.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步