主要介绍java常用解析二维码的两种方式!
写在前边:第一种比第二种功能要更强大一点,其可以解析图片中的二维码图片,但是第二种不可以。
使用File处理文件的方式适合在本地测试使用,如果把二维码图片现在到本地服务器,然后处理也不是不可以,只是比较麻烦。
使用输入流的方式适合在服务中使用,可以有效解决图片链接中带点号的问题。
实例demo以及第三方依赖jar包下载地址:点击打开链接
直接上代码
第一种:使用QRCode
1.maven依赖
<dependency>
<groupId>QRCode</groupId>
<artifactId>QRCode</artifactId>
<version>3.0</version>
</dependency>
2.主要代码
package com.xxx.xxx.biz.util;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import javax.imageio.ImageIO;
import com.swetake.util.Qrcode;
import jp.sourceforge.qrcode.QRCodeDecoder;
import jp.sourceforge.qrcode.exception.DecodingFailedException;
/**
*
* Copyright © 2018 www.xxx.com All rights reserved.
*
* 功能描述:二维码工具类
* @Package: com.xxx.xxx.web.util
* @author: clg
* @date: 2018年5月14日 下午3:39:27
*/
public class TwoDimensionCodeUtil {
/**
* 生成二维码(QRCode)图片
* @param content 存储内容
* @param imgPath 图片路径
*/
public void encoderQRCode(String content, String imgPath) {
this.encoderQRCode(content, imgPath, "png", 7);
}
/**
* 生成二维码(QRCode)图片
* @param content 存储内容
* @param imgPath 图片路径
* @param imgType 图片类型
* @param size 二维码尺寸
*/
public void encoderQRCode(String content, String imgPath, String imgType, int size) {
try {
BufferedImage bufImg = this.qRCodeCommon(content, imgType, size);
File imgFile = new File(imgPath);
// 生成二维码QRCode图片
ImageIO.write(bufImg, imgType, imgFile);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 生成二维码(QRCode)图片的公共方法
* @param content 存储内容
* @param imgType 图片类型
* @param size 二维码尺寸
* @return
*/
private BufferedImage qRCodeCommon(String content, String imgType, int size) {
BufferedImage bufImg = null;
try {
Qrcode qrcodeHandler = new Qrcode();
// 设置二维码排错率,可选L(7%)、M(15%)、Q(25%)、H(30%),排错率越高可存储的信息越少,但对二维码清晰度的要求越小
qrcodeHandler.setQrcodeErrorCorrect('M');
qrcodeHandler.setQrcodeEncodeMode('B');
// 设置设置二维码尺寸,取值范围1-40,值越大尺寸越大,可存储的信息越大
qrcodeHandler.setQrcodeVersion(size);
// 获得内容的字节数组,设置编码格式
byte[] contentBytes = content.getBytes("utf-8");
// 图片尺寸
int imgSize = 67 + 12 * (size - 1);
bufImg = new BufferedImage(imgSize, imgSize, BufferedImage.TYPE_INT_RGB);
Graphics2D gs = bufImg.createGraphics();
// 设置背景颜色
gs.setBackground(Color.WHITE);
gs.clearRect(0, 0, imgSize, imgSize);
// 设定图像颜色> BLACK
gs.setColor(Color.BLACK);
// 设置偏移量,不设置可能导致解析出错
int pixoff = 2;
// 输出内容> 二维码
if (contentBytes.length > 0 && contentBytes.length < 800) {
boolean[][] codeOut = qrcodeHandler.calQrcode(contentBytes);
for (int i = 0; i < codeOut.length; i++) {
for (int j = 0; j < codeOut.length; j++) {
if (codeOut[j][i]) {
gs.fillRect(j * 3 + pixoff, i * 3 + pixoff, 3, 3);
}
}
}
} else {
throw new Exception("QRCode content bytes length = " + contentBytes.length + " not in [0, 800].");
}
gs.dispose();
bufImg.flush();
} catch (Exception e) {
e.printStackTrace();
}
return bufImg;
}
/**
* 解析二维码(QRCode)
* @param imgPath 图片路径
* @return
*/
public static String decoderQRCode(String imgPath) {
// QRCode 二维码图片的文件
BufferedImage bufImg = null;
String content = null;
try {
InputStream input = getInputStream(imgPath);
// File input = new File(imgPath);//注释4
bufImg = ImageIO.read(input);
QRCodeDecoder decoder = new QRCodeDecoder();
content = new String(decoder.decode(new TwoDimensionCodeImage(bufImg)), "utf-8");
} catch (IOException e) {
System.out.println("Error: " + e.getMessage());
e.printStackTrace();
} catch (DecodingFailedException dfe) {
System.out.println("Error: " + dfe.getMessage());
dfe.printStackTrace();
}
return content;
}
/**下载服务器图片输入流*/
public static InputStream getInputStream(String path){
InputStream inputStream=null;
HttpURLConnection httpURLConnection=null;
try{
URL url=new URL(path);
if(url!=null){
httpURLConnection=(HttpURLConnection) url.openConnection();
httpURLConnection.setConnectTimeout(3000);
httpURLConnection.setRequestMethod("GET");
int responseCode=httpURLConnection.getResponseCode();
if(responseCode==200){
inputStream=httpURLConnection.getInputStream();
}
}
}catch(Exception e){
e.printStackTrace();
}
return inputStream;
}
public static void main(String[] args) {
TwoDimensionCodeUtil util = new TwoDimensionCodeUtil();
util.encoderQRCode("www.baidu.com", "C:/Users/dell/Desktop/work-down/2.jpg");
// String imgPath = "C:/Users/dell/Desktop/work-down/1.jpg";//注释1
// imgPath = "http://wdgj.oss-cn-xxxx.aliyuncs.com/community/post/f496d880915c430e916b970e4848bd29.jpg";//注释2
// String cont = decoderQRCode(imgPath);//注释3
}
}
3.执行说明:
一、直接运行main方法,生成二维码图片目录:C:/Users/dell/Desktop/work-down/1.jpg。
二、打开注释1、注释2和注释3,执行main方法,控制台打印出二维码图片中的内容(图片链接中带点号)。
三、关闭注释2并打开注释4,执行main方法,控制台打印出二维码图片中的内容(本地图片)。
备注:图片链接中如果有点号(后缀除外),不能使用File处理,只能适用流的方式!!!
第二种:使用Google工具
1.maven依赖
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>core</artifactId>
<version>3.3.0</version>
</dependency>
2.主要代码
package com.xxx.xxx.biz.util;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import javax.imageio.ImageIO;
import com.google.zxing.Binarizer;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.DecodeHintType;
import com.google.zxing.LuminanceSource;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.Result;
import com.google.zxing.common.HybridBinarizer;
/**
*
* Copyright © 2018 www.xxx.com All rights reserved.
* 功能描述:用于二维码的解析,由Google提供。
* 存在局限性,不能识别图片中附带的二维码
* @Package: com.xxx.xxx.biz.util
* @author: clg
* @date: 2018年5月14日 下午5:14:31
*/
public final class BufferedImageLuminanceSource extends LuminanceSource {
private final BufferedImage image;
private final int left;
private final int top;
public BufferedImageLuminanceSource(BufferedImage image) {
this(image, 0, 0, image.getWidth(), image.getHeight());
}
public BufferedImageLuminanceSource(BufferedImage image, int left, int top, int width, int height) {
super(width, height);
int sourceWidth = image.getWidth();
int sourceHeight = image.getHeight();
if (left + width > sourceWidth || top + height > sourceHeight) {
throw new IllegalArgumentException("Crop rectangle does not fit within image data.");
}
for (int y = top; y < top + height; y++) {
for (int x = left; x < left + width; x++) {
if ((image.getRGB(x, y) & 0xFF000000) == 0) {
image.setRGB(x, y, 0xFFFFFFFF); // = white
}
}
}
this.image = new BufferedImage(sourceWidth, sourceHeight, BufferedImage.TYPE_BYTE_GRAY);
this.image.getGraphics().drawImage(image, 0, 0, null);
this.left = left;
this.top = top;
}
@Override
public byte[] getRow(int y, byte[] row) {
if (y < 0 || y >= getHeight()) {
throw new IllegalArgumentException("Requested row is outside the image: " + y);
}
int width = getWidth();
if (row == null || row.length < width) {
row = new byte[width];
}
image.getRaster().getDataElements(left, top + y, width, 1, row);
return row;
}
@Override
public byte[] getMatrix() {
int width = getWidth();
int height = getHeight();
int area = width * height;
byte[] matrix = new byte[area];
image.getRaster().getDataElements(left, top, width, height, matrix);
return matrix;
}
@Override
public boolean isCropSupported() {
return true;
}
@Override
public LuminanceSource crop(int left, int top, int width, int height) {
return new BufferedImageLuminanceSource(image, this.left + left, this.top + top, width, height);
}
@Override
public boolean isRotateSupported() {
return true;
}
@Override
public LuminanceSource rotateCounterClockwise() {
int sourceWidth = image.getWidth();
int sourceHeight = image.getHeight();
AffineTransform transform = new AffineTransform(0.0, -1.0, 1.0, 0.0, 0.0, sourceWidth);
BufferedImage rotatedImage = new BufferedImage(sourceHeight, sourceWidth, BufferedImage.TYPE_BYTE_GRAY);
Graphics2D g = rotatedImage.createGraphics();
g.drawImage(image, transform, null);
g.dispose();
int width = getWidth();
return new BufferedImageLuminanceSource(rotatedImage, top, sourceWidth - (left + width), getHeight(), width);
}
/**
* 解析指定路径下的二维码图片
*
* @param filePath 二维码图片路径
* @return
*/
private static String parseQRCode(String filePath) {
String content = "";
try {
// File file = new File(filePath);//注释4
InputStream input = getInputStream(filePath);//注释2
BufferedImage image = ImageIO.read(input);
LuminanceSource source = new BufferedImageLuminanceSource(image);
Binarizer binarizer = new HybridBinarizer(source);
BinaryBitmap binaryBitmap = new BinaryBitmap(binarizer);
Map<DecodeHintType, Object> hints = new HashMap<>();
hints.put(DecodeHintType.CHARACTER_SET, "UTF-8");
MultiFormatReader formatReader = new MultiFormatReader();
Result result = formatReader.decode(binaryBitmap, hints);
//设置返回值
content = result.getText();
} catch (Exception e) {
e.printStackTrace();
}
return content;
}
public static InputStream getInputStream(String path){
InputStream inputStream=null;
HttpURLConnection httpURLConnection=null;
try{
URL url=new URL(path);
if(url!=null){
httpURLConnection=(HttpURLConnection) url.openConnection();
httpURLConnection.setConnectTimeout(3000);
httpURLConnection.setRequestMethod("GET");
int responseCode=httpURLConnection.getResponseCode();
if(responseCode==200){
inputStream=httpURLConnection.getInputStream();
}
}
}catch(Exception e){
e.printStackTrace();
}
return inputStream;
}
public static void main(String[] args) {
String cont = parseQRCode("http://xxx.xxx.xxx.com/community/post/f496d880915c430e916b970e4848bd29.jpg");//注释1
// String cont = parseQRCode("C:/Users/dell/Desktop/work-down/3.jpg");//注释3
System.out.println(cont);
}
}
3.执行说明:
一、直接运行main方法,控制台打印出二维码图片中的内容(图片链接中带点号)。
二、打开注释3和注释4,注释注释1和注释2,执行main方法,控制台打印出二维码图片中的内容(本地图片)。
备注:图片链接中如果有点号(后缀除外),不能使用File处理,只能适用流的方式!!!