【SpringBoot】生成二维码、在图片中嵌入二维码

背景

说明:本文章是介绍,在一张背景图片中嵌入生成的二维码和中文文字。

用处:比如活动分享二维码的时候,提供一张背景图,然后在背景图中嵌入二维码等。

注意:二维码和文字的位置需要你自行调整。

          

一、依赖引入

        <!-- https://mvnrepository.com/artifact/com.google.zxing/zxing-parent --><dependency><groupId>com.google.zxing</groupId><artifactId>zxing-parent</artifactId><version>3.5.0</version><type>pom</type></dependency>

二、创建工具类

生成工具类:ImageFileUtils

1、导入包

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import com.hvit.user.yst.request.CreateQrcodeRequest;
import org.apache.commons.lang3.StringUtils;import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

2、生成二维码

    // 生成二维码图片// text:二维码内容// size: 二维码尺寸private static BufferedImage generateQRCode(String text, int size) {Map<EncodeHintType, Object> hints = new HashMap<>();hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");try {QRCodeWriter writer = new QRCodeWriter();BitMatrix bitMatrix = writer.encode(text, BarcodeFormat.QR_CODE, size, size, hints);int width = bitMatrix.getWidth();int height = bitMatrix.getHeight();BufferedImage qrImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);Graphics2D graphics = qrImage.createGraphics();graphics.setColor(Color.WHITE);graphics.fillRect(0, 0, size, size);graphics.setColor(Color.BLACK);for (int x = 0; x < size; x++) {for (int y = 0; y < size; y++) {if (bitMatrix.get(x, y)) {graphics.fillRect(x, y, 1, 1);}}}// 渲染二维码Graphics2D graphics1 = qrImage.createGraphics();// 添加蓝色边框int borderSize = 10; // 边框大小Color myColor = new Color(0x19, 0x76, 0xFF); // 红色graphics1.setColor(myColor);graphics1.fillRect(0, 0, size, borderSize); // 上边框graphics1.fillRect(0, 0, borderSize, size); // 左边框graphics1.fillRect(size - borderSize, 0, borderSize, size); // 右边框graphics1.fillRect(0, size - borderSize, size, borderSize); // 下边框return qrImage;} catch (WriterException e) {e.printStackTrace();return null;}}

说明:以上生成的二维码是带有蓝色边框的二维码!如图:

                                                       

3、在背景图片上加入文字,并且居中支持\n换行

    // 在图片上添加图片private static void addImageToImage(BufferedImage baseImage, BufferedImage overlayImage, int x, int y) {Graphics2D g2d = baseImage.createGraphics();g2d.drawImage(overlayImage, x, y, null);g2d.dispose();}// 在图片上添加文本,支持手动换行,文本水平居中private static void addTextToImage(BufferedImage baseImage, String text, Font font, Color color, int maxWidth, int y) {Graphics2D g2d = baseImage.createGraphics();g2d.setFont(font);g2d.setColor(color);FontMetrics fm = g2d.getFontMetrics();int lineHeight = fm.getHeight();int currentY = y;String[] lines = text.split("\n");for (String line : lines) {int lineWidth = fm.stringWidth(line);int lineX = (maxWidth - lineWidth) / 2; // 居中g2d.drawString(line, lineX, currentY);currentY += lineHeight;}g2d.dispose();}

