VUE+Springboot实现生成二维码及二维码下载功能

一、Springboot相关

1、pom依赖引入

<!-- 生成二维码 --><dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.3.0</version></dependency><dependency><groupId>com.google.zxing</groupId><artifactId>javase</artifactId><version>3.3.0</version></dependency>

2、代码实现

import com.google.zxing.BarcodeFormat;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;/*** 生成图片二维码** @param content 二维码内容* @return*/private String buildQRCode(String content, String[] arr) {ByteArrayOutputStream outputStream = null;ByteArrayInputStream in = null;ByteArrayOutputStream outputStream1 = null;try {QRCodeWriter qrCodeWriter = new QRCodeWriter();BitMatrix bitMatrix = qrCodeWriter.encode(content, BarcodeFormat.QR_CODE, 1000, 1000);//去掉二维码白边int[] rec = bitMatrix.getEnclosingRectangle();int resWidth = rec[2] + 1;int resHeight = rec[3] + 1;BitMatrix resMatrix = new BitMatrix(resWidth, resHeight);resMatrix.clear();for (int i = 0; i < resWidth; i++) {for (int j = 0; j < resHeight; j++) {if (bitMatrix.get(i + rec[0], j + rec[1]))resMatrix.set(i, j);}}//去掉二维码白边  结束outputStream = new ByteArrayOutputStream();MatrixToImageWriter.writeToStream(resMatrix, "PNG", outputStream);int width = 1000;int height = 1500;outputStream1 = new ByteArrayOutputStream();in = new ByteArrayInputStream(outputStream.toByteArray());BufferedImage image = ImageIO.read(in);BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);Graphics2D g2 = bi.createGraphics();//            //开始绘图 这版设置透明似乎有点点问题  暂时注掉
//            g2.setBackground(Color.WHITE);
//            g2.clearRect(0, 0, width, height);
//            g2.setPaint(new Color(255, 255, 255,1));      //设置背景颜色
//            g2.fillRect(0, 0, width, height);  //填充颜色
//
//            //设置透明  start
//            bi = g2.getDeviceConfiguration().createCompatibleImage(width, height, Transparency.TRANSLUCENT);
//            g2 = bi.createGraphics();
//            //设置透明  endg2.setBackground(Color.WHITE);g2.clearRect(0, 0, width, height);/** 设置生成图片的文字样式 * */Font font = new Font("黑体", Font.BOLD, 80);g2.setFont(font);g2.setPaint(Color.BLACK);//生成头部文字/** 防止生成的文字带有锯齿 * */g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);FontRenderContext context = g2.getFontRenderContext();Rectangle2D bounds = font.getStringBounds(QR_CODE_HEAD_STR, context);double headX = (width - bounds.getWidth()) / 2;/** 在图片上生成文字 * */g2.drawString(QR_CODE_HEAD_STR, (int) headX, 80);g2.drawImage(image, 0, 165, width - 1, height - 520, null); //这里减去25是为了防止字和图重合font = new Font("黑体", Font.BOLD, 60);g2.setFont(font);double i = 2.5;for (String str : arr) {/** 设置字体在图片中的位置 在这里是居中* */context = g2.getFontRenderContext();bounds = font.getStringBounds(str, context);double x = (width - bounds.getWidth()) / 2;double y = (height - 75 - bounds.getHeight());double ascent = -bounds.getY() - bounds.getHeight() * i - 9 * i;double baseY = y + ascent;/** 防止生成的文字带有锯齿 * */g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);/** 在图片上生成文字 * */g2.drawString(str, (int) x, (int) baseY);i--;}//todo 放置尾部logoResponse response = fileUploadFeignService.getFileInputStream("img/logopng.png");BufferedImage tailImage = ImageIO.read(response.body().asInputStream());//缩小图片尺寸g2.drawImage(tailImage, (width - tailImage.getWidth() / 3) / 2 + 5, 1400, tailImage.getWidth() / 3, tailImage.getHeight() / 3, null);int c = bi.getRGB(999, 1100);BufferedImage tmpImg = new BufferedImage(width, height,BufferedImage.TYPE_4BYTE_ABGR);//新建一个类型支持透明的BufferedImagefor(int k = 0; k < width; ++k)//把原图片的内容复制到新的图片,同时把背景设为透明{for(int j = 0; j < height; ++j){//把背景设为透明if(bi.getRGB(k, j) == c){tmpImg .setRGB(k, j, c & 0x00ffffff);}//设置透明度else{int rgb = tmpImg .getRGB(k, j);rgb = ((10 * 255 / 10) << 24) | (rgb & 0x00ffffff);tmpImg .setRGB(k, j, rgb);}}}g2.dispose();ImageIO.write(tmpImg, "PNG", outputStream1);Base64.Encoder encoder = Base64.getEncoder();String text = encoder.encodeToString(outputStream1.toByteArray());return text;} catch (WriterException e) {e.printStackTrace();return "";} catch (IOException e) {e.printStackTrace();return "";} finally {try {if (outputStream != null) {outputStream.close();}if (in != null) {in.close();}if (outputStream1 != null) {outputStream1.close();}} catch (IOException e) {e.printStackTrace();}}}

content:二维码内容

arr:二维码图片上要显示的内容

//todo 放置尾部logo
Response response = fileUploadFeignService.getFileInputStream("img/logopng.png");

 3、controller调用‘

public AjaxResult getInfo(){AjaxResult ajax = AjaxResult.success();ajax.put("img", "data:image/png;base64," + buildQRCode(qrCodeContent, qrCodeMessage.toArray(new String[qrCodeMessage.size()])));}return ajax;}

二、vue页面

1、vue弹出二维码页面

<el-dialog :title="title" :visible.sync="openLabel" :close-on-click-modal="false"><el-form ref="form" :model="form" :rules="rules" label-width="120px"><el-row v-show="false"><el-col><el-form-item label="电子标签码" prop="electronicLabelCode"><el-input v-model="form.electronicLabelCode" placeholder="请输入电子标签码" :disabled="isDisabled"/></el-form-item></el-col></el-row><el-row><el-col><el-form-item prop="file" ref="uploadElement" label="二维码"><el-uploadclass="avatar-uploader"action="#":show-file-list="false":disabled="true"><el-image v-if="dangerousImageUrl" :src="dangerousImageUrl" class="avatar"><div slot="error" class="image-slot"><i class="el-icon-picture-outline"></i></div></el-image><i v-else class="el-icon-plus avatar-uploader-icon"></i></el-upload></el-form-item></el-col></el-row><el-row><el-col :span="24"><el-form-item label=""><el-link @click="downloadQRCode" :disabled="isDisabled">下载二维码图片</el-link></el-form-item></el-col></el-row></el-form><div slot="footer" class="dialog-footer"><el-button type="primary" @click="submitForm" v-if="!isDisabled" v-show="false">保 存</el-button><el-button @click="cancel">取 消</el-button></div></el-dialog>

dangerousImageUrl :

        请求后端接口响应

                this.dangerousImageUrl = response.img;

2、二维码图片下载

//二维码图片下载downloadQRCode() {let aLink = document.createElement('a');let blob = this.base64ToBlob(this.dangerousImageUrl); //new Blob([content]);let evt = document.createEvent("HTMLEvents");evt.initEvent("click", true, true);//initEvent 不加后两个参数在FF下会报错  事件类型,是否冒泡,是否阻止浏览器的默认行为aLink.download = "group_" + new Date().getTime() + ".png";aLink.href = URL.createObjectURL(blob);// aLink.dispatchEvent(evt);aLink.click();},base64ToBlob(code) {let parts = code.split(';base64,');let contentType = parts[0].split(':')[1];let raw = window.atob(parts[1]);let rawLength = raw.length;let uInt8Array = new Uint8Array(rawLength);for (let i = 0; i < rawLength; ++i) {uInt8Array[i] = raw.charCodeAt(i);}return new Blob([uInt8Array], { type: contentType });},

三、data: image/png; base64 用法详解

data:image/png;base64, 字符串... 这个表示什么意思,又有什么作用呢?
其实这就是所谓的 Data URI scheme。 直译过来的意思是:URI 数据处理方案...

1. Data URI scheme 是什么 ?

1)Data URI scheme 是在 RFC2397 中定义的,目的是将一些小的数据,直接嵌入到网页中,从而不用再从外部文件载入。减少对 HTTP 的请求次数。达到优化网页的效果。

