【uni-app】压缩图片并添加水印

总体思路

在这里插入图片描述

dom 结点

这里的 cvHeightcvWidth 初始时要设置为你后续需要压缩后的最大宽高。假设我们在图片上传后图片最大为 350 * 350

<u-upload :fileList="baseInfoFormData.entrustFileList" @afterRead="afterFileRead" multiple></u-upload>
<!-- 添加水印虚拟结点 -->
<view style="width: 0px; height: 0px; overflow: hidden"><canvas canvas-id="cid3" :style="{height: `${canvasSize.cvHeight}px`,width: `${canvasSize.cvWidth}px`,}"></canvas>
</view>

获取原本图片的宽高

这是一个用于获取图片尺寸的异步函数。它接受一个图片的URL作为参数,并返回一个Promise对象。
这个函数的作用是加载指定URL的图片,获取其宽度和高度,并将它们包装在一个对象中返回。

getImageSizeByUrl(url) {return new Promise((resolve, reject) => {// 创建一个新的Image对象,用于加载图片。const img = new Image();// 设置图片的src属性为传入的URL,以开始加载图片。img.src = url;// 当图片加载完成时,会触发onload事件。img.onload = function() {// 在加载成功时,通过resolve函数将图片的宽度和高度以对象的形式传递出去。resolve({width: img.width,height: img.height,});};// 当图片加载失败时,会触发onerror事件。img.onerror = function() {// 在加载失败时,通过reject函数返回一个带有错误信息的Error对象。reject(new Error("getImageSizeByUrl 加载图片失败"));};});
},

得到按比例压缩后的宽高

如果最长边大于350,计算缩放比例.如果最长边不大于350,直接返回原始尺寸。这里的350,就是最初始的 cvHeightcvWidth ,数值需要对应!

scaleImage(width, height) {return new Promise((resolve, reject) => {// 找到较长的一边const maxSide = Math.max(width, height);// 如果最长边大于350,计算缩放比例if (maxSide > 350) {const scale = 350 / maxSide;// 使用缩放比例来调整图片的长宽const newWidth = Math.round(width * scale);const newHeight = Math.round(height * scale);resolve({width: newWidth,height: newHeight,});} else {// 如果最长边不大于350,直接返回原始尺寸resolve({width,height,});}});
},

核心添加水印方法

这是一个用于在图片上添加水印并将结果绘制到 canvas 上的异步函数。
它接受一个图片的URL、图片的宽度和高度作为参数,并返回一个Promise对象。

imgToCanvas(url, width, height) {return new Promise((resolve, reject) => {// 使用 uni.createCanvasContext 创建一个 Canvas 2D 渲染上下文,参数为在 DOM 元素中定义的 canvas 元素的 id(cid3)。const ctx = uni.createCanvasContext("cid3");// 在 Canvas 上使用 drawImage 方法绘制图片,从指定的 URL 加载图片,并设置宽度和高度。ctx.drawImage(url, 0, 0, width, height);// 设置水印的大小和样式。ctx.setFontSize(width / 10); // 设置字体大小为图片宽度的十分之一。ctx.setFillStyle("rgba(150,150,150,0.2)"); // 设置水印的颜色和透明度。// 添加两行水印文字。// 第一行水印,居中显示在图片上半部分。ctx.fillText("长沙市老年人居家",width / 2 - (width / 10) * 4,height / 2 - parseInt(width / 10 / 3) - width / 10 / 10 - 10);// 第二行水印,居中显示在图片下半部分。ctx.fillText("适老化改造业务专用",width / 2 - (width / 10) * 4 - width / 10 / 2,height / 2 + parseInt((width / 10 / 3) * 2) + width / 10 / 10 + 10);// 使用 ctx.draw 方法将绘制的内容显示在 Canvas 上。// 第一个参数为 false,表示此次绘制不清空之前的内容。// 在绘制完成后,调用 uni.canvasToTempFilePath 将 Canvas 转换为临时文件路径。ctx.draw(false, () => {uni.canvasToTempFilePath({canvasId: "cid3", // 指定要转换的 Canvas 的 id。fileType: "jpg", // 指定要生成的图片文件类型。success: (res) => {// 在转换成功时,通过 resolve 函数返回生成的图片的临时文件路径。resolve(res.tempFilePath);},fail: (err) => {// 在转换失败时,通过 reject 函数返回错误信息。reject(err);},});});});
},

整合图片处理方法

async imageAddWatermarks(url) {try {const {width,height} = await this.getImageSizeByUrl(url);const scaledImage = await this.scaleImage(width, height);this.$set(this.canvasSize, "cvWidth", scaledImage.width);this.$set(this.canvasSize, "cvHeight", scaledImage.height);let waterUrl = await this.imgToCanvas(url, this.canvasSize.cvWidth, this.canvasSize.cvHeight);// 重置画布大小,否则会有显示不全的问题this.$set(this.canvasSize, "cvWidth", 350);this.$set(this.canvasSize, "cvHeight", 350);return waterUrl;} catch (error) {console.error(error);}
},

上传图片类型检测

这是一个用于检测上传的图片文件格式的函数。它接受一个文件名列表作为参数,并返回一个 Promise 对象。
函数的目的是检查上传的文件是否属于支持的图片格式(.jpg、.jpeg、.png)。

checkImageFiles(filenames) {// 定义支持的图片文件格式。const imageExtensions = ['.jpg', '.jpeg', '.png'];// 创建一个 Promise 数组,对每个文件进行格式检查。const promises = filenames.map(file => {return new Promise((resolve, reject) => {// 获取文件名的小写形式,并提取出文件扩展名。const fileExtension = file.name.toLowerCase().substring(file.name.lastIndexOf('.'));// 检查文件扩展名是否在支持的图片格式列表中。if (imageExtensions.includes(fileExtension)) {// 如果是支持的格式,通过 resolve 函数返回 true。resolve(true);} else {// 如果不是支持的格式,通过 reject 函数返回错误信息。reject('格式错误!请上传 jpg 或 png 图片');}});});// 使用 Promise.all 来等待所有的检查 Promise 完成。return Promise.all(promises);
},

参考代码

以下代码是配合 uView 框架实现的,用作参考即可

<u-upload :fileList="baseInfoFormData.entrustFileList" @afterRead="afterFileRead" @delete="deletePic" :name="entrustFile.name" multiple :maxCount="entrustFile.maxCount" :previewFullImage="true" width="163" height="102" :deletable="true"><view class="u-flex u-flex-center u-flex-items-center photo-con"><u-image width="18" height="18" src="@/static/applicant/upAdd.png"></u-image><view class="up-txt">{{ entrustFile.upTxt }}</view></view>
</u-upload>
<!-- 添加水印虚拟结点 -->
<view style="width: 0px; height: 0px; overflow: hidden"><canvas canvas-id="cid3" :style="{height: `${canvasSize.cvHeight}px`,width: `${canvasSize.cvWidth}px`,}"></canvas>
</view>
async afterFileRead(event) {try {let lists = [].concat(event.file)let fileListLen = this.baseInfoFormData.entrustFileList.lengthawait this.checkImageFiles(lists)// 添加水印,获得处理后的urlfor (const item of lists) {let waterUrl = await this.imageAddWatermarks(item.url);item.url = waterUrlitem.thumb = waterUrlthis.baseInfoFormData.entrustFileList.push({...item,status: 'uploading',message: '上传中'});}// 将添加完水印的图片上传至统一存储for (let i = 0; i < lists.length; i++) {const imgInfo = await this.uploadFilePromise(lists[i].url);const imgSrc = imgInfo.imgSrcconst fileId = imgInfo.fileIdlet item = this.baseInfoFormData.entrustFileList[fileListLen];this.baseInfoFormData.entrustFileList.splice(fileListLen,1,Object.assign(item, {message: "已上传",status: "success",url: imgSrc,thumb: imgSrc,}));this.baseInfoFormData.ahap7744 = fileIdfileListLen++;}} catch (e) {uni.$u.toast(e)}
},
uploadFilePromise(url) {return new Promise((resolve, reject) => {uni.uploadFile({url: config.basePath + config.interfaceConfig["uploadSLHFile"],filePath: url,name: "file",formData: {azzx0025: this.getWxuuid(),businessLevel: 1,azzx0040: "slh",azzx0063: "01",},success: (res) => {const result = JSON.parse(res.data);const fileId = result.data.resultData.fileId;const imgSrc = this.$url_config.fileBasePath + fileId;const imgInfo = {fileId,imgSrc}resolve(imgInfo);},});});
},
async imageAddWatermarks(url) {try {const {width,height} = await this.getImageSizeByUrl(url);const scaledImage = await this.scaleImage(width, height);this.$set(this.canvasSize, "cvWidth", scaledImage.width);this.$set(this.canvasSize, "cvHeight", scaledImage.height);let waterUrl = await this.imgToCanvas(url, this.canvasSize.cvWidth, this.canvasSize.cvHeight);// 重置画布大小,否则会有显示不全的问题this.$set(this.canvasSize, "cvWidth", 350);this.$set(this.canvasSize, "cvHeight", 350);return waterUrl;} catch (error) {console.error(error);}
},
getImageSizeByUrl(url) {return new Promise((resolve, reject) => {const img = new Image();img.src = url;img.onload = function() {resolve({width: img.width,height: img.height,});};img.onerror = function() {reject(new Error("getImageSizeByUrl 加载图片失败"));};});
},
// 如果最长边大于350,计算缩放比例.如果最长边不大于350,直接返回原始尺寸
scaleImage(width, height) {return new Promise((resolve, reject) => {// 找到较长的一边const maxSide = Math.max(width, height);// 如果最长边大于350,计算缩放比例if (maxSide > 350) {const scale = 350 / maxSide;// 使用缩放比例来调整图片的长宽const newWidth = Math.round(width * scale);const newHeight = Math.round(height * scale);resolve({width: newWidth,height: newHeight,});} else {// 如果最长边不大于350,直接返回原始尺寸resolve({width,height,});}});
},
imgToCanvas(url, width, height) {return new Promise((resolve, reject) => {const ctx = uni.createCanvasContext("cid3"); //在dom元素中定义了一个不显示的canvas元素ctx.drawImage(url, 0, 0, width, height);// 设置水印的大小,位置ctx.setFontSize(width / 10);ctx.setFillStyle("rgba(150,150,150,0.2)");// 添加水印ctx.fillText("水印具体内容1",width / 2 - (width / 10) * 4,height / 2 - parseInt(width / 10 / 3) - width / 10 / 10 - 10);ctx.fillText("水印具体内容2",width / 2 - (width / 10) * 4 - width / 10 / 2,height / 2 + parseInt((width / 10 / 3) * 2) + width / 10 / 10 + 10);// 绘制到canvas上,返回加完水印的 base64 urlctx.draw(false, () => {uni.canvasToTempFilePath({canvasId: "cid3",fileType: "jpg",success: (res) => {resolve(res.tempFilePath);},fail: (err) => {reject(err);},});});});
},

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

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

相关文章

如何利用Python代码优雅的进行文件下载

如何利用Python代码优雅的进行文件下载 一、什么是wget&#xff1f;二、使用wget.exe客户端进行文件下载三、使用Python脚本进行文件下载 欢迎学习交流&#xff01; 邮箱&#xff1a; z…1…6.com 网站&#xff1a; https://zephyrhours.github.io/ 一、什么是wget&#xff1f;…

python web GUI框架-NiceGUI 教程(一)

python web GUI框架-NiceGUI 教程&#xff08;一&#xff09; streamlit可以在一些简单的场景下仍然推荐使用&#xff0c;但是streamlit实在不灵活&#xff0c;受限于它的核心机制&#xff0c;NiceGUI是一个灵活的web框架&#xff0c;可以做web网站也可以打包成独立的exe。 基…

linux安装部署gitlab全教程,包含配置中文

linux安装部署gitlab全教程&#xff0c;包含配置中文 大家好&#xff0c;我是酷酷的韩~ 1.前期准备 安装包下载地址 https://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/yum/el7/ 我这里选择的这个gitlab-ce-15.7.3-ce.0.el7.x86_64.rpm 还有一些相关依赖包(地址等审核过我放到…

YOLOv7-tracker 目标追踪 输入视频帧

目录 1 项目安装1.1 环境搭建1.2 项目下载1.3 权重下载1.4 环境安装1.5 上传待检测的视频帧 2 视频帧检测与追踪2.1 检测与追踪2.3 结果 参考项目&#xff1a;https://github.com/JackWoo0831/Yolov7-tracker/tree/master github链接&#xff1a;https://github.com/Whiffe/Yo…

【算法】经典的八大排序算法

点击链接 可视化排序 动态演示各个排序算法来加深理解&#xff0c;大致如下 一&#xff0c;冒泡排序&#xff08;Bubble Sort&#xff09; 原理 冒泡排序&#xff08;Bubble Sort&#xff09;是一种简单的排序算法&#xff0c;它通过多次比较和交换相邻元素的方式&#xff0c;将…

本地电脑搭建Plex私人影音云盘教程,内网穿透实现远程访问

文章目录 1.前言2. Plex网站搭建2.1 Plex下载和安装2.2 Plex网页测试2.3 cpolar的安装和注册 3. 本地网页发布3.1 Cpolar云端设置3.2 Cpolar本地设置 4. 公网访问测试5. 结语6 总结 1.前言 用手机或者平板电脑看视频&#xff0c;已经算是生活中稀松平常的场景了&#xff0c;特…

2023最新Python重点知识万字汇总

这是一份来自于 SegmentFault 上的开发者 二十一 总结的 Python 重点。由于总结了太多的东西&#xff0c;所以篇幅有点长&#xff0c;这也是作者"缝缝补补"总结了好久的东西。 **Py2 VS Py3** * print成为了函数&#xff0c;python2是关键字* 不再有unicode对象…

数据是如何存储在内存中的?听我慢慢道来

数据的存储 1. 前言2. 数据类型2.1 整形家族2.2 浮点数家族2.3 构造类型&#xff08;自定义类型&#xff09;2.4 指针类型2.5 空类型&#xff08;无类型&#xff09; 3. 整数在内存中的存储4. 大小端5. 浮点数在内存中的存储 1. 前言 大家好&#xff0c;我是努力学习游泳的鱼。…

美国纽约10日游

一、前言 我有两周断更了&#xff0c;原因是去纽约只顾着玩&#xff0c;没时间写&#xff0c;今天有时间正好和大家分享一下去纽约的攻略 二、以下是一个10天去美国纽约旅游的攻略&#xff0c;十万以内&#xff0c;包括机票、酒店、交通、餐饮和景点门票等费用&#xff1a; 第…

Linux —— nfs文件系统

简介 NFS 是Network File System的缩写&#xff0c;即网络文件系统。一种使用于分散式文件系统的协定&#xff0c;由Sun公司开发&#xff0c;于1984年向外公布。功能是通过网络让不同的机器、不同的操作系统能够彼此分享个别的数据&#xff0c;让应用程序在客户端通过网络访问位…

高通开发系列 - 5G网络之QTI守护进程服务介绍

By: fulinux E-mail: fulinux@sina.com Blog: https://blog.csdn.net/fulinus 喜欢的盆友欢迎点赞和订阅! 你的喜欢就是我写作的动力! 返回:专栏总目录 目录 代码位置和依赖关系功能介绍代码逻辑讲解外设节点关注的目录socket服务端初始化DPM客户端监听守护关键的数据结构体…

评估安全 Wi-Fi 接入:Cisco ISE、Aruba、Portnox 和 Foxpass

在当今不断变化的数字环境中&#xff0c;对 Wi-Fi 网络进行强大访问控制的需求从未像现在这样重要。各组织一直在寻找能够为其用户提供无缝而安全的体验的解决方案。 在本博客中&#xff0c;我们将深入探讨保护 Wi-Fi&#xff08;和有线&#xff09;网络的四种领先解决方案——…