生成二维码的方式有多种,这里使用 Google的 Zxing 架包。在maven项目中添加依赖
com.google.zxing
core
3.3.3
com.google.zxing
javase
3.3.3
二维码主要包括两各方面:
1)将信息生成二维码展示(图片,字节数组),中文信息慎用,注意乱码问题
2)解析二维码读取其字符串信息。
参数传入二维码文件或者 InputStream流都可以,将二维码加载都内存中(BufferedImage),然后根据Zing的API解析
1、生成简单二维码并解析
import com.google.zxing.*;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.HybridBinarizer;
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.*;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
/**
* 生成二维码工具类
*/
public class QRCodeUtil {
private static final String CHARSET = "UTF-8";
private static final String FORMAT_NAME = "JPG";
private QRCodeUtil(){}
/**
* 生成二维码图片,传文件流
* @param content 内容
* @param width 宽度
* @param height 高度
* @param outputStream 输出流
* @throws IOException
* @throws WriterException
*/
public static void generateQRCodeImage(String content, int width, int height, OutputStream outputStream) throws IOException, WriterException {
// 用于设置QR二维码参数
Hashtable hints = new Hashtable();
// 设置QR二维码的纠错级别——这里选择最高H级别
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
// 设置编码方式
hints.put(EncodeHintType.CHARACTER_SET, CHARSET);
BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, width, height,hints);
MatrixToImageWriter.writeToStream(bitMatrix,FORMAT_NAME,outputStream);
}
/**
* 生成二维码图片,传文件path
* @param content 内容
* @param width 宽度
* @param height 高度
* @param filePath 文件路径
* @throws IOException
* @throws WriterException
*/
public static void generateQRCodeImage(String content, int width, int height, String filePath) throws IOException,
WriterException {
// 用于设置QR二维码参数
Hashtable hints = new Hashtable();
// 设置QR二维码的纠错级别——这里选择最高H级别
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
// 设置编码方式
hints.put(EncodeHintType.CHARACTER_SET, CHARSET);
BitMatrix bitMatrix = new QRCodeWriter().encode(content, BarcodeFormat.QR_CODE, width, height,hints);
Path path = FileSystems.getDefault().getPath(filePath);
MatrixToImageWriter.writeToPath(bitMatrix,FORMAT_NAME,path);
}
/**
* 生成二维码返回byte数组
* @param content 内容
* @param width 宽度
* @param height 高度
* @return 二维码的byte数组
*/
public static byte[] getQRCodeImage(String content, int width, int height) throws IOException, WriterException {
ByteArrayOutputStream pngOutputStream = new ByteArrayOutputStream();
// 用于设置QR二维码参数
Hashtable hints = new Hashtable();
// 设置QR二维码的纠错级别——这里选择最高H级别
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
// 设置编码方式
hints.put(EncodeHintType.CHARACTER_SET, CHARSET);
BitMatrix bitMatrix = new QRCodeWriter().encode(content, BarcodeFormat.QR_CODE, width, height,hints);
MatrixToImageWriter.writeToStream(bitMatrix, FORMAT_NAME, pngOutputStream);
return pngOutputStream.toByteArray();
}
/**
* 解析二维码获取内容
* @param file 二维码文件,或定义InputStream
* @return 二维码包含的字符串信息
* @throws Exception
*/
public static String decodeQRCodeImage(File file) throws Exception {
if (!file.exists()) {
return null;
}
BufferedImage image = ImageIO.read(file);
BufferedImageLuminanceSource source = new BufferedImageLuminanceSource(image);
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
Map hints = new HashMap();
hints.put(DecodeHintType.CHARACTER_SET, CHARSET);
Result result = new MultiFormatReader().decode(bitmap, hints);
return result.getText();
}
public static void main(String[] args) throws Exception {
// 生成二维码都OK
/*String filePath = "E:/java/as1234.jpg";
//QRCodeUtil.generateQRCodeImage("https://www.baidu.com",550,550,filePath);
FileOutputStream outputStream = new FileOutputStream(filePath);
//QRCodeUtil.generateQRCodeImage("asdaklj123112abc",550,550,outputStream);
byte[] data = QRCodeUtil.getQRCodeImage("发送端sadds12312", 550, 500);
outputStream.write(data);
outputStream.close();*/
// 解析二维码
String resultStr = QRCodeUtil.decodeQRCodeImage(new File("E:/java/as1234.jpg"));
System.out.println(resultStr);
}
}
2、生成二维码中间带logo,底部带文字说明
import com.google.zxing.*;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.QRCodeWriter;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.*;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
/**
* 生成二维码工具类
*/
public class QRCodeUtil {
private static final String CHARSET = "UTF-8";
private static final String FORMAT_NAME = "JPG";
private QRCodeUtil(){}
/**
* 生成二维码图片,传文件流
* @param content 内容
* @param width 宽度
* @param height 高度
* @param outputStream 输出流
* @throws IOException
* @throws WriterException
*/
public static void generateQRCodeImage(String content, int width, int height, OutputStream outputStream) throws IOException, WriterException {
// 用于设置QR二维码参数
Hashtable hints = new Hashtable();
// 设置QR二维码的纠错级别——这里选择最高H级别
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
// 设置编码方式
hints.put(EncodeHintType.CHARACTER_SET, CHARSET);
BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, width, height,hints);
MatrixToImageWriter.writeToStream(bitMatrix,FORMAT_NAME,outputStream);
}
/**
* 生成二维码图片,传文件path
* @param content 内容
* @param width 宽度
* @param height 高度
* @param filePath 文件路径
* @throws IOException
* @throws WriterException
*/
public static void generateQRCodeImage(String content, int width, int height, String filePath) throws IOException,
WriterException {
// 用于设置QR二维码参数
Hashtable hints = new Hashtable();
// 设置QR二维码的纠错级别——这里选择最高H级别
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
// 设置编码方式
hints.put(EncodeHintType.CHARACTER_SET, CHARSET);
BitMatrix bitMatrix = new QRCodeWriter().encode(content, BarcodeFormat.QR_CODE, width, height,hints);
Path path = FileSystems.getDefault().getPath(filePath);
MatrixToImageWriter.writeToPath(bitMatrix,FORMAT_NAME,path);
}
/**
* 生成二维码返回byte数组
* @param content 内容
* @param width 宽度
* @param height 高度
* @return 二维码的byte数组
*/
public static byte[] getQRCodeImage(String content, int width, int height) throws IOException, WriterException {
ByteArrayOutputStream pngOutputStream = new ByteArrayOutputStream();
// 用于设置QR二维码参数
Hashtable hints = new Hashtable();
// 设置QR二维码的纠错级别——这里选择最高H级别
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
// 设置编码方式
hints.put(EncodeHintType.CHARACTER_SET, CHARSET);
BitMatrix bitMatrix = new QRCodeWriter().encode(content, BarcodeFormat.QR_CODE, width, height,hints);
MatrixToImageWriter.writeToStream(bitMatrix, FORMAT_NAME, pngOutputStream);
return pngOutputStream.toByteArray();
}
/**
* 解析二维码获取内容
* @param file 二维码文件,或定义InputStream
* @return 二维码包含的字符串信息
* @throws Exception
*/
public static String decodeQRCodeImage(File file) throws Exception {
if (!file.exists()) {
return null;
}
BufferedImage image = ImageIO.read(file);
BufferedImageLuminanceSource source = new BufferedImageLuminanceSource(image);
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
Map hints = new HashMap();
hints.put(DecodeHintType.CHARACTER_SET, CHARSET);
Result result = new MultiFormatReader().decode(bitmap, hints);
return result.getText();
}
/**
* 给二维码插入logo图片
* @param data 二维码的字节数据,也可以是二维码文件,将二维码数据加载进内存处理就ok
* @param logoFile logo图片所在的路径
* @param needCompressed 是否需要压缩logo图片
* @return 带logo二维码的byte数组
* @throws IOException
*/
private static byte[] addLogoImage(byte[] data, File logoFile, boolean needCompressed) throws IOException {
if (!logoFile.exists()){
System.out.println("logo文件不存在");
return null;
}
BufferedImage qrcodeImage = ImageIO.read(new ByteArrayInputStream(data)); //data图片数据加载进内存
int qrcodeWidth = qrcodeImage.getWidth(null);
int qrcodeHeight = qrcodeImage.getHeight(null);
Image logoImage = ImageIO.read(logoFile);
int logoWidth = logoImage.getWidth(null);
int logoHight = logoImage.getHeight(null);
// 压缩logo图片
if (needCompressed) {
if (logoWidth > qrcodeWidth) logoWidth = qrcodeWidth/5;
if (logoHight > qrcodeHeight) logoHight = qrcodeHeight/5;
Image src = logoImage.getScaledInstance(logoWidth, logoWidth, Image.SCALE_SMOOTH); //创建此图像的缩放版本。
BufferedImage tag = new BufferedImage(logoWidth, logoWidth, BufferedImage.TYPE_INT_RGB);
Graphics2D graphics = tag.createGraphics();
graphics.drawImage(src, 0, 0, null);// 绘制当前可用的指定图像的大小。
graphics.dispose(); // 释放占有的资源
logoImage = src;
}
//logoWidth = logoImage.getWidth(null);
//logoHight = logoImage.getHeight(null);
// 插入logo图片
Graphics2D graphics = qrcodeImage.createGraphics();
int x = (qrcodeWidth - logoWidth) / 2;
int y = (qrcodeHeight - logoHight) / 2;
graphics.drawImage(logoImage, x, y, logoWidth, logoHight, null);
Shape shape = new RoundRectangle2D.Float(x, y, logoWidth, logoHight, 6, 6);
graphics.setStroke(new BasicStroke(3f));
graphics.draw(shape);
graphics.dispose();
// 带logo二维码返回
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ImageIO.write(qrcodeImage, FORMAT_NAME, bos);
return bos.toByteArray();
}
/**
* 给二维码底部添加文字
* @param data 二维码的字节数据
* @param text 底部文字
* @param fontName 字体名
* @param fontStyle 字体样式
* @param color 字体颜色
* @param fontSize 字体大小
* @return 带文字二维码的byte数组
* @throws IOException
*/
public static byte[] addFontIMage(byte[] data, String text,String fontName,int fontStyle, Color color,
int fontSize) throws IOException {
//data图片数据加载进内存
BufferedImage qrcodeImage = ImageIO.read(new ByteArrayInputStream(data));
int qrcodeWidth = qrcodeImage.getWidth(null);
int qrcodeHeight = qrcodeImage.getHeight(null);
Graphics2D graphics = qrcodeImage.createGraphics();
Font font = new Font(fontName, fontStyle, fontSize);
// 文字在图片中的坐标,这里设置在中间
FontMetrics metrics = graphics.getFontMetrics(font);
int startX = (qrcodeWidth - metrics.stringWidth(text)) / 2;
int startY = qrcodeHeight - 10;
graphics.setColor(color);
graphics.setFont(font);
graphics.drawString(text, startX, startY);
graphics.dispose();
// 带文字二维码返回
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ImageIO.write(qrcodeImage, FORMAT_NAME, bos);
return bos.toByteArray();
}
public static void main(String[] args) throws Exception {
File logoFile = new File("E:/java/logo.jpg");
byte[] data = QRCodeUtil.getQRCodeImage("发送端sadds12312", 550, 550);
data = QRCodeUtil.addLogoImage(data,logoFile,true);
// 内存二维码byte数据输出到磁盘
// 带logo二维码
FileOutputStream outputStream = new FileOutputStream("E:/java/as1234logo.jpg");
outputStream.write(data);
outputStream.close();
//给logo二维码添加底部文字
data = QRCodeUtil.addFontIMage(data, "二维码底部文字说明","宋体",Font.PLAIN,Color.BLUE,30);
outputStream = new FileOutputStream("E:/java/as1234logotext.jpg");
outputStream.write(data);
outputStream.close();
// 解析二维码
String resultStr = QRCodeUtil.decodeQRCodeImage(new File("E:/java/as1234logotext.jpg"));
System.out.println(resultStr); // 发送端sadds12312
}
}
总结:
1)掌握ZXing核心类解析和生成二维码
MultiFormatWriter 类或QRCodeWriter类编码和解码来生成和解析二维码
MatrixToImageWriter 类将内存数据写出去或者使用ImageIO类写
2)掌握Java的核心类:Image,BufferedImage和ImageIO
参考文章:
利用ZXing工具生成二维码以及解析二维码
站在前辈的肩膀上,每天进步一点点
ends~