【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.rhkb.cn/news/104948.html

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

相关文章

Netty简易聊天室

文章目录 本文目的参考说明环境说明maven依赖日志配置单元测试 功能介绍开发步骤 本文目的 通过一个简易的聊天室案例&#xff0c;讲述Netty的基本使用。同时分享案例代码。项目中用到了log4j2&#xff0c;junit5&#xff0c;同时分享这些基础组件的使用。项目中用到了awt&…

elementUI moment 年月日转时间戳 时间限制

changeStartTime(val){debuggerthis.startT val// this.startTime parseInt(val.split(-).join())this.startTime moment(val).unix() * 1000 //开始时间毫秒if(this.endTime){this.endTime moment(this.endT).unix() * 1000 //结束时间毫秒if(this.startTime - this.endTi…

Git gui教程---第七篇 Git gui的使用 返回上一次提交

1&#xff0e; 查看历史&#xff0c;打开gitk程序 2&#xff0e; 选中需要返回的版本&#xff0c;右键&#xff0c;然后点击Rest master branch to here 3.出现弹窗 每个选项我们都试一下&#xff0c;从Hard开始 返回的选项 HardMixedSoft Hard 会丢失所有的修改【此处的…

AMBA总线协议(0)——目录与传送门

一、AMBA总线协议 Arm高级微控制器总线架构&#xff08;Advanced Microcontroller Bus Architecture&#xff0c;AMBA&#xff09;是一种开放式标准片上互联规范&#xff0c;用于连接和管理片上系统&#xff08;System on Chip,Soc&#xff09;中的功能块。 AMBA是一种广泛用于…

车联网技术介绍

上图是目前车联网架构图&#xff0c;基于“云-管-端”的车联网系统架构以支持车联网应用的实现&#xff0c; “云”是指 V2X 基础平台、高基于精度定位平台等基础能力&#xff0c;可实现车辆动态厘米级定位&#xff0c;这将满足现阶段以及未来车联网应用场景的定位精度需求。 “…

计算机竞赛 基于LSTM的天气预测 - 时间序列预测

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 机器学习大数据分析项目 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非常推荐&#xff01; &#x1f9ff; 更多资料, 项目分享&#xff1a; https://gitee.com/dancheng-senior/po…

Jenkins 详细安装流程及填坑记录「图文」

目录 一、前言 二、环境准备 三、安装步骤 1、安装jdk 2、安装jenkins 3、配置修改 4、jenkins启动 四、登录jenkins 一、前言 省流&#xff1a;本文仅记录Jenkins详细安装过程&#xff0c;以及安装过程中经常遇到的问题。 二、环境准备 Linux系统&#xff1a;CentOS…

mysql的登录与退出

mysql是c/s架构&#xff0c;意味着同时要有客户端和服务端 1 找到客户端。mysql.exe的安装目录 打开命令行 2 输入对应的服务器的ip&#xff0c;如果是本地&#xff0c;就是Localhost&#xff0c;如果是远程服务器&#xff0c;那就输入对应ip/域名。并且指定mysql监听的端口 …

大数据(一)定义、特性

大数据&#xff08;一&#xff09;定义、特性 本文目录&#xff1a; 一、写在前面的话 二、大数据定义 三、大数据特性 3.1、大数据的大量 (Volume) 特性 3.2、大数据的高速(Velocity)特性 3.3、大数据的多样化 (Variety) 特性 3.4、大数据的价值 (value) 特性 3.5、大…

axios 进阶

axios 进阶 接口传参方式 使用 xhr 原生技术或者是 axios 时&#xff0c;它的 post 传参方式是键值对的形式 keyvalue。但是在实际开发中一般是使用对象的形式定义数据&#xff0c;方便读取和赋值。所以当我们需要发起请求时可以通过 qs 这一款插件将对象转成键值对形式&…

js实现定时器

用原生js实现一个倒计时效果.最下面有全部源码,需要自取 js语法: setTimeout:定时器 document.getElementById:Document的方法 getElementById()返回一个匹配特定 ID的元素。由于元素的 ID 在大部分情况下要求是独一无二的&#xff0c;这个方法自然而然地成为了一个高效查找特…

Easy Rules规则引擎(2-细节篇)

目录 一、序言二、规则引擎参数配置实例1、skipOnFirstAppliedRules示例(1) FizzRule(2) BuzzRule(3) FizzBuzzRule(4) NonFizzBuzzRule(5) FizzBuzzRulesLauncher 2、skipOnFirstNonTriggeredRule示例3、skipOnFirstFailedRule示例 三、组合规则1、UnitRuleGroup组合规则2、Ac…

Apache Doris 入门教程34:Join 优化

Bucket Shuffle Join Bucket Shuffle Join 是在 Doris 0.14 版本中正式加入的新功能。旨在为某些 Join 查询提供本地性优化&#xff0c;来减少数据在节点间的传输耗时&#xff0c;来加速查询。 它的设计、实现和效果可以参阅 上面的图片展示了Bucket Shuffle Join的工作原理…

idea使用tomcat

1. 建立javaweb项目 2. /WEB-INF/web.xml项目配置文件 如果javaweb项目 先建立项目&#xff0c;然后在项目上添加框架支持&#xff0c;选择javaee 3. 项目结构 4.执行测试&#xff1a;

【Java转Go】快速上手学习笔记(五)之Gorm篇

目录 go get命令1、go get命令无响应问题2、Unresolved dependency错误 连接数据库连接.gomain.go 操作数据库创建表新增数据更新数据删除数据查询数据单表查询多表查询 用到的数据库表原生SQL 完整代码 go往期文章笔记&#xff1a; 【Java转Go】快速上手学习笔记&#xff08;…

接口经典题目

​ White graces&#xff1a;个人主页 &#x1f649;专栏推荐:《Java入门知识》&#x1f649; &#x1f649; 内容推荐:继承与组合&#xff1a;代码复用的两种策略&#x1f649; &#x1f439;今日诗词:人似秋鸿来有信&#xff0c;事如春梦了无痕。&#x1f439; 目录 &…

剪枝基础与实战(3): 模型剪枝和稀疏化训练流程

Model Pruning 相关论文:Learning Efficient Convolutional Networks through Network Slimming (ICCV 2017) 考虑一个问题,深度学习模型里面的卷积层出来之后的特征有非常多,这里面会不会存在一些没有价值的特征及其相关的连接?又如何去判断一个特征及其连接是否有价值? …

Packet_Tracer的使用

一、实验目的&#xff1a; 通过该实验了解Packet Tracer的使用方法&#xff0c;能够用Packet Tracer建立和模拟网络模型。 二、主要任务&#xff1a; 1.熟悉PT的界面&#xff0c;了解按键用途。 2.尝试自己建立一个小型网络&#xff0c;并测试连通性。 3.学习P…

5.6.webrtc三大线程

那今天呢&#xff1f;我们来介绍一下web rtc的三大线程&#xff0c;那为什么要介绍这三大线程呢&#xff1f;最关键的原因在于web rtc的所有其他线程都是由这三大线程所创建的。那当我们将这三个线程理解清楚之后呢&#xff1f;我们就知道其他线程与它们之间是怎样关系&#xf…

stm32 之20.HC-06蓝牙模块

原理图显示使用usart3串口使用的是PB10和PB11引脚 直接配置usart3串口协议 void usart3_init(uint32_t baud) {GPIO_InitTypeDef GPIO_InitStructureure;USART_InitTypeDef USART_InitStructure;NVIC_InitTypeDef NVIC_InitStructure;//端口B硬件时钟打开RCC_AHB1PeriphClockC…