4、调用方法

 public static void main(String[] args) throws Exception {// 1. 读取原始图片BufferedImage image = null;try {image = ImageIO.read(new File("C:\\Users\\caozhen\\Desktop\\图片素材\\1.png")); // 替换成您的图片路径} catch (IOException e) {e.printStackTrace();}if (image == null) {System.err.println("无法读取图片");return;}// 2. 在图片上添加透明的二维码String qrText = "https://qhdm.mzt.zj.gov.cn:9090/szmp/#/wait?code=b20267e5298948a2bca5de8d4a8081a4&type=dz&timeStrap=1694503662057"; // 替换成您的二维码文本int qrSize = 500; // 二维码尺寸BufferedImage qrCodeImage = generateQRCode(qrText, qrSize);int qrX = (image.getWidth() - qrSize) / 2;int qrY = 1050; // 设置二维码的垂直位置addImageToImage(image, qrCodeImage, qrX, qrY);// 3. 在图片上添加中文文本,支持手动换行String chineseText = "浙江省湖州市吴兴区妙西镇\n" +"妙山村下姚166号";Font font = new Font("微软雅黑", Font.BOLD, 70); // 替换成所需的字体和大小Color textColor = Color.BLACK; // 文本颜色int textX = 20; // 文本左侧的边距int textY = 800; // 设置文本的垂直位置int textWidth = image.getWidth() - 40; // 文本可用的宽度addTextToImage(image, chineseText, font, textColor, textWidth, textY);// 4. 保存带有二维码和文本的图片try {ImageIO.write(image, "png", new File("C:\\Users\\caozhen\\Desktop\\图片素材\\output.png")); // 替换成保存的文件路径} catch (IOException e) {e.printStackTrace();}}

5、最终生成的图片成功

      

三、如何生成透明的二维码?

1、生成二维码

    // 生成透明的二维码图片private static BufferedImage generateQRCode(String text, int size) {Map<EncodeHintType, Object> hints = new HashMap<>();hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");hints.put(EncodeHintType.MARGIN, 0); // 无边距try {QRCodeWriter writer = new QRCodeWriter();BitMatrix bitMatrix = writer.encode(text, BarcodeFormat.QR_CODE, size, size, hints);int width = bitMatrix.getWidth();int height = bitMatrix.getHeight();BufferedImage qrImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);// 这里就是生成透明二维码关键之处for (int x = 0; x < width; x++) {for (int y = 0; y < height; y++) {qrImage.setRGB(x, y, bitMatrix.get(x, y) ? Color.BLACK.getRGB() : new Color(0, 0, 0, 0).getRGB());}}// 渲染二维码Graphics2D graphics1 = qrImage.createGraphics();// 添加蓝色边框int borderSize = 10; // 边框大小Color myColor = new Color(0x19, 0x76, 0xFF); // 红色graphics1.setColor(myColor);graphics1.fillRect(0, 0, size, borderSize); // 上边框graphics1.fillRect(0, 0, borderSize, size); // 左边框graphics1.fillRect(size - borderSize, 0, borderSize, size); // 右边框graphics1.fillRect(0, size - borderSize, size, borderSize); // 下边框return qrImage;} catch (WriterException e) {e.printStackTrace();return null;}}

 2、看看透明二维码结果

     

四、如何希望生成的是浏览器下载图片

1、 代码调整

1.在方法入参的时候加上HttpServletResponse response// 保存带有二维码和文本的图片// 将图片发送到浏览器response.setContentType("image/png");response.setHeader("Content-Disposition", "attachment; filename=\"output.png\"");OutputStream os = response.getOutputStream();ImageIO.write(image, "png", os);os.close();

五、完整接口调用流程

1.controller层

@RestController
@RequestMapping("/xxx/user/")
@Api(value = "生成二维码", description = "生成二维码")
public class QrcodeController {@RequestMapping(value = "/createAddressQrcode", method = RequestMethod.POST)public void createAddressQrcode(HttpServletResponse response) throws IOException {ImageFileUtils imageFileUtils = new ImageFileUtils();imageFileUtils.createImage(response);}}

 2、工具类ImageFileUtils

public class ImageFileUtils {public void createImage(HttpServletResponse response) throws IOException {// 1. 读取原始图片BufferedImage image = null;try {//这里是读取网络图片URL url = new URL("https:xxxxxxxxxxxxxxxxxxxxxxxxxx");image = ImageIO.read(url);} catch (IOException e) {e.printStackTrace();}if (image == null) {return R.error("无法读取图片");}// 2. 在图片上添加透明的二维码String qrText = "https:xxxxxxxxxxxxxxxx"; // 替换成您的二维码文本int qrSize = 500; // 二维码尺寸BufferedImage qrCodeImage = generateQRCode(qrText, qrSize);int qrX = (image.getWidth() - qrSize) / 2;int qrY = 1050; // 设置二维码的垂直位置addImageToImage(image, qrCodeImage, qrX, qrY);// 3. 在图片上添加中文文本,支持手动换行String chineseText = createQrcodeRequest.getAddress();Font font = new Font("微软雅黑", Font.BOLD, 90); // 替换成所需的字体和大小Color textColor = Color.BLACK; // 文本颜色int textX = 20; // 文本左侧的边距int textY = 800; // 设置文本的垂直位置int textWidth = image.getWidth() - 40; // 文本可用的宽度addTextToImage(image, chineseText, font, textColor, textWidth, textY);// 4. 保存带有二维码和文本的图片// 将图片发送到浏览器response.setContentType("image/png");response.setHeader("Content-Disposition", "attachment; filename=\"output.png\"");OutputStream os = response.getOutputStream();ImageIO.write(image, "png", os);os.close();}// 生成二维码图片private static BufferedImage generateQRCode(String text, int size) {Map<EncodeHintType, Object> hints = new HashMap<>();hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");try {QRCodeWriter writer = new QRCodeWriter();BitMatrix bitMatrix = writer.encode(text, BarcodeFormat.QR_CODE, size, size, hints);int width = bitMatrix.getWidth();int height = bitMatrix.getHeight();BufferedImage qrImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);Graphics2D graphics = qrImage.createGraphics();graphics.setColor(Color.WHITE);graphics.fillRect(0, 0, size, size);graphics.setColor(Color.BLACK);for (int x = 0; x < size; x++) {for (int y = 0; y < size; y++) {if (bitMatrix.get(x, y)) {graphics.fillRect(x, y, 1, 1);}}}// 渲染二维码Graphics2D graphics1 = qrImage.createGraphics();// 添加蓝色边框int borderSize = 10; // 边框大小Color myColor = new Color(0x19, 0x76, 0xFF); // 红色graphics1.setColor(myColor);graphics1.fillRect(0, 0, size, borderSize); // 上边框graphics1.fillRect(0, 0, borderSize, size); // 左边框graphics1.fillRect(size - borderSize, 0, borderSize, size); // 右边框graphics1.fillRect(0, size - borderSize, size, borderSize); // 下边框return qrImage;} catch (WriterException e) {e.printStackTrace();return null;}}// 在图片上添加图片private static void addImageToImage(BufferedImage baseImage, BufferedImage overlayImage, int x, int y) {Graphics2D g2d = baseImage.createGraphics();g2d.drawImage(overlayImage, x, y, null);g2d.dispose();}// 在图片上添加文本,支持手动换行,文本水平居中private static void addTextToImage(BufferedImage baseImage, String text, Font font, Color color, int maxWidth, int y) {Graphics2D g2d = baseImage.createGraphics();g2d.setFont(font);g2d.setColor(color);FontMetrics fm = g2d.getFontMetrics();int lineHeight = fm.getHeight();int currentY = y;String[] lines = text.split("\n");for (String line : lines) {int lineWidth = fm.stringWidth(line);int lineX = (maxWidth - lineWidth) / 2; // 居中g2d.drawString(line, lineX, currentY);currentY += lineHeight;}g2d.dispose();}
}

 六、注意事项

就是当程序部署到linux服务器时,文字格式没有变化的处理方案!

原因:就是linux服务器没有微软雅黑字体,所以导致没有效果。

解决方案是将windows中微软雅黑字体放到linux服务器下即可。

1、到 C:\windows\fonts 复制对应字体库,微软雅黑、宋体、黑体等,各文件后缀可能不一样,有的为ttf,有的为ttc,不影响使用。

2、上传刚才复制的字体库到/usr/share/fonts/zh_CN目录下,如果没有该目录,用命令:mkdir /usr/share/fonts/zh_CN  来创建,然后再上传。

3、修改字体权限,使root以外的用户可以使用这些字体:chmod -R 777 /usr/share/fonts/zh_CN,使用777 赋予全部权限

4、重启springboot项目即可。

 总结

好了,以上就是在图片上嵌入二维码和加入文字的代码了!

有问题可以在评论区留言或者私信我,看到会回复你。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/83610.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

两种风格的纯CSS3加载动画

<!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><title>加载动画</title><style>.loader {w…

已解决 TypeError: Fetch argument None has invalid type <class ‘NoneType‘>

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页: &#x1f405;&#x1f43e;猫头虎的博客&#x1f390;《面试题大全专栏》 &#x1f995; 文章图文并茂&#x1f996…

深入学习 Redis Cluster - 基于 Docker、DockerCompose 搭建 Redis 集群,处理故障、扩容方案

目录 一、基于 Docker、DockerCompose 搭建 Redis 集群 1.1、前言 1.2、编写 shell 脚本 1.3、执行 shell 脚本&#xff0c;创建集群配置文件 1.4、编写 docker-compose.yml 文件 1.5、启动容器 1.6、构建集群 1.7、使用集群 1.8、如果集群中&#xff0c;有节点挂了&am…

Perl区分文件换行符类型

背景 在Windows上使用Perl判断文件时何种换行符时&#xff0c;处理CR LF类型的换行符时&#xff0c;也识别成了LF。 思路 Windows上的换行是 CRLF , Unix上是 LF , Mac CR在Windows平台使用Perl读取文件创建文件句柄时&#xff0c;未对file handler设置binmode&#xff0c;了…

24.Xaml ListView控件-----显示数据

1.运行效果 2.运行源码 a.Xaml源码 <Window x:Class="testView.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.mic…

Python灰帽编程——网页信息爬取

文章目录 网页信息爬取1. 相关模块1.1 requests 模块1.1.1 模块中的请求方法1.1.2 请求方法中的参数1.1.3 响应对象中属性 1.2 RE 模块1.2.1 匹配单个字符1.2.2 匹配一组字符1.2.3 其他元字符1.2.4 核心函数 2. 网页信息爬取2.1 获取网页HTML 源代码2.2 提取图片地址2.3 下载图…

服务器端应用的安装

前言&#xff1a;相信看到这篇文章的小伙伴都或多或少有一些编程基础&#xff0c;懂得一些linux的基本命令了吧&#xff0c;本篇文章将带领大家服务器如何部署一个使用django框架开发的一个网站进行云服务器端的部署。 文章使用到的的工具 Python&#xff1a;一种编程语言&…

机器学习第九课--随机森林

一.什么是集成模型 对于几乎所有的分类问题(图像识别除外&#xff0c;因为对于图像识别问题&#xff0c;目前深度学习是标配)&#xff0c;集成模型很多时候是我们的首选。比如构建一个评分卡系统&#xff0c;业界的标配是GBDT或者XGBoost等集成模型&#xff0c;主要因为它的效…

Windows/Linux(命令、安装包和源码安装)平台各个版本QT详细安装教程

前言 本文章主要介绍了Windows/Linux平台下&#xff0c;QT4&#xff0c;QT5&#xff0c;QT6的安装步骤。为什么要把QT版本分开介绍呢&#xff0c;因为这三个版本&#xff0c;安装步骤都不一样。Windows平台&#xff0c;QT4的Qt Creator&#xff0c;QT库和编译器是分开的&#…

Postman应用——Collection、Folder和Request

文章目录 Collection新建CollectionCollection重命名保存Request到Collection在Collection下创建Request删除Collection Folder新建FolderFolder重命名保存Request到Folder在Folder下创建Request在Folder下创建Folder删除Folder Request创建临时RequestRequest重命名删除Reques…

攻防世界-WEB-fileinclude

访问url&#xff0c;可以看到一些提示&#xff0c;绝对路径/var/www/html/index.php&#xff0c;也提示了flag在flag.php中。 快捷键Ctrlu,查看网页源代码 思路&#xff1a; 源代码中看到 include($lan.".php"); &#xff0c;可知此处存在文件包含。$lan的值是从co…

QGIS怎么修改源代码?持续更新...

修改配置文件保存位置 修改目的&#xff1a;放着和本地安装的其他QGIS共用一份配置文件 修改文件&#xff1a;core/qgsuserprofilemanager.cpp 修改位置&#xff1a;第37行 return basePath QDir::separator() "my_profiles";修改完毕后&#xff0c;再次生成一下…

计算机和编程语言初见

学习程序设计的目的是什么呢&#xff1f; 不一定要做出一个软件或系统出来&#xff0c;更重要的是理解计算机是如何工作的以及它的长处和短处。 计算机本身是无意识的&#xff0c;因此我们要求它为我们做事时&#xff1a;应该将步骤细化、“直”化&#xff08;规律化&#xf…

day51: QTday4,绘制事件、QT连接TCP网络通信

一、绘制时钟 widget.h: #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QPainter> #include <QPaintEvent> #include <QRectF> #include <QTimer> #include <QTime> #include <QTimerEvent> #include <QLabe…

Spring Authorization Server入门 (十八) Vue项目使用PKCE模式对接认证服务

Vue单页面项目使用授权码模式对接流程说明 以下流程摘抄自官网 在本例中为授权代码流程。 授权码流程的步骤如下&#xff1a; 客户端通过重定向到授权端点来发起 OAuth2 请求。 对于公共客户端&#xff0c;此步骤包括生成code_verifier 并计算code_challenge&#xff0c;然后…

mysql数据库备份(mysqldump)

mysqldump命令备份数据 mysqldump -u root -p --databases 数据库1 数据库2 > xxx.sqlmysqldump常用操作示例 1. 备份全部数据库的数据和结构 mysqldump -uroot -p123456 -A > /data/mysqlbackup/mydb.sql2. 备份全部数据库的结构&#xff08;加 -d 参数&#xff09; …

【音视频】ffplay解析-音视频同步

音视频同步 主要解析&#xff1a;以音频为基准&#xff0c;让视频合成音频 思路 视频慢了则丢掉部分视频帧&#xff08;视觉->画⾯跳帧&#xff09; 视频快了则继续渲染上⼀帧 具体实现 一个国际标准&#xff1a;音频帧-视频帧时间戳的差值在-100ms~25ms内流畅 1.差值音频…

菜鸟教程《Python 3 教程》笔记(20):面向对象

菜鸟教程《Python 3 教程》笔记&#xff08;20&#xff09; 20 面向对象20.1 面向对象技术简介20.2 创建类20.2.1 类定义20.2.2 实例化20.2.3 初始化20.2.4 类变量、实例变量20.2.5 类方法、实例方法、静态方法 20.3 访问可见性20.3.1 property装饰器 20.4 动态性20.4.1 __slot…

wpf资源Resources探究性学习(一)

测试环境&#xff1a; vistual studio 2017 .net framework 3.5 window 10 新建WPF应用(.net framework)&#xff0c;项目名称为&#xff1a;WpfDemo&#xff0c;如下图&#xff1a; 新建完项目后&#xff0c;默认带有一个名为MainWindow.xaml的代码 一 简单使用字符串资源…

js常用的数组处理方法

some 方法 用于检查数组中是否至少有一个元素满足指定条件。如果有满足条件的元素&#xff0c;返回值为 true&#xff0c;否则返回 false。 const numbers [1, 2, 3, 4, 5];const hasEvenNumber numbers.some((number) > number % 2 0); console.log(hasEvenNumber); /…