2)base64 后面那一串字符,其实是一张图片,将这些字符串复制粘贴到浏览器的中打开,就能看到图片了

2. Data URI scheme 的语法

在上面的 Data URI scheme 中:

data 表示取得数据的协定名称;

image/png 是数据类型名称;

base64 是数据的编码方法,逗号后面就是这个image/png文件base64编码后的数据。

目前,Data URI scheme支持的类型有:

data: 文本数据
data: text/plain, ------- 文本数据
data: text/html, -------- HTML代码
data: text/html;base64, -------- base64编码的HTML代码
data: text/css, ---------- CSS代码
data: text/css;base64, ---------- base64编码的CSS代码
data: text/javascript, ------------ Javascript代码
data: text/javascript;base64, --------- base64编码的Javascript代码
data: image/gif;base64, ---------------- base64编码的gif图片数据
data: image/png;base64, -------------- base64编码的png图片数据
data: image/jpeg;base64, ------------- base64编码的jpeg图片数据
data: image/x-icon;base64, ---------- base64编码的icon图片数据

3. Data URI scheme 的优缺点

优点:

减少HTTP请求数,没有了TCP连接消耗和同一域名下浏览器的并发数限制。对于小文件会降低带宽。虽然编码后数据量会增加,但是却减少了http头,当http头的数据量大于文件编码的增量,那么就会降低带宽。 对于HTTPS站点,HTTPS和HTTP混用会有安全提示,而HTTPS相对于HTTP来讲开销要大更多,所以Data URI在这方面的优势更明显。可以把整个多媒体页面保存为一个文件。

