【POM】文件
<dependency>
<groupId>com.google.zxinggroupId>
<artifactId>coreartifactId>
<version>3.3.3version>
dependency>
<dependency>
<groupId>com.google.zxinggroupId>
<artifactId>javaseartifactId>
<version>3.3.3version>
dependency>
生成二维码工具类
/**
* 二维码工具
* @Author:debug (SteadyJack)
* @Link: weixin-> debug0868 qq-> 1948831260
* @Date: 2020/11/16 22:38
**/
public class QRCodeUtil {
private static final Logger log= LoggerFactory.getLogger(QRCodeUtil.class);
//CODE_WIDTH:二维码宽度,单位像素
private static final int CODE_WIDTH = 400;
//CODE_HEIGHT:二维码高度,单位像素
private static final int CODE_HEIGHT = 400;
//FRONT_COLOR:二维码前景色,0x000000 表示黑色
private static final int FRONT_COLOR = 0x000000;
//BACKGROUND_COLOR:二维码背景色,0xFFFFFF 表示白色
//演示用 16 进制表示,和前端页面 CSS 的取色是一样的,注意前后景颜色应该对比明显,如常见的黑白
private static final int BACKGROUND_COLOR = 0xFFFFFF;
public static void createCodeToFile(String content, File codeImgFileSaveDir, String fileName) {
try {
if (StringUtils.isBlank(content) || StringUtils.isBlank(fileName)) {
return;
}
content = content.trim();
if (codeImgFileSaveDir==null || codeImgFileSaveDir.isFile()) {
//二维码图片存在目录为空,默认放在桌面...
codeImgFileSaveDir = FileSystemView.getFileSystemView().getHomeDirectory();
}
if (!codeImgFileSaveDir.exists()) {
//二维码图片存在目录不存在,开始创建...
codeImgFileSaveDir.mkdirs();
}
//核心代码-生成二维码
BufferedImage bufferedImage = getBufferedImage(content);
File codeImgFile = new File(codeImgFileSaveDir, fileName);
ImageIO.write(bufferedImage, "png", codeImgFile);
log.info("二维码图片生成成功:" + codeImgFile.getPath());
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 生成二维码并输出到输出流, 通常用于输出到网页上进行显示,输出到网页与输出到磁盘上的文件中,区别在于最后一句 ImageIO.write
* write(RenderedImage im,String formatName,File output):写到文件中
* write(RenderedImage im,String formatName,OutputStream output):输出到输出流中
* @param content :二维码内容
* @param outputStream :输出流,比如 HttpServletResponse 的 getOutputStream
*/
public static void createCodeToOutputStream(String content, OutputStream outputStream) {
try {
if (StringUtils.isBlank(content)) {
return;
}
content = content.trim();
//核心代码-生成二维码
BufferedImage bufferedImage = getBufferedImage(content);
//区别就是这一句,输出到输出流中,如果第三个参数是 File,则输出到文件中
ImageIO.write(bufferedImage, "png", outputStream);
log.info("二维码图片生成到输出流成功...");
} catch (Exception e) {
e.printStackTrace();
}
}
//核心代码-生成二维码
private static BufferedImage getBufferedImage(String content) throws WriterException {
//com.google.zxing.EncodeHintType:编码提示类型,枚举类型
Map<EncodeHintType, Object> hints = new HashMap();
//EncodeHintType.CHARACTER_SET:设置字符编码类型
hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
//EncodeHintType.ERROR_CORRECTION:设置误差校正
//ErrorCorrectionLevel:误差校正等级,L = ~7% correction、M = ~15% correction、Q = ~25% correction、H = ~30% correction
//不设置时,默认为 L 等级,等级不一样,生成的图案不同,但扫描的结果是一样的
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
//EncodeHintType.MARGIN:设置二维码边距,单位像素,值越小,二维码距离四周越近
hints.put(EncodeHintType.MARGIN, 1);
MultiFormatWriter multiFormatWriter = new MultiFormatWriter();
BitMatrix bitMatrix = multiFormatWriter.encode(content, BarcodeFormat.QR_CODE, CODE_WIDTH, CODE_HEIGHT, hints);
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.setRGB(x, y, bitMatrix.get(x, y) ? FRONT_COLOR : BACKGROUND_COLOR);
}
}
return bufferedImage;
}
// 测试
public static void main(String[] args) {
String url = "https://pc.hkxt.tbkjkf.com?id=1411258341581467649&hostPlaceId=63bbe419ca9ce362e80d1a2d";
String path = "D:\\";
try {
final String fileName="my_qr_code_01.png";
// 生成二维码
QRCodeUtil.createCodeToFile(url,new File(path),fileName);
}catch (Exception e){
}
}
}
【图片合成】
结合二维码生成工具类,先将URL转换成二维码的流,再将二维码的流和背景图片的流结合生成新的图片流。可将流返回到前台界面下载,也可直接保存到本地。
/**
* 图片处理工具类
*
* @author ruoyi
*/
public class ImageUtils
{
private static final Logger log = LoggerFactory.getLogger(ImageUtils.class);
public static byte[] getImage(String imagePath)
{
InputStream is = getFile(imagePath);
try
{
return IOUtils.toByteArray(is);
}
catch (Exception e)
{
log.error("图片加载异常 {}", e);
return null;
}
finally
{
IOUtils.closeQuietly(is);
}
}
public static InputStream getFile(String imagePath)
{
try
{
byte[] result = readFile(imagePath);
result = Arrays.copyOf(result, result.length);
return new ByteArrayInputStream(result);
}
catch (Exception e)
{
log.error("获取图片异常 {}", e);
}
return null;
}
/**
* 读取文件为字节数据
*
* @param url 地址
* @return 字节数据
*/
public static byte[] readFile(String url)
{
InputStream in = null;
try
{
if (url.startsWith("http"))
{
// 网络地址
URL urlObj = new URL(url);
URLConnection urlConnection = urlObj.openConnection();
urlConnection.setConnectTimeout(30 * 1000);
urlConnection.setReadTimeout(60 * 1000);
urlConnection.setDoInput(true);
in = urlConnection.getInputStream();
}
else
{
// 本机地址
String localPath = RuoYiConfig.getProfile();
String downloadPath = localPath + StringUtils.substringAfter(url, Constants.RESOURCE_PREFIX);
in = new FileInputStream(downloadPath);
}
return IOUtils.toByteArray(in);
}
catch (Exception e)
{
log.error("获取文件路径异常 {}", e);
return null;
}
finally
{
IOUtils.closeQuietly(in);
}
}
/**
* 合成图片
*/
public static void composePic(String url) {
try {
//获取背景图片
ResourceLoader resourceLoader = new DefaultResourceLoader();
Resource resource = resourceLoader.getResource("templates/newBack.jpg");
InputStream bakStream = resource.getInputStream();
//获取二维码
ByteArrayOutputStream qrCodeOps = new ByteArrayOutputStream();
QRCodeUtil.createCodeToOutputStream(url, qrCodeOps);
ByteArrayInputStream qrCodeStream = new ByteArrayInputStream(qrCodeOps.toByteArray());
//合成文件路径
String path = "D:\\Recv Files\\gen.jpg";
//---------------------------------合成图片步骤-----------------------------
//读取背景图片
BufferedImage bg = ImageIO.read(bakStream);
//背景图片的高
int height = bg.getHeight();
//背景图片的宽
int width = bg.getWidth();
//读取二维码图片
BufferedImage qcCode = ImageIO.read(qrCodeStream);
//二维码图片的高
int pcheight = qcCode.getHeight();
//二维码图片的宽
int pcwidth = qcCode.getWidth();
//创建画布
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
//生成画笔 开启画图
Graphics g = img.getGraphics();
//绘制背景图片
g.drawImage(bg.getScaledInstance(width, height, Image.SCALE_DEFAULT), 0, 0, null);
//绘制二维码图片 定位到背景图的右下角
g.drawImage(qcCode.getScaledInstance(pcwidth + 220, pcheight + 220, Image.SCALE_DEFAULT), width - 840, height - 1090, null);
//关掉画笔
g.dispose();
ImageIO.write(img, "jpg", new File(path));
log.info("合成图片成功,路径:" + path);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
*
* @param qrImgPath 带有文件名的完成路径 例:(D:/ruoyi/uploadPath/QRCode/123.png)
* @param qrUrl 二维码url
* @return
*/
public static BufferedImage composeAndSavePic(String qrImgPath,String qrUrl,String placeName) {
ImageUtils imageUtils = new ImageUtils();
BufferedImage img = imageUtils.drawImg(qrUrl,placeName);
try{
ImageIO.write(img, "png", new File(qrImgPath));
}catch(Exception e){
log.info("合成后的二维码存入本地失败:" + e);
}
return img;
}
public static BufferedImage composeButNoSave(String qrUrl,String placeName) {
ImageUtils imageUtils = new ImageUtils();
return imageUtils.drawImg(qrUrl,placeName);
}
public static BufferedImage downloadQRCode(String filePath,String qrImgPath,String qrUrl,String placeName){
BufferedImage img = null;
try{
File imgFile = new File(qrImgPath);
File file = new File(filePath);
/**
* 如果图片存在,直接返回
* 如果不存在,先看文件夹是否存在
* 文件夹存在,合成图片后保存到服务器并返回流
* 文件夹不存在,创建文件夹,合成图片后保存到服务器,并返回流
* 文件夹创建失败只返回流
*/
if(!imgFile.exists()){
if(file.exists()){
img = composeAndSavePic(qrImgPath,qrUrl,placeName);
}else{
if(file.mkdirs()){
img = composeAndSavePic(qrImgPath,qrUrl,placeName);
}else{
img = composeButNoSave(qrUrl,placeName);
}
}
}else{
//存在,直接返回文件流
img = ImageIO.read(imgFile);
}
return img;
}catch(Exception e){
log.info("合成二维码失败:" + e);
return img;
}
}
public BufferedImage drawImg(String qrUrl,String placeName){
try{
//获取背景图片
ResourceLoader resourceLoader = new DefaultResourceLoader();
Resource resource = resourceLoader.getResource("templates/newBack.jpg");
InputStream bakStream = resource.getInputStream();
//获取二维码
ByteArrayOutputStream qrCodeOps = new ByteArrayOutputStream();
QRCodeUtil.createCodeToOutputStream(qrUrl, qrCodeOps);
ByteArrayInputStream qrCodeStream = new ByteArrayInputStream(qrCodeOps.toByteArray());
BufferedImage bg = ImageIO.read(bakStream);
//背景图片的高
int height = bg.getHeight();
//背景图片的宽
int width = bg.getWidth();
//读取二维码图片
BufferedImage qcCode = ImageIO.read(qrCodeStream);
//二维码图片的高
int pcheight = qcCode.getHeight();
//二维码图片的宽
int pcwidth = qcCode.getWidth();
int placeWith = width;
//计算文字边距,保持文字居中
if(!StringUtils.isEmpty(placeName)){
int strlen = placeName.length();
System.out.println(strlen);
if(strlen%2 == 0 && strlen >= 2){
placeWith = placeWith - 574 - 23*(strlen-2);
}else{
placeWith = placeWith - 550 - 23*(strlen-1);
}
}
//创建画布
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
//生成画笔 开启画图
Graphics g = img.getGraphics();
//绘制背景图片
g.drawImage(bg.getScaledInstance(width, height, Image.SCALE_DEFAULT), 0, 0, null);
//绘制二维码图片 定位到背景图的右下角
g.drawImage(qcCode.getScaledInstance(pcwidth + 220, pcheight + 220, Image.SCALE_DEFAULT), width - 840, height - 1090, null);
//添加文字
Font font = new Font("微软雅黑", Font.BOLD, 60);// 添加字体的属性设置
Font placefont = new Font("微软雅黑", Font.BOLD, 45);// 添加字体的属性设置
g.setFont(font);
g.setColor(Color.white);
//宽减得越多,离左边越近 高减得越多,离上边越近
g.drawString("要添加的文字",width-710, height-350);
g.setFont(placefont);
g.drawString(placeName,placeWith, height-280);
// g.drawString("西",placeWith, height-200);
//关掉画笔
g.dispose();
return img;
}catch(Exception e){
log.info("二维码合成失败:" + e);
return null;
}
}
public static void main(String[] args) {
composePic("https://pc.hkxt.tbkjkf.com?id=1411258341581467649");
}
}
【调整字间距】
Map<TextAttribute, Object> attributes = new HashMap<TextAttribute, Object>();
attributes.put(TextAttribute.TRACKING, 0.3);
Font font = new Font("微软雅黑", Font.BOLD, 75);// 添加字体的属性设置
Font font2 = font.deriveFont(attributes);
//生成画笔 开启画图
Graphics g = img.getGraphics();
g.setFont(font2);
g.setColor(Color.black);
g.drawString("辽宁省公安厅",width-820, height-430);
【Controller层】
获取合成的图片流返给界面下载并保存到本地
@PostMapping("/downloadQR")
public void downloadQRCode(HttpServletResponse response,SysPlace place){
String tenantId = "12341234"
String filePath = RuoYiConfig.getProfile() + "/QRCode/";
String qrImgName = tenantId + "_" + place.getId() + ".png";
String qrImgPath = filePath + qrImgName;
String qrUrl = "https://test.com?id=" + tenantId + "&hostPlaceId=" + place.getId();
//通过ID获取对象
SysPlace sp = sysPlaceService.selectPlaceById(place.getId());
try{
BufferedImage img = ImageUtils.downloadQRCode(filePath,qrImgPath,qrUrl,sp.getPlaceName());
ImageIO.write(img, "png", response.getOutputStream());
}catch(Exception e){
log.info("合成二维码失败:" + e);
}
}