0. 前言
五一假期闲来无事,在翻看b站收藏夹的时候无意间发现了Java生成二维码教程这条视频,仔细一看,时长两小时?那不得赶紧学一个?
1. 技术栈
- SpringBoot
- 谷歌的:zxing
- 生成普通的黑白二维码。
- 在二维码中间添加一个小图标。
- github开源项目:qrcode
- qrcode开源项目的内部是基于zxing实现的,可以让二维码更加酷炫。
2. 环境搭建
1、新建一个 SpringBoot 项目,创建的时候勾选 SpringBoot Web 和 Thymeleaf 依赖。
2、添加依赖:
1 2 3 4 5 6 7 8 9 10
| <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency>
|
3、编写Controller:
1 2 3 4 5 6 7
| @Controller public class WebController { @RequestMapping("/") public String index() { return "index"; } }
|
3. 使用zxing
3.1 zxing相关依赖
1 2 3 4 5 6 7 8 9 10 11 12
| <dependency> <groupId>com.google.zxing</groupId> <artifactId>javase</artifactId> <version>3.1.0</version> </dependency>
<dependency> <groupId>commons-lang</groupId> <artifactId>commons-lang</artifactId> <version>2.6</version> </dependency>
|
3.2 zxing常用API
3.2.1 EncodeHintType(编码提示类型)
EncodeHintType是用来设置二维码编码时的一些额外参数的枚举类型,常用枚举值如下:
ERROR_CORRECTION
:
- 误差校正级别。对于黑白二维码,可选值为
L
(7%)、M
(15%)、Q
(25%)、H
(30%),表示二维码允许破损的最大容错率。在二维码出现破损时,根据设置的容错率级别,可以尝试修复二维码中的一些数据。
- 二维码在生成过程中,可能会出现一些损坏或者缺失的情况,例如打印时墨水耗尽、图像压缩、摄像头拍摄角度不对等。这些问题可能导致二维码无法完全识别,或者识别出来的数据不准确,而误差校正码就是为了解决这些问题而产生的。
- 例如,选择L级别的容错率,相当于允许在二维码的整体颜色区域中,最多可有约7%的坏像素点;而选择H级别的容错率时,最多可有约30%的坏像素点。
- 注意:误差校正级别的具体值需要通过ErrorCorrectionLevel的枚举值来获取。
CHARACTER_SET
:
- 编码字符集。可以设置使用的字符编码,例如utf-8、gb2312等等。
MARGIN
:
- 二维码的空白区域大小。可以设置二维码周围的留白大小,以便于在不同的嵌入场景中使用二维码。
MultiFormatWriter
是一个便捷的二维码生成类,可以根据传入的 BarcodeFormat
参数,生成对应类型的二维码。
MultiFormatWriter
封装了一系列的二维码生成方法,可以生成多种格式的二维码,包括QR Code、Aztec Code、PDF417、Data Matrix等。
BarcodeFormat是枚举类,通过它来制定二维码格式:
- QR Code :QR Code是最常见的二维码格式之一,广泛应用于商品包装、票务、扫码支付等领域。QR Code矩阵有黑白两种颜色,其中黑色部分表示信息的编码,白色部分则用于衬托和辨识。
- Aztec Code:Aztec Code是一种高密度、可靠性很高的二维码格式。相比于其他二维码格式,它具有更低的容错率、更小的尺寸和更高的解码效率。因此,它适合用于储存一些核心信息,例如个人信息、证件信息、账户密码等。
- PDF417:是一种可以储存大量信息的二维码格式,它具有数据密度高、可靠性强等优点,可以应用于许多场景,例如航空机票,运输和配送标签,法律文件等。
- Data Matrix:是一种小巧的二维码格式,它的编码方式类似于QR Code,但是其可靠性、识别率、扫描速度和牢固度都比QR Code更优秀。由于尺寸较小、可靠性较高,因此Data Matrix适合嵌入简单的产品标签、医疗图像、检测数据等领域。
3.2.4 BitMatrix(位矩阵)
BitMatrix
是zxing库中表示二维码矩阵的数据结构,它是由0和1构成的二维数组,用于存储二维码的编码信息。在二维码生成过程中,我们通过对 BitMatrix
对象的构建和操作,最终生成一个可被扫描解码的二维码图像。
BitMatrix
实际上是一个紧凑型的布尔型二维数组,往往只需要占用一个字节即可表示8位二进制。在使用 BitMatrix
时,我们可以通过其不同的方法,例如 get()
、set()
等,来获取、设置矩阵中每个位置的值。
在zxing中,BitMatrix
常用于将编码后的信息转化为矩阵形式,并进行图像的生成和输出。在使用zxing生成二维码时,我们首先需要使用 MultiFormatWriter.encode()
方法来生成一个 BitMatrix
;然后,在对 BitMatrix
进行各种处理和操作后,就可以在UI中显示和输出二维码。
总的来说,BitMatrix
是zxing库中非常重要的数据结构之一,它负责存储和处理生成二维码图像所需的二进制信息,是实现二维码生成功能的关键。
BitMatrix常用API:
- getHeight():获取矩阵高度
- getWidth():获取矩阵宽度
- get(x, y):根据x,y的坐标获取矩阵中该坐标的值。结果是true(黑色)或者false(白色)。
3.3 生成普通黑白二维码
前端代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"/> <title>生成普通黑白二维码</title> </head> <body> url:<input type="text" id="url"> <button onclick="generateQRcode()">生成二维码</button> <br> <img id="image"/> <script> function generateQRcode() { let url = document.getElementById("url").value; let i = document.getElementById("image"); i.src = "/qrcode/create?url=" + url; } </script> </body> </html>
|
后端代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| @Controller public class CreateQrcodeController { @RequestMapping("/create") public void create(HttpServletRequest request, HttpServletResponse response) { try { Map<EncodeHintType, Object> map = new HashMap<>(); map.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); map.put(EncodeHintType.CHARACTER_SET, "utf-8"); map.put(EncodeHintType.MARGIN, 1);
String url = request.getParameter("url");
MultiFormatWriter writer = new MultiFormatWriter(); BitMatrix bitMatrix = writer.encode(url, BarcodeFormat.QR_CODE, 300, 300, map); int width = bitMatrix.getWidth(); int height = bitMatrix.getHeight();
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 out = response.getOutputStream(); ImageIO.write(image, "png", out); out.flush(); out.close();
} catch (Exception e) { e.printStackTrace(); }
}
}
|
3.4 生成一个带logo的黑白二维码
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <!DOCTYPE html> <html lang="en"> <head> <title>生成带有logo的黑白二维码</title> <meta charset="UTF-8"> </head> <body> <form action="/generateWithLogo" method="post" enctype="multipart/form-data"> 请输入文本内容:<input type="text" name="url"><br> 请选择图片:<input type="file" name="logo"><br> <input type="submit" value="生成带有logo的二维码"/> </form> </body> </html>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
| @Controller @MultipartConfig(fileSizeThreshold = 1024 * 1024 * 2, maxFileSize = 1024 * 1024 * 10, maxRequestSize = 1024 * 1024 * 100) public class GenerateQrCodeWithLogoController {
@RequestMapping("/generateWithLogo") public void create(HttpServletRequest request, HttpServletResponse response) { try { Map<EncodeHintType, Object> map = new HashMap<>(); map.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); map.put(EncodeHintType.CHARACTER_SET, "UTF-8"); map.put(EncodeHintType.MARGIN, 1);
String url = request.getParameter("url");
MultiFormatWriter writer = new MultiFormatWriter(); BitMatrix bitMatrix = writer.encode(url, BarcodeFormat.QR_CODE, 300, 300, map); int width = bitMatrix.getWidth(); int height = bitMatrix.getHeight();
BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { bufferedImage.setRGB(x, y, bitMatrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF); } }
Part logo = request.getPart("logo"); InputStream inputStream = logo.getInputStream(); Image logoImage = ImageIO.read(inputStream); int logoWidth = logoImage.getWidth(null); int logoHeight = logoImage.getHeight(null); if (logoWidth > 60) { logoWidth = 60; } if (logoHeight > 60) { logoHeight = 60; } Image scaledLogo = logoImage.getScaledInstance(logoWidth, logoHeight, Image.SCALE_SMOOTH);
Graphics2D graphics2D = bufferedImage.createGraphics(); int x = (300 - logoWidth) / 2; int y = (300 - logoHeight) / 2; graphics2D.drawImage(scaledLogo, 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(bufferedImage, "png", response.getOutputStream());
} catch (Exception e) { e.printStackTrace(); }
} }
|
4. 使用qrcode
1 2 3 4 5
| <dependency> <groupId>com.github.liuyueyi.media</groupId> <artifactId>qrcode-plugin</artifactId> <version>3.0.0</version> </dependency>
|
4.1 生成黑白二维码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| @MultipartConfig(fileSizeThreshold = 1024 * 1024 * 2, maxFileSize = 1024 * 1024 * 10, maxRequestSize = 1024 * 1024 * 100) public class GenerateWithQrCodeController {
@RequestMapping("/generateWithQrCode") public void create(HttpServletRequest request, HttpServletResponse response) { try { String url = request.getParameter("url"); BufferedImage image = QrCodeGenWrapper.of(url).asBufferedImage(); ImageIO.write(image, "png", response.getOutputStream()); } catch (Exception e) { throw new RuntimeException(e); } } }
|
4.2 生成带有logo的二维码
1 2 3 4 5 6 7 8 9
| String url = request.getParameter("url");
BufferedImage image = QrCodeGenWrapper.of(url) .setLogo(request.getPart("logo").getInputStream()) .setLogoRate(7) .setLogoStyle(QrCodeOptions.LogoStyle.ROUND) .asBufferedImage();
ImageIO.write(image, "png", response.getOutputStream());
|
4.3 生成彩色二维码
1 2 3 4 5 6 7
| String url = request.getParameter("url");
BufferedImage image = QrCodeGenWrapper.of(url) .setDrawPreColor(Color.BLUE) .asBufferedImage();
ImageIO.write(image, "png", response.getOutputStream());
|
4.4 生成背景图二维码
1 2 3 4 5 6 7 8
| String url = request.getParameter("url");
BufferedImage image = QrCodeGenWrapper.of(url) .setBgImg(request.getPart("logo").getInputStream()) .setBgOpacity(0.7F) .asBufferedImage();
ImageIO.write(image, "png", response.getOutputStream());
|
4.5 特殊形状二维码
1 2 3 4 5 6 7 8
| String url = request.getParameter("url");
BufferedImage image = QrCodeGenWrapper.of(url) .setDrawEnableScale(true) .setDrawStyle(QrCodeOptions.DrawStyle.DIAMOND) .asBufferedImage();
ImageIO.write(image, "png", response.getOutputStream());
|
4.6 图片填充二维码
1 2 3 4 5 6 7 8 9
| String url = request.getParameter("url");
BufferedImage image = QrCodeGenWrapper.of(url) .setErrorCorrection(ErrorCorrectionLevel.H) .setDrawStyle(QrCodeOptions.DrawStyle.IMAGE) .addImg(1, 1, request.getPart("logo").getInputStream()) .asBufferedImage();
ImageIO.write(image, "png", response.getOutputStream());
|
4.7 生成gif动图二维码
1 2 3 4 5 6 7 8 9 10 11
| String url = request.getParameter("url");
BufferedImage image = QrCodeGenWrapper.of(url) .setW(500) .setH(500) .setBgImg(request.getPart("logo").getInputStream()) .setBgOpacity(0.6f) .setPicType("gif") .asBufferedImage();
ImageIO.write(image, "gif", response.getOutputStream());
|