缺点:

  1. 无法被重复利用,同一个文档多次被应用到同一内容中,数据被大量增加,消耗了下载时间。
  2. 无法被独自缓存,其包含文档重新加载时,它也要重新加载。
  3. 耗时,客户端需要重新解码和显示,增加消耗。
  4. 不支持数据压缩,base64编码会增加1/3大小,而urlencode后数据量会增加更多
  5. 不安全,不利于安全软件的过滤,同时也存在一定的安全隐患。

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

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

相关文章

leetcode2487.从链表中移除节点

文章目录 题目思路复杂度Code 题目 给你一个链表的头节点 head 。 移除每个右侧有一个更大数值的节点。 返回修改后链表的头节点 head 。 示例 1&#xff1a; 输入&#xff1a;head [5,2,13,3,8] 输出&#xff1a;[13,8] 解释&#xff1a;需要移除的节点是 5 &#xff0…

【C程序设计】C作用域

任何一种编程中&#xff0c;作用域是程序中定义的变量所存在的区域&#xff0c;超过该区域变量就不能被访问。C 语言中有三个地方可以声明变量&#xff1a; 在函数或块内部的局部变量在所有函数外部的全局变量在形式参数的函数参数定义中 让我们来看看什么是局部变量、全局变…

云盘扩容、云盘缩容

天翼云文档地址&#xff1a;https://www.ctyun.cn/document/10027696/10169558 1、输入 growpart命令&#xff0c;检查此云主机是否已安装growpart扩容工具。若出现图中回显信息&#xff0c;则说明已经安装&#xff0c;无需手动安装。 注意 若没有图示信息&#xff0c;请执行…

《PySpark大数据分析实战》-24.数据可视化图表介绍

&#x1f4cb; 博主简介 &#x1f496; 作者简介&#xff1a;大家好&#xff0c;我是wux_labs。&#x1f61c; 热衷于各种主流技术&#xff0c;热爱数据科学、机器学习、云计算、人工智能。 通过了TiDB数据库专员&#xff08;PCTA&#xff09;、TiDB数据库专家&#xff08;PCTP…

prometheus基本介绍

官网&#xff1a;https://prometheus.io/docs/introduction/overview/ 中文&#xff1a; https://www.prometheus.wang/ Prometheus 选择 Prometheus 并不是偶然&#xff0c;因为&#xff1a; • Prometheus 是按照 《Google SRE 运维之道》的理念构建的&#xff0c;具有实用…

WSL2-Ubuntu22.04子系统图形化界面搭建与远程桌面连接

提示&#xff1a;文中不提供WSL2子系统搭建步骤&#xff0c;假定子系统已建立好&#xff1a; 文章目录 检查WSL子系统状态图形化界面安装远程桌面连接可能遇到的相关问题xrdp状态异常远程桌面黑屏 检查WSL子系统状态 wsl -l -v如下图所示为正常 图形化界面安装 以此执行如下…

【管理篇 / 登录】❀ 06. macOS下使用USB配置线登录 ❀ FortiGate 防火墙

【简介】飞塔防火墙上都会配有CONSOLE接口&#xff0c;包装里都会配置一根USB配置线&#xff0c;通过这个接口和这根线&#xff0c;我们可以用命令的方式登录飞塔防火墙。随着苹果电脑的普及&#xff0c;我们来学习如何在macOS中使用USB配置线登录飞塔防火墙。 早期飞塔防火墙包…

Java学习路线第六篇:互联网生态(1)

这篇则分享Java学习路线第六part&#xff1a;互联网生态 恭喜你已经成功追到第六章节啦&#xff0c;要被自己的努力感动到了吧&#xff0c;而这节将承担起学完互联网生态的使命&#xff0c;本使命为单向契约&#xff0c;你可选择YES或者选择YES。 Linux Linux从入门到精通视…

淘宝商品类目接口API:获取淘宝商品分类类目信息

