工具类:
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import javax.imageio.ImageIO;
import java.awt.BasicStroke;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Shape;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Hashtable;
import java.util.Objects;
/**
* 二维码生成工具类
* @author zql
* @createTime 2020-11-30 23:25:21
* @version 1.1
* @modifyLog 1.1 优化代码
*
*/
public class QrCodeEncodeUtil {
/**
* 生成二维码图片
* @author zql
* @createTime 2020-11-30 23:27:54
*
* @param content 二维码内容
* @param logoPath logo路径
* @param savePath 二维码保存路径
* @param qrCodeSize 二维码图片大小
* @param logoSize 二维码图片中的logo大小
* @throws Exception
*/
public static void encode(String content, String logoPath, String savePath, int qrCodeSize, int logoSize) throws Exception {
BufferedImage image;
if (Objects.nonNull(logoPath)) {
File logoFile = new File(logoPath);
if (logoFile.exists()) {
image = QrCodeEncodeUtil.createImage(content, qrCodeSize, logoFile, logoSize);
} else {
image = QrCodeEncodeUtil.createImage(content, qrCodeSize);
}
} else {
image = QrCodeEncodeUtil.createImage(content, qrCodeSize);
}
QrCodeEncodeUtil.mkdirs(savePath);
ImageIO.write(image, "JPG", new File(savePath));
}
/**
* 生成二维码图像缓存对象
* @author zql
* @createTime 2020-11-30 23:29:16
*
* @param content 二维码内容
* @param logoPath logo路径
* @param qrCodeSize 二维码图片大小
* @param logoSize 二维码图片中的logo大小
* @return BufferedImage
* @throws Exception
*/
public static BufferedImage encode(String content, String logoPath, int qrCodeSize, int logoSize) throws Exception {
BufferedImage image;
if (Objects.nonNull(logoPath)) {
File logoFile = new File(logoPath);
if (logoFile.exists()) {
image = QrCodeEncodeUtil.createImage(content, qrCodeSize, logoFile, logoSize);
} else {
image = QrCodeEncodeUtil.createImage(content, qrCodeSize);
}
} else {
image = QrCodeEncodeUtil.createImage(content, qrCodeSize);
}
return image;
}
/**
* 生成二维码图片
* @author zql
* @createTime 2020-11-30 23:30:06
*
* @param content 二维码内容
* @param savePath 二维码保存路径
* @param qrCodeSize 二维码图片大小
* @throws Exception
*/
public static void encode(String content, String savePath, int qrCodeSize) throws Exception {
QrCodeEncodeUtil.encode(content, null, savePath, qrCodeSize, 0);
}
/**
* 生成二维码图像缓存对象
* @author zql
* @createTime 2020-11-30 23:30:27
*
* @param content 二维码内容
* @param qrCodeSize 二维码图片大小
* @return BufferedImage
* @throws Exception
*/
public static BufferedImage encode(String content, int qrCodeSize) throws Exception {
return QrCodeEncodeUtil.encode(content, null, qrCodeSize, 0);
}
/**
* 将BufferedImage转换为InputStream
* @author zql
* @createTime 2021-01-02 11:39:57
*
* @param image
* @param imgType 图片类型
* @return InputStream
* @throws IOException
*/
public static InputStream bufferedImageToInputStream(BufferedImage image, String imgType) throws IOException {
ByteArrayOutputStream os = new ByteArrayOutputStream();
try {
ImageIO.write(image, imgType, os);
InputStream input = new ByteArrayInputStream(os.toByteArray());
return input;
} catch (IOException e) {
throw e;
}
}
/**
* 创建有logo的二维码图像缓存对象
* @author zql
* @createTime 2020-11-30 23:25:30
*
* @param content 二维码内容
* @param qrCodeSize 二维码图片大小
* @param logoFile logo文件对象
* @param logoSize logo在二维码中的大小
* @return BufferedImage
* @throws Exception
*/
private static BufferedImage createImage(String content, int qrCodeSize, File logoFile, int logoSize) throws Exception {
// 二维码图片大小不能小于logo图片大小的3倍,否则生成二维码会出现异常,导致二维码无效
if (qrCodeSize < logoSize * 3) {
logoSize = qrCodeSize / 3;
}
Hashtable<EncodeHintType, Object> ht = new Hashtable<EncodeHintType, Object>();
ht.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
ht.put(EncodeHintType.CHARACTER_SET, "UTF-8");
// 二维码的边界,0为无边界
ht.put(EncodeHintType.MARGIN, 0);
// UTF-8编码长度不能超过1273个字节,全是数字字符的话不超过3057
// 因汉字占了3个字节,所以最多能有424个汉字
BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, qrCodeSize, qrCodeSize, ht);
BufferedImage image = new BufferedImage(qrCodeSize, qrCodeSize, BufferedImage.TYPE_INT_RGB);
for (int x = 0; x < qrCodeSize; x++) {
// 如果想要的二维码不是正方形,这里的qrCodeSize请使用二维码图像的高度
for (int y = 0; y < qrCodeSize; y++) {
image.setRGB(x, y, bitMatrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF);
}
}
// 插入logo
QrCodeEncodeUtil.insertImage(image, logoFile, logoSize);
return image;
}
/**
* 往二维码图片插入logo
* @author zql
* @createTime 2020-11-30 23:26:12
*
* @param source 二维码图像缓存对象
* @param file logo的文件对象
* @param logoSize logo的尺寸
* @throws Exception
*/
private static void insertImage(BufferedImage source, File file, int logoSize) throws Exception {
Image src = ImageIO.read(file);
int width = src.getWidth(null);
int height = src.getHeight(null);
// 对logo图片进行压缩
width = width > logoSize ? logoSize : width;
height = height > logoSize ? logoSize : height;
Image image = src.getScaledInstance(width, height, Image.SCALE_SMOOTH);
BufferedImage tag = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics g = tag.getGraphics();
// 绘制缩小后的图
g.drawImage(image, 0, 0, null);
g.dispose();
src = image;
// 因为得到的二维码是正方形,因此只需要获取宽度或高度即可
int qrCodeSize = source.getWidth();
// 中间插入LOGO
Graphics2D graph = source.createGraphics();
int x = (qrCodeSize - logoSize) / 2;
int y = (qrCodeSize - logoSize) / 2;
graph.drawImage(src, x, y, logoSize, logoSize, null);
/*
* @param x 新构造的圆矩形的x坐标
* @param y 新构造的圆矩形的y坐标
* @param w 新构造的圆矩形的宽度
* @param h 新构造的圆矩形的高度
* @param arcw 圆弧的宽度,用来四舍五入新建的圆矩形的角
* @param arch 圆弧的高度,用来四舍五入新建的圆矩形的角
* java.awt.geom.RoundRectangle2D.Float.Float(float x, float y, float w, float h, float arcw, float arch)
*/
// 外边画个圆距形,让logo不显得那么生硬
Shape shape = new RoundRectangle2D.Float(x, y, logoSize, logoSize, logoSize / 10, logoSize / 10);
graph.setStroke(new BasicStroke(3f));
graph.draw(shape);
graph.dispose();
}
/**
* 创建二维码图像缓存对象
* @author zql
* @createTime 2020-11-30 23:26:58
*
* @param content 二维码内容
* @param qrCodeSize 二维码图片大小
* @return
* @throws Exception
*/
private static BufferedImage createImage(String content, int qrCodeSize) throws Exception {
Hashtable<EncodeHintType, Object> ht = new Hashtable<EncodeHintType, Object>();
ht.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
ht.put(EncodeHintType.CHARACTER_SET, "UTF-8");
ht.put(EncodeHintType.MARGIN, 0);
// UTF-8编码长度不能超过1273个字节,全是数字字符的话不超过3057
// 因汉字占了3个字节,所以最多能有424个汉字
BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, qrCodeSize, qrCodeSize, ht);
BufferedImage image = new BufferedImage(qrCodeSize, qrCodeSize, BufferedImage.TYPE_INT_RGB);
for (int x = 0; x < qrCodeSize; x++) {
for (int y = 0; y < qrCodeSize; y++) {
image.setRGB(x, y, bitMatrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF);
}
}
return image;
}
/**
* 保存二维码图片自动创建不存在的文件夹
* @author zql
* @createTime 2020-11-30 23:27:29
*
* @param savePath
*/
private static void mkdirs(String savePath) {
File file = new File(savePath);
// 当文件夹不存在时,自动创建多层目录
if (!file.exists() && !file.isDirectory()) {
// mkdirs和mkdir的区别在于mkdir如果父目录不存在则会抛出异常
file.mkdirs();
}
}
}
测试类:
import org.junit.Test;
import java.awt.image.BufferedImage;
import java.io.InputStream;
/**
* 二维码生成工具测试类
* @author zql
* @createTime 2020-11-30 23:25:21
* @version 1.1
* @modifyLog 1.1 优化代码
*
*/
public class QrCodeEncodeUtilTest {
@Test
public void encode() throws Exception {
// 存放在二维码中的内容
String text = "我是二维码";
String savePath = "E:\\image\\test1.jpg";
// 生成二维码
QrCodeEncodeUtil.encode(text, savePath,300);
}
@Test
public void encode2() throws Exception {
// 存放在二维码中的内容
String text = "我是有logo的二维码";
// 嵌入二维码的logo图片路径
String logoPath = "E:\\image\\logo.jpg";
// 保存的二维码的路径及名称
String savePath = "E:\\image\\test2.jpg";
// 生成有logo的二维码
QrCodeEncodeUtil.encode(text, logoPath, savePath, 400, 100);
}
@Test
public void encodeBufferedImage() throws Exception {
// 存放在二维码中的内容
String text = "我是二维码2";
String savePath = "E:\\image\\test3.png";
BufferedImage image = QrCodeEncodeUtil.encode(text, 300);
InputStream inputStream = QrCodeEncodeUtil.bufferedImageToInputStream(image, "png");
// FileUtil:https://blog.csdn.net/mr_zql/article/details/98671993
new FileUtil().writeToLocal(savePath, inputStream);
}
@Test
public void encodeBufferedImage2() throws Exception {
// 存放在二维码中的内容
String text = "我是有logo的二维码2";
// 嵌入二维码的logo图片路径
String logoPath = "E:\\image\\logo.jpg";
// 保存的二维码的路径及名称
String savePath = "E:\\image\\test4.jpg";
BufferedImage image = QrCodeEncodeUtil.encode(text, logoPath, 100, 300);
InputStream inputStream = QrCodeEncodeUtil.bufferedImageToInputStream(image, "jpg");
new FileUtil().writeToLocal(savePath, inputStream);
}
}
普通项目需要引入的包
core-3.4.0.jar
maven项目依赖
<!-- 二维码 -->
<!-- https://mvnrepository.com/artifact/com.google.zxing/core -->
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>core</artifactId>
<version>3.4.0</version>
</dependency>