Java使用ZXing库生成带有Logo的二维码图片,并去除白边动态伸缩上传到阿里云OSS

文章目录

    • 引言
    • 二维码基本原理
      • 1、二维码概述
      • 2、QR Code结构
      • 3、错误纠正级别
    • QR Code生成技术
      • 1、ZXing库
      • 2、生成二维码的步骤
    • 图像处理技术
      • 1、嵌入Logo
      • 2. 去除白边
    • 阿里云OSS基本概念
      • 1、OSS概述
      • 2. 主要功能
      • 3. 基本概念
    • 实战演示
      • 1、依赖库
      • 2、类结构
      • 3、生成普通二维码
      • 4. 去除白边
      • 5、普通二维码增加Logo
      • 6. 上传到阿里云OSS
    • 完整工具类
    • 总结

引言

在现代应用中,二维码因其高效的信息编码能力而被广泛应用。为了提升二维码的视觉效果和品牌识别度,通常会在二维码中嵌入Logo。本文将详细介绍使用ZXing库生成带有Logo的二维码图片,去除白边,并将生成的二维码上传到阿里云OSS。此外,本文还将介绍二维码的基本原理、QR Code的结构、图像处理技术以及阿里云OSS的基本概念。

二维码基本原理

1、二维码概述

二维码(QR Code)是一种二维条码,可以存储大量的数据,如URL、文本、数字等。与一维条码相比,二维码可以在两个维度上存储信息,因此具有更高的信息密度和更强的容错能力。

2、QR Code结构

QR Code由以下部分组成:
定位图案:位于二维码的三个角,用于帮助扫描设备定位二维码。
校正图案:用于纠正扫描过程中可能出现的错误。
数据区域:存储实际的数据信息。
格式信息:存储二维码的版本、错误纠正级别等信息。
版本信息:指示二维码的版本号,版本号越高,可以存储的数据量越大。
静区:二维码周围的空白区域,用于防止二维码与其他图案混淆。

3、错误纠正级别

QR Code支持四种错误纠正级别:
L(Low):约7%的错误纠正能力。
M(Medium):约15%的错误纠正能力。
Q(Quartile):约25%的错误纠正能力。
H(High):约30%的错误纠正能力。

QR Code生成技术

1、ZXing库

ZXing(Zebra Crossing)是一个开源的、多格式的1D/2D条码图像处理库。它支持多种条码格式,包括QR Code、Code 128、EAN-13等。在本文中,我们将使用ZXing库来生成二维码。

2、生成二维码的步骤

创建QRCodeWriter实例:用于生成二维码。
设置编码提示:如字符集、错误纠正级别等。
生成BitMatrix:将输入数据编码为BitMatrix对象。
转换为BufferedImage:将BitMatrix对象转换为BufferedImage对象。
去除白边:去除二维码周围的白边,使二维码更加紧凑。
嵌入Logo:在二维码中嵌入Logo图像。

图像处理技术

1、嵌入Logo

在二维码中嵌入Logo图像可以提升视觉效果。嵌入Logo的步骤如下:
读取Logo图像:从指定路径读取Logo图像。
调整Logo大小:根据二维码的大小调整Logo的尺寸。
绘制Logo:将调整后的Logo绘制到二维码的中心位置。
添加圆角:为Logo添加圆角,使其更加美观。

2. 去除白边

去除二维码周围的白边可以减少图像的大小,提升视觉效果。去除白边的步骤如下:
遍历图像:遍历二维码图像,找到非白色像素的边界。
裁剪图像:根据找到的边界裁剪图像,去除白边。

阿里云OSS基本概念

1、OSS概述

阿里云对象存储服务(Object Storage Service,简称OSS)是阿里云提供的海量、安全、低成本、高可靠的云存储服务。OSS适合存放任意类型的文件,如图片、音视频、日志文件、备份文件等。

2. 主要功能

存储和分发:提供高可用性和持久性的存储服务。
权限管理:支持细粒度的访问控制。
数据处理:提供图像处理、视频处理等增值服务。
监控和日志:提供详细的监控和日志记录。

3. 基本概念

Bucket:存储空间,用于存放文件。
Object:存储在Bucket中的文件。
Endpoint:访问OSS的域名。
Access Key ID 和 Access Key Secret:用于身份验证的密钥对。

