效果图:
背景图:
直接看代码和代码说明:
方法drawQr() 为绘制核心,仅绘制出图上的二维码
方法createQr() 包含 读取背景图和 调用drawQr() 。绘制出完整的带有背景图的二维码
drawQr()方法参数说明:
* @param content 二维码内容
* @param qrSize 二维码大小
* @param logoBarry 二维码logo字节流
* @param qrMaDianColor 二维码码点颜色
* @param qrBgColor 二维码背景颜色
* @param bgImg 包裹二维码的背景图
* @param qrInBgImgSize 二维码占用背景图内部的大小的百分之多少,1-10之间
* @param qrInBgImgX 二维码在背景图内部的位置X坐标
* @param qrInBgImgY 二维码在背景图内部的位置Y坐标
二维码绘制保证了logo在二维码中心的位置,且大小仅是占用二维码的20%
码点的绘制避开了logo区域的10个像素点。可以保证二维码在中间的美观性
ErrorCorrectionLevel.M 是错误等级,可自行修改。
二维码的码点形状绘制,敬请期待...
码点绘制开发好后保证全部免费开源
import cn.hutool.core.img.ImgUtil;
import cn.hutool.core.io.FileUtil;
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 lombok.extern.log4j.Log4j2;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriter;
import javax.imageio.stream.FileImageOutputStream;
import java.awt.*;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
* <p>
* 二维码生成工具
* </p>
*
* @author Garcia
* @since 2023-05-31
*/
@Log4j2
public class QrCodeUtil {
/**
* 使用示例
*/
private static void useExample() throws IOException {
BufferedImage schoolLogo = ImgUtil.read(FileUtil.file("C:\\Users\\Garcia\\Desktop\\test\\234.png"));
ByteArrayOutputStream baos = new ByteArrayOutputStream(); // 创建字节输出流
DataOutputStream dos = new DataOutputStream(baos); // 创建数据输出流,并关联到字节输出流上
ImageIO.write(schoolLogo, "png", dos);
byte[] logo = baos.toByteArray();
byte[] bytes = QrCodeUtil.generateQr("www.baidu.com",logo);
QrCodeUtil.generateQrPng("www.baidu.com",logo,"C:\\Users\\Garcia\\Desktop\\test\\qq.png");
}
/**
* 直接生成png到指定路径
* @param content
* @param logo
* @param outPath
*/
public static void generateQrPng(String content, byte[] logo,String outPath){
try {
BufferedImage image = createQr(content,logo);
Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName("png");
ImageWriter writer = writers.next();
ImgUtil.write(image,writer,new FileImageOutputStream(new File(outPath)),1);
} catch (Exception e) {
log.error("创建二维码异常",e);
}
}
/**
* 返回流字节
* @param content
* @param logo
* @return
*/
public static byte[] generateQr(String content, byte[] logo){
try {
Image image = createQr(content,logo);
return ImgUtil.toBytes(image,"PNG");
} catch (Exception e) {
log.error("创建二维码异常",e);
}
return null;
}
private static BufferedImage createQr(String content,byte[] logo) throws Exception {
//读取背景图
BufferedImage bgImg = ImgUtil.read(FileUtil.file("C:\\Users\\Garcia\\Desktop\\test\\bg.png"));
BufferedImage originalImage = drawQr(content,
1000,
logo,
Color.white,
new Color(0,105,183),
bgImg,5,-1,213);
return originalImage;
}
/**
* 二维码绘制
* @param content
* @param qrSize
* @param logoBarry
* @param qrMaDianColor
* @param qrBgColor
* @param bgImg
* @param qrInBgImgSize
* @param qrInBgImgX
* @param qrInBgImgY
* @return
* @throws Exception
*/
private static BufferedImage drawQr(String content,
int qrSize ,
byte[] logoBarry,
Color qrMaDianColor,
Color qrBgColor,
BufferedImage bgImg,
int qrInBgImgSize,
int qrInBgImgX,
int qrInBgImgY) throws Exception {
int logoRadius = 10;
float cornerRadius = 50.525f;
int prohibitArea = 15;
Map<EncodeHintType, Object> hints = new HashMap<>();
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
hints.put(EncodeHintType.MARGIN, 1); //二维码边界距离
BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, qrSize, qrSize, hints);
int matrixWidth = bitMatrix.getWidth();
int matrixHeight = bitMatrix.getHeight();
BufferedImage image = new BufferedImage(matrixWidth, matrixHeight, BufferedImage.TYPE_INT_ARGB);
if (logoBarry!=null&&logoBarry.length>0){
BufferedImage logo = ImageIO.read(new ByteArrayInputStream(logoBarry));
BufferedImage borderImage = new BufferedImage(logo.getWidth(), logo.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g2dff1 = borderImage.createGraphics();
g2dff1.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2dff1.setColor(Color.WHITE);
g2dff1.fill(new RoundRectangle2D.Float(0, 0, logo.getWidth(), logo.getHeight(), logoRadius * 2, logoRadius * 2));
g2dff1.setComposite(AlphaComposite.SrcIn);
g2dff1.drawImage(logo, 0, 0, null);
g2dff1.dispose();
//计算放置logo到二维码中的大小
int widthLogo = image.getWidth()*2/10;
int heightLogo = image.getHeight()*2/10;
//计算放置logo到二维码中的位置
int leftX = (qrSize - widthLogo) / 2;
int leftY = (qrSize - heightLogo) / 2;
//logo右下角坐标
int rightX = leftX + widthLogo;
int rightY = leftY + heightLogo;
for (int mx = 0; mx < matrixWidth; mx++) {
for (int my = 0; my < matrixHeight; my++) {
//logo区域禁止画码点
if (mx>=leftX-prohibitArea&&mx<=rightX+prohibitArea&&my>=leftY-prohibitArea&&my<=rightY+prohibitArea){
image.setRGB(mx, my, qrBgColor.getRGB());
continue;
}
if (!bitMatrix.get(mx, my)){
image.setRGB(mx, my, qrBgColor.getRGB());
continue;
}
//码点样式,有机会再修改
image.setRGB(mx, my, qrMaDianColor.getRGB());
}
}
//放置logo到二维码
Graphics2D graph = image.createGraphics();
graph.drawImage(borderImage, leftX, leftY, widthLogo, heightLogo, null); //将 Logo 插入到二维码中间
graph.dispose();
}else {
for (int mx = 0; mx < matrixWidth; mx++) {
for (int my = 0; my < matrixHeight; my++) {
image.setRGB(mx, my, bitMatrix.get(mx, my)?qrMaDianColor.getRGB():qrBgColor.getRGB());
}
}
}
//将二维码绘制为圆角矩形
BufferedImage roundedCornerQRCode = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g2dff = roundedCornerQRCode.createGraphics();
g2dff.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2dff.setColor(Color.white);
g2dff.fill(new RoundRectangle2D.Float(0, 0, image.getWidth(), image.getHeight(), cornerRadius * 2, cornerRadius * 2));
g2dff.setComposite(AlphaComposite.SrcIn);
g2dff.drawImage(image, 0, 0, null);
g2dff.dispose();
//背景
int emw = Math.min(roundedCornerQRCode.getWidth(null), bgImg.getWidth() * qrInBgImgSize / 10),
emh = roundedCornerQRCode.getHeight(null)>bgImg.getWidth()*qrInBgImgSize/10?(bgImg.getWidth()*qrInBgImgSize/10):roundedCornerQRCode.getWidth(null);
int X=qrInBgImgX,Y=qrInBgImgY;
if (qrInBgImgY==-1){
//计算放置二维码到背景中的位置
Y = ( bgImg.getHeight() - emh) / 2;
}
if (qrInBgImgX==-1){
//计算放置二维码到背景中的位置
X = ( bgImg.getWidth() - emw) / 2;
}
Graphics2D bg2d = bgImg.createGraphics();
bg2d.drawImage(roundedCornerQRCode, X, Y, emw, emh, null);
bg2d.dispose();
return bgImg;
}
}