Java 实现二维码生成与解析

得益于二维码的信息容量大、容错能力强、制作成本低等优点,在移动互联网时代,二维码得到了非常广泛的应用。

当然本篇文章并不是要讲二维码编码原理,想要了解原理可以看:https://coolshell.cn/articles/10590.html。本文主要讲应用层面,Java 中怎么生成和解析二维码。

二维码的生成和解析自然涉及到编码算法,这里我们引用 Google 的一个第三方包作为基础:

1
2
3
4
5
6
7
8
9
10
11
12
<!-- https://mvnrepository.com/artifact/com.google.zxing/core -->
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>core</artifactId>
<version>3.3.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.google.zxing/javase -->
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>javase</artifactId>
<version>3.3.0</version>
</dependency>

具体生成和解析方法:

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
79
80
81
82
83
84
85
86
87
88
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

import javax.imageio.ImageIO;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.DecodeHintType;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.Result;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.client.j2se.MatrixToImageConfig;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;

/**
* 二维码工具类
*/
public class QRCodeUtils {

/**
* 生成二维码图片
* @param content 二维码内容
* @param size 图片大小
* @param outPath 图片输出路径
* @param onColor 前景色,默认黑色
* @param offColor 背景色, 默认白色
* @return
*/
public static void generateQRCode(String content, int size, String outPath, Color onColor, Color offColor) throws Exception {
File imageFile = new File(outPath);
if (imageFile.exists()) {
throw new RuntimeException("Image:" + outPath + "exist.");
}
Map<EncodeHintType, Object> hints = new HashMap<>();
hints.put(EncodeHintType.CHARACTER_SET, StandardCharsets.UTF_8); // 内容编码
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); // 纠错级别
hints.put(EncodeHintType.MARGIN, 1); // 外边距
// 设置颜色(默认黑白)
if (onColor == null) onColor = Color.BLACK;
if (offColor == null) offColor = Color.WHITE;
MatrixToImageConfig config = new MatrixToImageConfig(onColor.getRGB(), offColor.getRGB());
BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, size, size, hints);
MatrixToImageWriter.writeToPath(bitMatrix, "jpg", imageFile.toPath(), config);
}

/**
* 解析二维码内容
* @param imageInputStream 图片输入流
* @return
*/
public static String readQRCode(InputStream imageInputStream) throws Exception {
if (imageInputStream == null) {
throw new RuntimeException("Image inputStream is null.");
}
return readQRCode(ImageIO.read(imageInputStream));
}

/**
* 解析二维码内容
* @param imageFile 二维码文件
* @return
*/
public static String readQRCode(File imageFile) throws Exception {
if (!imageFile.exists()) {
throw new RuntimeException("Image not exist.");
}
return readQRCode(ImageIO.read(imageFile));
}

private static String readQRCode(BufferedImage image) throws Exception {
Map<DecodeHintType, Object> hints = new HashMap();
hints.put(DecodeHintType.CHARACTER_SET, StandardCharsets.UTF_8);
BufferedImageLuminanceSource source = new BufferedImageLuminanceSource(image);
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
Result result = new MultiFormatReader().decode(bitmap, hints);
return result.getText();
}
}

单元测试:

1
2
3
4
5
6
7
8
9
10
@Test
public void testQRCode() throws Exception {
String path = "D:\\qrcode.jpg";
// 生成
QRCodeUtils.generateQRCode("https://zhangzw.com/posts/20191203.html", 200, path, Color.BLUE, new Color(250, 250, 250));
// 解析
String content = QRCodeUtils.readQRCode(new FileInputStream(path));
System.out.println("解析二维码:" + content);
}
// out: 解析二维码:https://zhangzw.com/posts/20191203.html

生成效果:

1575967723784