实战演示

1、依赖库

为了实现二维码生成和图像处理功能,QRCodeWithLogoUtil 使用了以下依赖库:
ZXing (Zebra Crossing):一个开源的、多格式的1D/2D条码图像处理库。
Apache Commons Imaging:用于图像处理和操作。
阿里云OSS SDK:用于上传文件到阿里云OSS。
在 pom.xml 中添加以下依赖:

<!--安装OSS SDK-->
<dependency><groupId>com.aliyun.oss</groupId><artifactId>aliyun-sdk-oss</artifactId><version>3.16.3</version>
</dependency>
<!-- ZXing core -->
<dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.5.3</version>
</dependency>
<!-- ZXing javase -->
<dependency><groupId>com.google.zxing</groupId><artifactId>javase</artifactId><version>3.5.3</version>
</dependency>

2、类结构

在这里插入图片描述

3、生成普通二维码

generateQRCodeImage(String text, int width, int height) 方法用于生成带有Logo的二维码。
在这里插入图片描述

4. 去除白边

deleteWhite(BitMatrix matrix,int qrWidth,int qrHeight)
方法用于去除二维码周围的白边,使二维码更加紧凑,去除白边后对二维码图片进行拉伸满足业务要求。
在这里插入图片描述

5、普通二维码增加Logo

addLogoToQrCode(BufferedImage qrCodeImage, BufferedImage logoImage,int loginWidth,int loginHeight) 方法在原始的 二维码基础上增加logo。
在这里插入图片描述

6. 上传到阿里云OSS

generateQrCodeImageAndUploadToOss(String qrText, int width, int height,String logoName,int loginWidth,int loginHeight,String objectName) 方法作为调用入口,将二维码创建完成后并将生成的二维码上传到阿里云OS。
在这里插入图片描述

完整工具类

