Java集成Zxing和OpenCV实现二维码生成与识别工具类
本文将介绍如何使用Java集成Zxing和OpenCV库,实现二维码的生成和识别功能。识别方法支持多种输入形式,包括File对象、文件路径和Base64编码。
一、环境准备
- 添加Maven依赖
xml
<dependencies>
<!-- Zxing核心库 -->
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>core</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>javase</artifactId>
<version>3.5.2</version>
</dependency>
<!-- OpenCV库 -->
<dependency>
<groupId>org.openpnp</groupId>
<artifactId>opencv</artifactId>
<version>4.5.5-1</version>
</dependency>
<!-- 其他工具类 -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
</dependency>
</dependencies>
- OpenCV库加载
在使用OpenCV功能前,需要先加载本地库:
java
static {
// 加载OpenCV本地库
nu.pattern.OpenCV.loadLocally();
}
二、二维码生成工具类
java
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
public class QRCodeGenerator {
private static final int DEFAULT_WIDTH = 300;
private static final int DEFAULT_HEIGHT = 300;
private static final String DEFAULT_FORMAT = "png";
/
* 生成二维码图片
* @param content 二维码内容
* @param width 宽度
* @param height 高度
* @return BufferedImage对象
*/
public static BufferedImage generateQRCodeImage(String content, int width, int height) throws WriterException {
Map<EncodeHintType, Object> hints = new HashMap<>();
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
hints.put(EncodeHintType.MARGIN, 1);
hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
QRCodeWriter qrCodeWriter = new QRCodeWriter();
BitMatrix bitMatrix = qrCodeWriter.encode(content, BarcodeFormat.QR_CODE, width, height, hints);
return MatrixToImageWriter.toBufferedImage(bitMatrix);
}
/
* 生成二维码并保存到文件
* @param content 二维码内容
* @param width 宽度
* @param height 高度
* @param filePath 文件路径
*/
public static void generateQRCodeToFile(String content, int width, int height, String filePath)
throws WriterException, IOException {
BufferedImage image = generateQRCodeImage(content, width, height);
ImageIO.write(image, DEFAULT_FORMAT, new File(filePath));
}
/
* 生成二维码并返回Base64编码
* @param content 二维码内容
* @param width 宽度
* @param height 高度
* @return Base64编码字符串
*/
public static String generateQRCodeToBase64(String content, int width, int height)
throws WriterException, IOException {
BufferedImage image = generateQRCodeImage(content, width, height);
ByteArrayOutputStream os = new ByteArrayOutputStream();
ImageIO.write(image, DEFAULT_FORMAT, os);
return Base64.getEncoder().encodeToString(os.toByteArray());
}
}
三、二维码识别工具类
java
import com.google.zxing.*;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.common.HybridBinarizer;
import org.opencv.core.*;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.util.Base64;
import java.util.EnumMap;
import java.util.Map;
public class QRCodeRecognizer {
static {
// 加载OpenCV本地库
nu.pattern.OpenCV.loadLocally();
}
/
* 识别二维码内容 - 通过File对象
* @param file 二维码图片文件
* @return 识别结果
*/
public static String recognizeQRCode(File file) throws IOException, NotFoundException {
BufferedImage image = ImageIO.read(file);
return decodeQRCode(image);
}
/
* 识别二维码内容 - 通过文件路径
* @param filePath 二维码图片路径
* @return 识别结果
*/
public static String recognizeQRCode(String filePath) throws IOException, NotFoundException {
// 使用OpenCV预处理图像提高识别率
Mat image = Imgcodecs.imread(filePath);
if (image.empty()) {
throw new IOException("无法读取图像文件: " + filePath);
}
// 转换为灰度图
Mat gray = new Mat();
Imgproc.cvtColor(image, gray, Imgproc.COLOR_BGR2GRAY);
// 二值化处理
Mat binary = new Mat();
Imgproc.threshold(gray, binary, 0, 255, Imgproc.THRESH_BINARY | Imgproc.THRESH_OTSU);
// 转换为BufferedImage
BufferedImage bufferedImage = matToBufferedImage(binary);
return decodeQRCode(bufferedImage);
}
/
* 识别二维码内容 - 通过Base64编码
* @param base64Str 二维码图片的Base64编码
* @return 识别结果
*/
public static String recognizeQRCodeFromBase64(String base64Str) throws IOException, NotFoundException {
byte[] imageBytes = Base64.getDecoder().decode(base64Str);
ByteArrayInputStream bis = new ByteArrayInputStream(imageBytes);
BufferedImage image = ImageIO.read(bis);
return decodeQRCode(image);
}
/
* 核心解码方法
*/
private static String decodeQRCode(BufferedImage image) throws NotFoundException {
LuminanceSource source = new BufferedImageLuminanceSource(image);
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
Map<DecodeHintType, Object> hints = new EnumMap<>(DecodeHintType.class);
hints.put(DecodeHintType.TRY_HARDER, Boolean.TRUE);
hints.put(DecodeHintType.CHARACTER_SET, "UTF-8");
Result result = new MultiFormatReader().decode(bitmap, hints);
return result.getText();
}
/
* 将OpenCV的Mat对象转换为BufferedImage
*/
private static BufferedImage matToBufferedImage(Mat mat) {
int type = BufferedImage.TYPE_BYTE_GRAY;
if (mat.channels() > 1) {
type = BufferedImage.TYPE_3BYTE_BGR;
}
byte[] data = new byte[mat.cols() * mat.rows() * (int)mat.elemSize()];
mat.get(0, 0, data);
BufferedImage image = new BufferedImage(mat.cols(), mat.rows(), type);
image.getRaster().setDataElements(0, 0, mat.cols(), mat.rows(), data);
return image;
}
}
四、使用示例
java
public class QRCodeExample {
public static void main(String[] args) {
try {
// 1. 生成二维码
String content = "https://www.example.com";
String filePath = "qrcode.png";
// 生成并保存二维码
QRCodeGenerator.generateQRCodeToFile(content, 300, 300, filePath);
System.out.println("二维码已生成到: " + filePath);
// 2. 识别二维码 - 通过File对象
File qrFile = new File(filePath);
String decodedContent1 = QRCodeRecognizer.recognizeQRCode(qrFile);
System.out.println("识别结果(File): " + decodedContent1);
// 3. 识别二维码 - 通过文件路径
String decodedContent2 = QRCodeRecognizer.recognizeQRCode(filePath);
System.out.println("识别结果(文件路径): " + decodedContent2);
// 4. 识别二维码 - 通过Base64
String base64 = QRCodeGenerator.generateQRCodeToBase64(content, 300, 300);
String decodedContent3 = QRCodeRecognizer.recognizeQRCodeFromBase64(base64);
System.out.println("识别结果(Base64): " + decodedContent3);
} catch (Exception e) {
e.printStackTrace();
}
}
}
五、关键点说明
-
OpenCV预处理:在识别二维码时,使用OpenCV对图像进行灰度化和二值化处理,可以显著提高识别率,特别是对低质量或模糊的二维码图像。
-
多输入支持:识别方法支持三种输入形式:
File
对象:直接读取文件- 文件路径:使用OpenCV读取并预处理
- Base64编码:适用于网络传输的场景
-
错误处理:方法会抛出
IOException
和NotFoundException
,调用方需要处理这些异常。 -
性能优化:
- 使用
TRY_HARDER
提示让解码器更努力尝试解码 - 指定字符集为UTF-8确保中文内容正确识别
- OpenCV的预处理可以有效提高识别率
- 使用
六、扩展建议
-
添加Logo:可以在生成二维码时添加中心Logo,增强品牌识别度。
-
颜色定制:修改生成方法支持自定义前景色和背景色。
-
批量处理:扩展工具类支持批量生成和识别二维码。
-
性能监控:添加耗时统计和性能监控功能。
这个工具类结合了Zxing的高效二维码生成/识别能力和OpenCV强大的图像处理能力,可以满足大多数Java项目中二维码处理的需求。