cat_get-获得淘宝分类详情 响应参数 名称类型必须示例值描述 info Mix0{"cid": 16, "parent_cid": 0, "name": "其他女装", "is_parent": "true", "status": "normal", "sort_order&q…

【UnityShader入门精要学习笔记】(3)章节答疑

本系列为作者学习UnityShader入门精要而作的笔记&#xff0c;内容将包括&#xff1a; 书本中句子照抄 个人批注项目源码一堆新手会犯的错误潜在的太监断更&#xff0c;有始无终 总之适用于同样开始学习Shader的同学们进行有取舍的参考。 文章目录 复习&#xff08;阶段性总结…

matlab如何标定相机内外参和畸变参数

关于内外参矩阵和畸变矩阵可以学习 https://blog.csdn.net/qq_30815237/article/details/87530011?spm1001.2014.3001.5506 在APP中找到 camera Calibrator 点击 Add Images&#xff0c;导入拍照图片。标定20张左右就够了&#xff0c;然后角度变一下&#xff0c;但不需要变太…

Jupyter Notbook+cpolar内网穿透实现公共互联网访问使用数据分析工作

​​ 文章目录 1.前言2.Jupyter Notebook的安装2.1 Jupyter Notebook下载安装2.2 Jupyter Notebook的配置2.3 Cpolar下载安装 3.Cpolar端口设置3.1 Cpolar云端设置3.2.Cpolar本地设置 4.公网访问测试5.结语 ​​​​ 1.前言 在数据分析工作中&#xff0c;使用最多的无疑就是各…

【C# 使用selenium组件操作浏览器并且截图】

1.背景 需要完成一个统计报表的定时推送功能&#xff0c;所有定时打开统计报表界面进行截图。在网上找了一圈&#xff0c;最后决定使用selenium组件进行操作浏览器。 2.代码 using OpenQA.Selenium.Edge; using OpenQA.Selenium; using System; using System.Collections.Gen…

代码随想录算法训练营第五十三天|1143.最长公共子序列、1035.不相交的线、53.最大子序和(动态规划)

代码随想录 (programmercarl.com) 1143.最长公共子序列 与718的区别在于本题不需要是连续的&#xff0c;可以是在【不改变字符的相对顺序的情况下删除某些字符&#xff08;也可以不删除任何字符&#xff09;后组成的新字符串】 1.dp数组及下标含义 dp[i][j]&#xff1a;长度…

python pillow(PIL)库使用介绍

Python 图像库向 Python 解释器添加了图像处理功能。 该库提供了广泛的文件格式支持、高效的内部表示和相当强大的图像处理功能。 核心图像库旨在快速访问以几种基本像素格式存储的数据。它应该为通用图像处理工具提供坚实的基础。 概述 Python 图像库将图像处理功能添加到…

太阳光模拟器|百科

太阳光模拟器的功率 太阳光模拟器是一种能够模拟太阳光谱的仪器&#xff0c;它的功率对于太阳能行业来说至关重要。本文将从六个方面对太阳光模拟器的功率进行详细阐述&#xff0c;包括功率的定义、功率的计算、功率的影响因素、功率的调节方法、功率的应用以及未来的发展方向…

2024北京新能源电池及技术设备展-推动电池产业的持续发展

2024北京新能源电池及技术设备展-推动电池产业的持续发展 2024中国&#xff08;北京&#xff09;国际新能源电池技术及设备展览会 时间&#xff1a;2024年7月17-19日 地点&#xff1a;中国国际展览中心&#xff08;顺义馆&#xff09; 展会概况 受益于政策的支持&#xff0…

数据库选择题 (期末复习)

数据库第一章 概论简答题 数据库第二章 关系数据库简答题 数据库第三章 SQL简答题 数据库第四第五章 安全性和完整性简答题 数据库第七章 数据库设计简答题 数据库第九章 查询处理和优化简答题 数据库第十第十一章 恢复和并发简答题 2015期末 1、在数据库中&#xff0c;下列说…

Typescript---webpack和Babel的使用 03

webpack 通常情况下&#xff0c;实际开发中我们都需要使用构建工具对代码进行打包&#xff0c;TS同样也可以结合构建工具一起使用&#xff0c;下边以webpack为例介绍一下如何结合构建工具使用TS。 步骤&#xff1a; 初始化项目 进入项目根目录&#xff0c;执行命令 npm init -…

代码随想录算法训练营第二十三天 | 669. 修剪二叉搜索树、 108.将有序数组转换为二叉搜索树、 538.把二叉搜索树转换为累加树

669. 修剪二叉搜索树 题目链接&#xff1a;669. 修剪二叉搜索树 给你二叉搜索树的根节点 root &#xff0c;同时给定最小边界low 和最大边界 high。通过修剪二叉搜索树&#xff0c;使得所有节点的值在[low, high]中。修剪树 不应该 改变保留在树中的元素的相对结构 (即&#…