/*** QRCodeWithLogoUtil* @author senfel* @version 1.0* @date 2025/2/25 14:31*/
@Component
@Slf4j
public class QRCodeWithLogoUtil {private static final String ENDPOINT = "https://oss-cn-shanghai.aliyuncs.com";private static final String ACCESS_KEY_ID = "LTAI5tB91wtXft75XXXX";private static final String ACCESS_KEY_SECRET = "ecgR2ZCAb9uXXXXXX";private static final String BUCKET_NAME = "cn-sh-dev-csa-oss-01";private static OSS OSS_CLIENT = null;static {// 创建OSSClient实例。OSS_CLIENT = new OSSClientBuilder().build(ENDPOINT, ACCESS_KEY_ID, ACCESS_KEY_SECRET);}public static void main(String[] args) throws Exception {// 二维码内容String qrText = "https://XXXXX/code/mp?scene=dp&dpsource=scancode&b=fdzInN0FwUuL4a5E";// logo图片名称,放置在resourceString logoName = "inchanel-logo.png";String objectName = "moi/fdzInN0FwUuL4a5E222.png";int width = 100;int height = 100;int loginWidth = 26;int loginHeight = 26;String s = generateQrCodeImageAndUploadToOss(qrText, width, height, logoName, loginWidth, loginHeight, objectName);System.err.println(s);}/*** generateQrCodeImageAndUploadToOss* @param qrText* @param width* @param height* @param logoName* @param loginWidth* @param loginHeight* @param objectName* @author senfel* @date 2025/2/26 10:01* @return java.lang.String*/public static String generateQrCodeImageAndUploadToOss(String qrText, int width, int height,String logoName,int loginWidth,int loginHeight,String objectName) throws Exception {try {BufferedImage qrImage = generateQRCodeImage(qrText, width, height);BufferedImage logoImage = ImageIO.read(Objects.requireNonNull(QRCodeWithLogoUtil.class.getClassLoader().getResource(logoName)));BufferedImage finalImage = addLogoToQrCode(qrImage, logoImage,loginWidth,loginHeight);ByteArrayOutputStream os = new ByteArrayOutputStream();ImageIO.write(finalImage, "PNG", os);// 将图片保存在内存中,imageBytes即为二维码图片的字节流byte[] imageBytes = os.toByteArray();//保存本地//ImageIO.write(finalImage, "PNG", new File("D:\\blank\\fdzInN0FwUuL4a5E22.png"));//将图片上传到oss//将imageBytes转为输入流ByteArrayInputStream inputStream = new ByteArrayInputStream(imageBytes);PutObjectRequest putObjectRequest = new PutObjectRequest(BUCKET_NAME, objectName, inputStream);OSS_CLIENT.putObject(putObjectRequest);VoidResult voidResult = OSS_CLIENT.setObjectAcl(BUCKET_NAME, objectName, CannedAccessControlList.PublicRead);if( 200 != voidResult.getResponse().getStatusCode()){log.error("QRCodeWithLogoUtil上传图片到OSS失败,响应信息为:{}", voidResult.getResponse());throw new RuntimeException("QRCodeWithLogoUtil上传图片到OSS失败");}return voidResult.getResponse().getUri().substring(0,voidResult.getResponse().getUri().indexOf("?"));} catch (Exception e) {log.error("QRCodeWithLogoUtil生成二维码失败,异常信息为:{}", e.getMessage(),e);throw new RuntimeException("QRCodeWithLogoUtil生成二维码失败");}}/*** generateQRCodeImage* @param text* @param width* @param height* @author senfel* @date 2025/2/25 19:00* @return java.awt.image.BufferedImage*/private static BufferedImage generateQRCodeImage(String text, int width, int height) throws WriterException {Map<EncodeHintType, Object> hints = new HashMap<>();hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);BitMatrix bitMatrix = new MultiFormatWriter().encode(text, BarcodeFormat.QR_CODE, width, height, hints);return deleteWhite(bitMatrix,width,height);}/*** deleteWhite* @param matrix* @param qrWidth* @param qrHeight* @author senfel* @date 2025/2/25 19:00* @return java.awt.image.BufferedImage*/private static BufferedImage deleteWhite(BitMatrix matrix,int qrWidth,int qrHeight) {int[] rec = matrix.getEnclosingRectangle();int resWidth = rec[2];int resHeight = rec[3];BitMatrix resMatrix = new BitMatrix(resWidth, resHeight);resMatrix.clear();for (int i = 0; i < resWidth; i++) {for (int j = 0; j < resHeight; j++) {if (matrix.get(i + rec[0], j + rec[1]))resMatrix.set(i, j);}}int width = resMatrix.getWidth();int height = resMatrix.getHeight();BufferedImage image = new BufferedImage(width, height,BufferedImage.TYPE_INT_RGB);for (int x = 0; x < width; x++) {for (int y = 0; y < height; y++) {image.setRGB(x, y, resMatrix.get(x, y) ? 0 : 255);}}//生成二维码BufferedImage bufferedImage = MatrixToImageWriter.toBufferedImage(resMatrix);// 若二维码的实际宽高和预期的宽高不一致, 则缩放if (qrWidth != width || qrHeight != height) {BufferedImage tmp = new BufferedImage(qrWidth, qrHeight, BufferedImage.TYPE_INT_RGB);tmp.getGraphics().drawImage(bufferedImage.getScaledInstance(qrWidth, qrHeight,Image.SCALE_SMOOTH), 0, 0, null);bufferedImage = tmp;}return bufferedImage;}/*** addLogoToQrCode* @param qrCodeImage* @param logoImage* @param loginWidth* @param loginHeight* @author senfel* @date 2025/2/26 17:42* @return java.awt.image.BufferedImage*/private static BufferedImage addLogoToQrCode(BufferedImage qrCodeImage, BufferedImage logoImage,int loginWidth,int loginHeight) {Graphics2D graphics = qrCodeImage.createGraphics();// Logo图片左上角的x坐标,可根据需要调整位置int x = (qrCodeImage.getWidth() - loginWidth) / 2;// Logo图片左上角的y坐标,可根据需要调整位置int y = (qrCodeImage.getHeight() - loginHeight) / 2;// 设置抗锯齿graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);graphics.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);// 绘制Logo图片到二维码上graphics.drawImage(logoImage, x, y, loginWidth, loginHeight, null);// 释放资源graphics.dispose();// 返回带有Logo的二维码图片对象return qrCodeImage;}
}

效果展示

在这里插入图片描述

在这里插入图片描述

总结

通过本文的介绍,你已经了解了使用ZXing库生成带有Logo的二维码图片,去除白边,并将生成的二维码上传到阿里云OSS。此外,本文还介绍了二维码的基本原理、QR Code的结构、图像处理技术以及阿里云OSS的基本概念。这个工具类可以广泛应用于各种需要生成二维码的场景,提升用户体验和品牌识别度。

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

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

相关文章

AI工具箱最新使用教程

先克隆项目 电脑需要先安装 git &#xff0c;安装的画看这个 Git安装教程&#xff08;超详细&#xff09;。 git镜像 git clone https://github.com/Escaflowne1985/MyToolsWebBackendUser.gitgitee镜像 git clone https://gitee.com/escaflowne/MyToolsWebBackendUser.git…

Android-创建mipmap-anydpi-v26的Logo

利用 Android Studio 自动创建 创建新项目&#xff1a;打开 Android Studio&#xff0c;点击 “Start a new Android Studio project” 创建新项目。在创建项目的过程中&#xff0c;当设置Target SDK Version为 26 或更高版本时&#xff0c;Android Studio 会在项目的res目录下…

SEO炼金术(4)| Next.js SEO 全攻略

在上一篇文章 SEO炼金术&#xff08;3&#xff09;| 深入解析 SEO 关键要素 中&#xff0c;我们深入解析了 SEO 关键要素&#xff0c;包括 meta 标签、robots.txt、canonical、sitemap.xml 和 hreflang&#xff0c;并探讨了它们在搜索引擎优化&#xff08;SEO&#xff09;中的作…

面试葵花宝典之React(持续更新中)

1.谈谈你对HOC的理解 定义&#xff1a; 高阶组件是一个接收组件作为参数并返回新组件的函数&#xff0c;用于复用组件逻辑&#xff0c;遵循纯函数特性&#xff08;无副作用&#xff0c;输出仅依赖输入&#xff09;。 组合性&#xff1a;可嵌套使用多个 HOC。 HOC&#xff08;…

数据安全管理的AI工具有哪些?

数据安全管理的AI工具在不断演进&#xff0c;它们凭借强大的算法和学习能力&#xff0c;为企业筑起了一道坚不可摧的数字防线。 在数据安全管理领域&#xff0c;AI工具的应用日益广泛&#xff0c;以下是一些常见的工具及其功能&#xff1a; AI驱动的数据分类与标记 工具: Micr…

Matplotlib 绘图标记

Matplotlib 绘图标记 引言 Matplotlib 是一个功能强大的 Python 绘图库&#xff0c;广泛用于数据可视化。在 Matplotlib 中&#xff0c;绘图标记&#xff08;markers&#xff09;是数据点在图表中显示的方式。正确的使用绘图标记可以增强图表的可读性和美观性。本文将详细介绍…

【DeepSeek问答】QProcess::start是异步的吗?会使UI卡顿吗?

好的&#xff0c;我现在需要回答用户关于QProcess::start是否是异步的&#xff0c;以及它是否会导致UI卡顿的问题。用户之前已经询问过如何开发一个调用7-Zip的Qt应用&#xff0c;并且我给出了示例代码。现在用户可能在使用过程中遇到了问题&#xff0c;或者想更深入了解QProce…

Android 常用命令和工具解析之存储相关

1 基本概念 2 命令解读 2.1 adb shell df df 命令主要用于需要检查文件系统上已使用和可用的磁盘空间的数量。如果没有指定文件名&#xff0c;则显示在当前所有挂载的文件系统上可用的空间。其原理是从proc/mounts 或 /etc/mtab 中检索磁盘信息。 注意&#xff1a;df命令并…

使用ZFile打造属于自己的私有云系统结合内网穿透实现安全远程访问

文章目录 前言1.关于ZFile2.本地部署ZFile3.ZFile本地访问测试4.ZFile的配置5.cpolar内网穿透工具安装6.创建远程连接公网地址7.固定ZFile公网地址 前言 在数字化的今天&#xff0c;我们每个人都是信息的小能手。无论是职场高手、摄影达人还是学习狂人&#xff0c;每天都在创造…

HarmonyOS 5.0应用开发——鸿蒙接入高德地图实现POI搜索

【高心星出品】 文章目录 鸿蒙接入高德地图实现POI搜索运行结果&#xff1a;准备地图编写ArkUI布局来加载HTML地图 鸿蒙接入高德地图实现POI搜索 在当今数字化时代&#xff0c;地图应用已成为移动设备中不可或缺的一部分。随着鸿蒙系统的日益普及&#xff0c;如何在鸿蒙应用中…

idea + Docker + 阿里镜像服务打包部署

一、下载docker desktop软件 官网下载docker desktop&#xff0c;需要结合wsl使用 启动成功的画面(如果不是这个画面例如一直处理start或者是stop需要重新启动&#xff0c;不行就重启电脑) 打包成功的镜像在这里&#xff0c;如果频繁打包会导致磁盘空间被占满&#xff0c;需…

IP---网络类型

这只是IP的其中一块内容-网络类型&#xff0c;IP还有更多内容可以查看IP专栏&#xff0c;前一章内容为访问服务器流程&#xff0c;可通过以下路径查看IP----访问服务器流程-CSDN博客&#xff0c;欢迎指正 2.网络类型 网络类型---根据二层&#xff08;数据链路层&#xff09;所…

【监督学习】ARIMA预测模型步骤及matlab实现

ARIMA预测模型 ARIMA预测模型1.算法步骤2.参数选择(1)拖尾截尾判断法(2) AIC 准则(3) BIC 准则 3.MATLAB 实现参考资料 ARIMA预测模型 #mermaid-svg-mDhjwpnuA0YcEGnE {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg…

使用git管理uniapp项目

1.本地管理 1. 在项目根目录中新建 .gitignore 忽略文件&#xff0c;并配置如下&#xff1a; # 忽略 node_modules 目录 /node_modules /unpackage/dist 2. 打开终端&#xff0c;切换到项目根目录中&#xff0c;运行如下的命令&#xff0c;初始化本地 Git 仓库&#xff1…

Unity中动态切换光照贴图的方法

关键代码&#xff1a;LightmapSettings.lightmaps lightmapDatas; LightmapData中操作三张图&#xff1a;lightmapColor,lightmapDir,以及一张ShadowMap 这里只操作前两张&#xff1a; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.UI;public cl…

C# 运算符

C# 运算符 在C#编程语言中,运算符是用于执行数学或逻辑运算的符号。它们是构建程序逻辑和表达式的基石。C#支持多种类型的运算符,包括算术运算符、关系运算符、逻辑运算符、位运算符、赋值运算符、自增自减运算符以及一些特殊运算符。 算术运算符 算术运算符用于执行基本的…

1.2 Kaggle大白话:Eedi竞赛Transformer框架解决方案02-GPT_4o生成训练集缺失数据

目录 0. 本栏目竞赛汇总表1. 本文主旨2. AI工程架构3. 数据预处理模块3.1 配置数据路径和处理参数3.2 配置API参数3.3 配置输出路径 4. AI并行处理模块4.1 定义LLM客户端类4.2 定义数据处理函数4.3 定义JSON保存函数4.4 定义数据分片函数4.5 定义分片处理函数4.5 定义文件名排序…

pycharm远程连接服务器运行pytorch

Linux部署pytorch 背景介绍 不同的开源代码可能需要不同的实验环境和版本&#xff0c;这时候的确体现出Anaconda管理环境的好处了&#xff0c;分别搞一个独立环境方便管理。 有的教程建议选择较旧的版本&#xff0c;但笔者建议在条件允许的情况下安装最新版&#xff0c;本次…

Python开发 Flask框架面试题及参考答案

目录 Flask 的核心设计理念是什么?与 Django 相比有哪些显著差异? 解释 Flask 框架的核心理念及其作为 “微框架” 的优缺点 Flask 的依赖库有哪些?简述 Werkzeug 和 Jinja2 的作用 什么是 WSGI?Flask 如何基于 WSGI 实现服务端与应用的交互 解释 RESTful API 的设计原…

从“Switch-case“到“智能模式“:C#模式匹配的终极进化指南

当代码开始"思考" 你是否厌倦了层层嵌套的if-else地狱&#xff1f;是否想过让代码像侦探推理一样优雅地解构数据&#xff1f;C#的模式匹配正是这样一把瑞士军刀&#xff0c;从C# 7.0到C# 12&#xff0c;它已悄然进化成改变编程范式的利器。 一、模式匹配的三重境界…