Java集成Zxing和OpenCV实现二维码生成与识别工具类
本文将介绍如何使用Java集成Zxing和OpenCV库,实现二维码的生成和识别功能。识别方法支持多种输入形式,包括File对象、文件路径和Base64编码。
一、环境准备
- 添加Maven依赖
<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功能前,需要先加载本地库:
static {// 加载OpenCV本地库 nu.pattern.OpenCV.loadLocally();
}
二、二维码生成工具类
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());}
}
三、二维码识别工具类
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;}
}
四、使用示例
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项目中二维码处理的需求。