效果
准备:
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>javase</artifactId>
<version>3.4.0</version>
</dependency>
package com.muzhongyun.sannong.common.utils;
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 org.springframework.util.StringUtils;
import javax.imageio.ImageIO;
import javax.swing.filechooser.FileSystemView;
import java.awt.*;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
public class CodeUtils {
/**
* CODE_WIDTH:二维码宽度,单位像素
* CODE_HEIGHT:二维码高度,单位像素
* FRONT_COLOR:二维码前景色,0x000000 表示黑色
* BACKGROUND_COLOR:二维码背景色,0xFFFFFF 表示白色
* 演示用 16 进制表示,和前端页面 CSS 的取色是一样的,注意前后景颜色应该对比明显,如常见的黑白
*/
private static final int CODE_WIDTH = 400;
private static final int CODE_HEIGHT = 400;
private static final int FRONT_COLOR = 0x000000;
private static final int BACKGROUND_COLOR = 0xFFFFFF;
public static void main(String[] args) {
String codeContent1 = "www.baidu.com";
File file = new File("D:/codes");
String fileName = "z" + System.currentTimeMillis() + ".png";
createCodeToFile(codeContent1, file, fileName, "只要我们可以好好学习java,我们一定可以成为大神!");
}
/**
* 生成二维码 并 保存为图片
*/
/**
* @param codeContent :二维码参数内容,如果是一个网页地址,如 https://www.baidu.com/ 则 微信扫一扫会直接进入此地址
* 如果是一些参数,如 1541656080837,则微信扫一扫会直接回显这些参数值
* @param codeSaveUrl :二维码图片保存的目录,如 D:/codes
* @param fileName :二维码图片文件名称,带格式,如 123.png
*/
public static void createCodeToFile(String codeContent, File codeSaveUrl, String fileName, String note) {
try {
//判断内容是否为空
if (!StringUtils.isEmpty(codeContent)) {
System.out.println("二维码内容为空,请输入内容.....");
return;
}
codeContent = codeContent.trim();//去除内容空格
//如果地址为空,那么就保存到桌面
if (codeSaveUrl == null || codeSaveUrl.isFile()) {
codeSaveUrl = FileSystemView.getFileSystemView().getHomeDirectory();
}
if (!codeSaveUrl.exists()) {
codeSaveUrl.mkdirs();
System.out.println("二维码图片目录不存在,开始创建...");
}
if (StringUtils.isEmpty(fileName)) {
fileName = new Date().getTime() + ".png";
System.out.println("二维码图片文件名为空,随机生成 png 格式图片...");
}
Map<EncodeHintType, Object> hints = new HashMap();
//设置字符编码类型
hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
/**设置误差校正
* L = ~7% correction、M = ~15% correction、Q = ~25% correction、H = ~30%
* 等级不一样,生成的图片也会不一样
*/
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
//设置二维码边距,单位像素,值越小,二维码距离四周越近
hints.put(EncodeHintType.MARGIN, 1);
/**
* MultiFormatWriter:多格式写入,这是一个工厂类,里面重载了两个 encode 方法,用于写入条形码或二维码
* encode(String contents,BarcodeFormat format,int width, int height,Map<EncodeHintType,?> hints)
* contents:条形码/二维码内容
* format:编码类型,如 条形码,二维码 等
* width:码的宽度
* height:码的高度
* hints:码内容的编码类型
* BarcodeFormat:枚举该程序包已知的条形码格式,即创建何种码,如 1 维的条形码,2 维的二维码 等
* BitMatrix:位(比特)矩阵或叫2D矩阵,也就是需要的二维码
*/
MultiFormatWriter multiFormatWriter = new MultiFormatWriter();
BitMatrix bitMatrix = multiFormatWriter.encode(codeContent, BarcodeFormat.QR_CODE, CODE_WIDTH, CODE_HEIGHT, hints);
//BufferedImage x 横坐标 y纵坐标
BufferedImage bufferedImage = new BufferedImage(CODE_WIDTH, CODE_HEIGHT, BufferedImage.TYPE_INT_BGR);
for (int x = 0; x < CODE_WIDTH; x++) {
for (int y = 0; y < CODE_HEIGHT; y++) {
//bufferedImage中的x是横坐标 y是纵坐标
//BitMatrix的get(int x, int y) 获取比特矩阵内容,指定位置有值,则返回true,将其设置为前景色,否则设置为背景色
bufferedImage.setRGB(x, y, bitMatrix.get(x, y) ? FRONT_COLOR : BACKGROUND_COLOR);
}
}
/**给二维码添加logo*/
LogoMatrix(bufferedImage, "D:/codes/22.png");
/**保存二维码图片文件*/
File codeImgFile = new File(codeSaveUrl, fileName);
ImageIO.write(bufferedImage, "png", codeImgFile);
System.out.println("二维码图片生成成功:" + codeImgFile.getPath());
// 自定义文本描述
if (!StringUtils.isEmpty(note)) {
// 新的图片,把带logo的二维码下面加上文字
BufferedImage outImage = new BufferedImage(400, 445, BufferedImage.TYPE_4BYTE_ABGR);
Graphics2D outg = outImage.createGraphics();
// 画二维码到新的面板
outg.drawImage(bufferedImage, 0, 0, bufferedImage.getWidth(), bufferedImage.getHeight(), null);
// 画文字到新的面板
outg.setColor(Color.BLACK);
outg.setFont(new Font("楷体", Font.BOLD, 30)); // 字体、字型、字号
int strWidth = outg.getFontMetrics().stringWidth(note);
Integer height = 400;
if (strWidth > 399) {
//长度过长就截取前面部分
// 长度过长就换行
String note1 = note.substring(0, note.length() / 2);
String note2 = note.substring(note.length() / 2, note.length());
int strWidth1 = outg.getFontMetrics().stringWidth(note1);
int strWidth2 = outg.getFontMetrics().stringWidth(note2);
outg.drawString(note1, 200 - strWidth1 / 2, height + (outImage.getHeight() - height) / 2 + 12);
BufferedImage outImage2 = new BufferedImage(400, 485, BufferedImage.TYPE_4BYTE_ABGR);
Graphics2D outg2 = outImage2.createGraphics();
outg2.drawImage(outImage, 0, 0, outImage.getWidth(), outImage.getHeight(), null);
outg2.setColor(Color.BLACK);
outg2.setFont(new Font("宋体", Font.BOLD, 30)); // 字体、字型、字号
outg2.drawString(note2, 200 - strWidth2 / 2, outImage.getHeight() + (outImage2.getHeight() - outImage.getHeight()) / 2 + 5);
outg2.dispose();
outImage2.flush();
outImage = outImage2;
} else {
outg.drawString(note, 200 - strWidth / 2, height + (outImage.getHeight() - height) / 2 + 12); // 画文字
}
outg.dispose();
outImage.flush();
bufferedImage = outImage;
}
bufferedImage.flush();
/**
* 区别就是以一句,输出到输出流中,如果第三个参数是 File,则输出到文件中
*/
ImageIO.write(bufferedImage, "png", codeImgFile);
} catch (Exception e) {
e.printStackTrace();
}
}
public static BufferedImage LogoMatrix(BufferedImage matrixImage, String logoUrl) throws IOException {
/**
* 读取二维码图片,并构建绘图对象
*/
Graphics2D g2 = matrixImage.createGraphics();
int matrixWidth = matrixImage.getWidth();
int matrixHeigh = matrixImage.getHeight();
/**
* 读取Logo图片
*/
if (StringUtils.isEmpty(logoUrl)){
throw new IOException("logoUrl地址不能为空.....");
}
BufferedImage logo = ImageIO.read(new File(logoUrl));
//开始绘制图片
g2.drawImage(logo, matrixWidth / 5 * 2, matrixHeigh / 5 * 2, matrixWidth / 5, matrixHeigh / 5, null);//绘制
BasicStroke stroke = new BasicStroke(5, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
g2.setStroke(stroke);// 设置笔画对象
//指定弧度的圆角矩形
RoundRectangle2D.Float round = new RoundRectangle2D.Float(matrixWidth / 5 * 2, matrixHeigh / 5 * 2, matrixWidth / 5, matrixHeigh / 5, 20, 20);
g2.setColor(Color.white);
g2.draw(round);// 绘制圆弧矩形
//设置logo 有一道灰色边框
BasicStroke stroke2 = new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
g2.setStroke(stroke2);// 设置笔画对象
RoundRectangle2D.Float round2 = new RoundRectangle2D.Float(matrixWidth / 5 * 2 + 2, matrixHeigh / 5 * 2 + 2, matrixWidth / 5 - 4, matrixHeigh / 5 - 4, 20, 20);
g2.setColor(new Color(128, 128, 128));
g2.draw(round2);// 绘制圆弧矩形
g2.dispose();
matrixImage.flush();
return matrixImage;
}
}