Java生成二维码示例(带logo以及文字描述)

先看一下生成效果

普通二维码

在这里插入图片描述

普通带文本二维码

在这里插入图片描述

带logo二维码

在这里插入图片描述

带logo带文本二维码

在这里插入图片描述

直接上代码

这里主要是用的第三方工具生成二维码的,所以我们需要先引入 jar 包

		<dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.4.1</version></dependency><dependency><groupId>com.google.zxing</groupId><artifactId>javase</artifactId><version>3.4.1</version></dependency>

虽然二维码生成依靠的是第三方工具,但是 logo 和文本还是需要我们自己添加进去的

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.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;/*** @author Sakura* @date 2024/9/30 14:11*/
public class QRCodeGenerator {/*** @description: 生成二维码* @param text 二维码内容* @param remark 二维码描述* @param path 二维码保存路径* @param logoFile 二维码logo文件* @param width 二维码宽度* @param height 二维码高度*/public static void generateQRCode(String text, String remark, String path, File logoFile, int width, int height) throws Exception {// 设置二维码参数Map<EncodeHintType, Object> hints = new ConcurrentHashMap<>();hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); // 高纠错等级hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");hints.put(EncodeHintType.MARGIN, 1); // 边框// 创建BitMatrix对象BitMatrix matrix = new MultiFormatWriter().encode(text, BarcodeFormat.QR_CODE, width, height, hints);// 动态计算增加的高度用于备注文本int textHeight = (remark != null && !remark.isEmpty()) ? 30 : 0;// 创建带有二维码和备注文本的 BufferedImageBufferedImage qrImage = new BufferedImage(width, height + textHeight, BufferedImage.TYPE_INT_RGB);Graphics2D g = qrImage.createGraphics();g.setColor(Color.WHITE);g.fillRect(0, 0, width, height + textHeight); // 设置背景为白色// 绘制二维码到 BufferedImagefor (int x = 0; x < width; x++) {for (int y = 0; y < height; y++) {qrImage.setRGB(x, y, matrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF);}}// 添加Logo到二维码if (logoFile != null && logoFile.exists()) {addLogoToQRCode(qrImage, logoFile, width, height);}// 添加备注文本if (remark != null && !remark.isEmpty()) {addTextToQRCode(qrImage, remark, width, height, textHeight);}// 保存二维码图片到指定路径Path filePath = Paths.get(path);Files.createDirectories(filePath.getParent()); // 确保目录存在ImageIO.write(qrImage, "PNG", new File(path));}// 添加Logo到二维码private static void addLogoToQRCode(BufferedImage qrImage, File logoFile, int qrWidth, int qrHeight) throws Exception {// 读取Logo图片BufferedImage logoImage = ImageIO.read(logoFile);// 计算Logo的缩放比例和新宽高int logoWidth = Math.min(logoImage.getWidth(), qrWidth / 5);  // 缩小至二维码宽度的1/5int logoHeight = Math.min(logoImage.getHeight(), qrHeight / 5);// 计算Logo绘制的左上角位置,使其居中int x = (qrWidth - logoWidth) / 2;int y = (qrHeight - logoHeight) / 2;// 绘制白色边框背景Graphics2D g2 = qrImage.createGraphics();g2.setColor(Color.WHITE);g2.fillRoundRect(x - 5, y - 5, logoWidth + 10, logoHeight + 10, 10, 10);// 绘制Logo到二维码中心g2.drawImage(logoImage.getScaledInstance(logoWidth, logoHeight, Image.SCALE_SMOOTH), x, y, null);g2.dispose();}// 在二维码底部添加文本private static void addTextToQRCode(BufferedImage image, String text, int width, int qrHeight, int textHeight) {Graphics2D g2 = image.createGraphics();g2.setColor(Color.BLACK);g2.setFont(new Font("Arial", Font.PLAIN, 20));  // 设置字体// 获取文本的宽度以便居中对齐FontMetrics fm = g2.getFontMetrics();int textWidth = fm.stringWidth(text);int x = (width - textWidth) / 2;// 调整 y 坐标位置,将文本稍微上移int padding = 10;  // 增加一个 padding 值,让文本上移一点,避免贴得太近int y = qrHeight + (textHeight - fm.getHeight()) / 2 + fm.getAscent() - padding;// 绘制文本g2.drawString(text, x, y);g2.dispose(); // 释放资源}
}

然后就可以在我们的业务里面调用了

@RestController
@RequestMapping("/qrcode")
@Module("base")
@Api(value = "二维码api", tags = {"二维码管理"})
public class QrcodeController {@Autowiredprivate QrcodeService qrcodeService;@PostMapping("/generate")@ApiOperation(value = "生成二维码", response = ApiResult.class)public ApiResult<String> generate(@RequestParam(value = "text") String text,@RequestParam(value = "remark", required = false) String remark,@RequestParam(value = "width", required = false, defaultValue = "300") Integer width,@RequestParam(value = "height", required = false, defaultValue = "300") Integer height) throws Exception {String path = qrcodeService.generate(text, remark, width, height);return ApiResult.ok(path);}@PostMapping("/generateWithLogo")@ApiOperation(value = "生成带logo二维码", response = ApiResult.class)public ApiResult<String> generateWithLogo(@RequestPart("file") MultipartFile file,@RequestParam(value = "text") String text,@RequestParam(value = "remark", required = false) String remark,@RequestParam(value = "width", required = false, defaultValue = "300") Integer width,@RequestParam(value = "height", required = false, defaultValue = "300") Integer height) throws Exception {String path = qrcodeService.generateWithLogo(file, text, remark, width, height);return ApiResult.ok(path);}/*** 下载文件*/@GetMapping("/{code}")@ApiOperation(value = "下载")public void download(HttpServletResponse response, @PathVariable("code") String code) throws Exception {qrcodeService.download(response, code);}}
@Service
@Log
public class QrcodeServiceImpl implements QrcodeService {@Value("${local.host}")String LOCAL_HOST;// 文件存放路径跟jar包同目录下/resources/files/private static final String LOCAL_FILE_PATH = "./resources/qrcode/";@Overridepublic String generate(String text, String remark, Integer width, Integer height) throws Exception {// 随机生成一个文件名String code = RandomStringUtils.randomAlphanumeric(32);QRCodeGenerator.generateQRCode(text, remark, LOCAL_FILE_PATH + code + ".png", null, width, height);return LOCAL_HOST + "qrcode/" + code;}@Overridepublic String generateWithLogo(MultipartFile file, String text, String remark, Integer width, Integer height) throws Exception {// 随机生成一个文件名String code = RandomStringUtils.randomAlphanumeric(32);// 创建临时文件,确保文件路径正确File convFile = File.createTempFile("logo_", "_" + file.getOriginalFilename());file.transferTo(convFile);// 调用生成二维码的方法QRCodeGenerator.generateQRCode(text, remark, LOCAL_FILE_PATH + code + ".png", convFile, width, height);// 删除临时文件convFile.delete();return LOCAL_HOST + "qrcode/" + code;}@Overridepublic void download(HttpServletResponse response, String code) throws Exception {File downloadFile = new File(LOCAL_FILE_PATH + code + ".png");if (!downloadFile.exists() || downloadFile.length() == 0) {throw new BusinessException(500, "文件不存在");}// 确定文件的Content-TypeString mimeType = Files.probeContentType(downloadFile.toPath());if (mimeType == null) {mimeType = "application/octet-stream"; // 默认类型}response.setContentType(mimeType);response.addHeader("Content-Length", String.valueOf(downloadFile.length()));response.addHeader("Content-Disposition", "attachment; filename=\"" + code + ".png\"");try (InputStream is = new FileInputStream(downloadFile);OutputStream os = response.getOutputStream()) {IOUtils.copy(is, os);os.flush(); // 确保数据已写入输出流} catch (IOException e) {log.info("下载图片发生IO异常");e.printStackTrace();throw new BusinessException(500, "文件下载失败");} catch (Exception e) {log.info("下载图片发生异常");e.printStackTrace();throw new BusinessException(500, "文件下载失败");}}
}

注意我这里是将二维码保存到了本地 ./resources/qrcode/ 路径下,然后通过 http://localhost:1000/api-base/qrcode/m1BGhAAj29N9eIeKbyEBvocXXboW1RGc 调用自己的下载接口下载的,大家可以直接就返回生成的二维码文件即可

在这里插入图片描述

在这里插入图片描述

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

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

相关文章

2024诺贝尔生理学或医学奖:RNA技术将拯救人类世界

生信碱移 miRNA领域获得最新诺贝尔奖 “我好像接到了真的诺贝尔委员会的电话&#xff01;” 加里鲁夫坎 2024年诺贝尔医学奖得主 ▲ 两位诺贝尔奖获奖得主。来源:诺贝尔生理学或医学奖委员会。 就在今天&#xff0c;卡罗林斯卡学院的诺贝尔大会决定将2024年诺贝尔生理学或医学…

动手学深度学习(李沐)PyTorch 第 6 章 卷积神经网络

李宏毅-卷积神经网络CNN 如果使用全连接层&#xff1a;第一层的weight就有3*10^7个 观察 1&#xff1a;检测模式不需要整张图像 很多重要的pattern只要看小范围即可 简化1&#xff1a;感受野 根据观察1 可以做第1个简化&#xff0c;卷积神经网络会设定一个区域&#xff0c…

无人机之飞行算法篇

无人机的飞行算法是一个复杂而精细的系统&#xff0c;它涵盖了多个关键技术和算法&#xff0c;以确保无人机能够稳定、准确地执行飞行任务。 一、位置估计 无人机在空中飞行过程中需要实时获取其位置信息&#xff0c;以便进行路径规划和控制。这通常通过以下传感器实现&#…

基于STM32的模拟舞台灯光控制系统设计

引言 本项目设计了一个基于STM32的模拟舞台灯光控制系统&#xff0c;可以通过调节灯光的亮度、颜色和模式&#xff0c;实现多种灯光效果模拟&#xff0c;如渐变、闪烁和跟随节奏的灯光变化。该系统结合了LED灯条、PWM控制和按钮输入等&#xff0c;实现了舞台灯光的多样化展示。…

【Linux的那些事】shell命名及Linux权限的理解

目录 一、shell命令以及运行原理 二、Linux权限的概念 三、Linux权限管理 3.1.文件访问者的分类&#xff08;人&#xff09; 3.2.文件类型和访问权限&#xff08;事物属性&#xff09; 3.3.文件权限值的表示方法 3.4.文件访问权限的相关设置方法 a)chmod b)chown c)…

5.错误处理在存储过程中的重要性(5/10)

错误处理在存储过程中的重要性 引言 在数据库编程中&#xff0c;存储过程是一种重要的组件&#xff0c;它允许用户将一系列SQL语句封装成一个单元&#xff0c;以便重用和简化数据库操作。然而&#xff0c;像任何编程任务一样&#xff0c;存储过程中的代码可能会遇到错误或异常…

使用MTVerseXR SDK实现VR串流

1、概述​ MTVerseXR SDK 是摩尔线程GPU加速的虚拟现实&#xff08;VR&#xff09;流媒体平台&#xff0c;专门用于从远程服务器流式传输基于标准OpenXR的应用程序。MTVerseXR可以通过Wi-Fi和USB流式将VR内容从Windows服务器流式传输到XR客户端设备, 使相对性能低的VR客户端可…

15分钟学 Python 第38天 :Python 爬虫入门(四)

Day38 : Python爬虫异常处理与反爬虫机制 章节1&#xff1a;异常处理的重要性 在爬虫开发过程中&#xff0c;网络请求和数据解析常常会遭遇各种异常。正确的异常处理可以提高程序的稳定性&#xff0c;避免崩溃&#xff0c;并帮助开发者快速定位问题。 章节2&#xff1a;常见…

18710 统计不同数字的个数(升级版)

### 思路 为了快速判断某个数字是否在之前出现过&#xff0c;我们可以使用一个布尔数组来记录每个数字是否已经出现过。由于题目中给出了数字的范围&#xff08;0 < ai < 200000&#xff09;&#xff0c;我们可以开一个大小为200001的布尔数组来记录每个数字的出现情况。…

网络编程(15)——服务器如何主动退出

十五、day15 服务器主动退出一直是服务器设计必须考虑的一个方向&#xff0c;旨在能通过捕获信号使服务器安全退出。我们可以通过asio提供的信号机制绑定回调函数即可实现优雅退出。 之前服务器的主函数如下 #include "CSession.h" #include "CServer.h"…

ASP.NetCore---I18n(internationalization)多语言版本的应用

文章目录 0.实现的效果如下1.创建新项目I18nBaseDemo2.添加页面中的下拉框3.在HomeController中添加ChangeLanguage方法4.在Progress.cs 文件中添加如下代码&#xff1a;5. 在progress.cs中添加code6.添加Resource资源文件7.在页面中引用i18n的变量8. 重启项目&#xff0c;应该…

录屏达人必备!四款神器助你轻松搞定一切

录屏&#xff0c;一个既简单又实用的技能&#xff0c;不仅能帮助我们记录下电脑上的精彩瞬间&#xff0c;还能在需要的时候进行演示。是不是觉得特别棒呢&#xff1f;今天&#xff0c;我就来给大家分享一下如何轻松地录屏&#xff0c;并推荐四款非常实用的录屏工具。 一、如何录…

力扣hot100--链表

链表 1. 2. 两数相加 给你两个 非空 的链表&#xff0c;表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的&#xff0c;并且每个节点只能存储 一位 数字。 请你将两个数相加&#xff0c;并以相同形式返回一个表示和的链表。 你可以假设除了数字 0 之外&#xff…

网络学习第二篇

认识网关和路由器 这里大家先了解一下什么三层设备。 三层设备 三层设备是指在网络架构中能够工作在第三层&#xff08;网络层&#xff09;的设备&#xff0c;通常包括三层交换机和路由器。这些设备可以根据IP地址进行数据包的转发和路由选择&#xff0c;从而在不同的网络之间…

JVM Class类文件结构

国庆节快乐 2024年10月2日17:49:22 目录 前言 magic 数 文件版本 使用JClassLib观察class文件 一般信息 接口 常量池 字段 方法 常量池计数器 常量池 类型 CONSTANT_Methodref_info CONSTANT_Class_info 类型结构总表 访问标志 类索引, …

【DataSophon】DataSophon1.2.1 整合Zeppelin并配置Hive|Trino|Spark解释器

目录 ​一、Zeppelin简介 二、实现步骤 2.1 Zeppelin包下载 2.2 work配置文件 三、配置常用解释器 3.1配置Hive解释器 3.2 配置trino解释器 3.3 配置Spark解释器 一、Zeppelin简介 Zeppelin是Apache基金会下的一个开源框架&#xff0c;它提供了一个数据可视化的框架&am…

影视cms泛目录用什么程序?苹果cms二次开发泛目录插件

影视CMS泛目录一般使用的程序有很多种&#xff0c;&#xff08;maccmscn&#xff09;以下是其中几种常见的程序&#xff1a; WordPress&#xff1a;WordPress是一个非常流行的开源内容管理系统&#xff0c;可以通过安装一些插件来实现影视CMS泛目录功能。其中&#xff0c;一款常…

基于H3C环境的实验——OSPF

目录 实验设备和环境 实验设备 实验环境 实验记录 1、单区域 OSPF基本配置 步骤1:搭建实验环境并完成基本配置 步骤2:检查网络连通性和路由器路由表。 步骤3:配置OSPF 步骤4:检查路由器OSPF邻居状态及路由表 实验设备和环境 实验设备 三台路由器、两台PC、电源线、两…

Kubernetes中部署ELK Stack日志收集平台

1 、ELK概念 ELK是Elasticsearch、Logstash、Kibana三大开源框架首字母大写简称。市面上也被成为Elastic Stack。其中: Elasticsearch是一个基于Lucene、分布式、通过Restful方式进行交互的近实时搜索平台框架。像类似百度、谷歌这种大数据全文搜索引擎的场景都可以使用Elas…

【Spring】@RequestMapping、@RestController和Postman

文章目录 1.RequestMapping 注解介绍2. RequestMapping 使用3. RequestMapping 是 GET 还是 POST 请求&#xff1f;GET 请求POST 请求指定 GET/POST 方法类型 2. Postman 介绍1. 创建请求2. 传参介绍1. 普通传参2. form-data3. x-www-form-urlencoded4. raw 1.RequestMapping 注…