uni-app移动端使用uni-file-picker上传图片时通过canvas添加拍摄时间等水印信息

news2024/11/18 3:28:56

实现效果:

添加的照片添加水印信息

实现方式:

将添加水印的方法抽离成组件,为Vue文件,方便复用,在父组件中直接引用即可实现水印效果。

子组件:waterMarker.vue   

此为添加水印的组件文件,实现了在图片中添加水印,本示例在图片中添加了拍摄人、拍摄时间和拍摄经纬度的水印信息,其中拍摄人是从缓存中获取,拍摄时间为实时时间,拍摄经纬度根据mapbox获取当前位置信息的方法获取。此处展示的水印信息可根据个人需求灵活调整,如字体大小、字体颜色、背景颜色等,均支持自定义。

<template>
	<canvas v-if="waterMarkParams.display" canvas-id="waterMarkCanvas" :style="canvasStyle" />
</template>
<script>
	export default {
		data() {
			return {
				userLocation: {
					lng: 124.066873,
					lat: 40.45218,
				}, // 地图图标的默认位置--凤城市市政府
				waterMarkParams: {
					display: false, // 控制 canvas 创建与销毁
					canvasWidth: 300, // 默认宽度
					canvasHeight: 225, // 默认高度
					contentHeight: 170, // 将要被绘制到图像中的矩形的高度(px)
				},
				username: "YourUsername", // 假设的用户名
			}
		},
		computed: {
			// 画布
			canvasStyle() {
				return {
					position: "fixed", // 移除到屏幕外
					left: "9999px",
					width: this.waterMarkParams.canvasWidth + "px",
					height: this.waterMarkParams.canvasHeight + "px",
				};
			},
		},
		mounted() {
			this.getUserLocation(); // 获取当前所在位置
		},
		methods: {
			// 因为有可能在相册中选择多个图片,所以这里要依次生成水印
			async callAddWaterMark(imgPathArr) {
				let results = [];
				if (imgPathArr.length > 0) {
					let addIndex = 0;
					while (addIndex < imgPathArr.length) {
						const tempFilePath = await this.addWaterMark(imgPathArr[addIndex]);
						results.push(tempFilePath);
						addIndex = addIndex + 1;
					}
				}
				return results;
			},
			// 添加水印
			addWaterMark(src) {
				return new Promise((resolve, reject) => {
					// 获取图片信息,配置 canvas 尺寸
					uni.getImageInfo({
						src,
						success: (res) => {
							// 修复部分手机(如红米9)手机屏幕比较窄拍摄出来的图片水印压缩着覆盖的问题
							this.waterMarkParams.canvasWidth = Math.max(res.width, 886);
							this.waterMarkParams.canvasHeight = res.height;
							this.waterMarkParams.display = true;
							console.log("当前图片信息waterMarkParams:", this.waterMarkParams);
							// 等待 canvas 元素创建
							this.$nextTick(() => {
								let context = uni.createCanvasContext("waterMarkCanvas", this);
								/* 绘制 */
								const {
									canvasWidth,
									canvasHeight,
									contentHeight
								} =
								this.waterMarkParams;
								// 绘制前清空画布
								context.clearRect(0, 0, canvasWidth, canvasHeight);
								// 将图片src放到cancas内,宽高必须为图片大小
								context.drawImage(
									src,
									0,
									0,
									canvasWidth,
									canvasHeight,
									canvasWidth,
									canvasHeight
								);
								// 设置边框的透明度
								context.setGlobalAlpha(0.3);
								context.beginPath();
								// 绘制底部的白色背景
								context.rect(
									0,
									canvasHeight - contentHeight,
									canvasWidth,
									contentHeight
								);
								// context.setFillStyle("white"); // 白色背景
								context.fill();
								// 设置文字的透明度
								context.setGlobalAlpha(1);
								// 3.绘制底部的文字
								context.setFontSize(32);
								context.setTextAlign("left");
								context.setFillStyle("white"); // 显示字为白色
								context.fillText(`拍摄人:${this.username}`, 50, canvasHeight -
									120);
								context.fillText(
									`拍摄时间:${this.$u.timeFormat(
                  new Date(),
                  "yyyy-mm-dd hh:MM:ss"
                )}`,
									50,
									canvasHeight - 70
								);
								context.fillText(
									`拍摄定位:${this.userLocation.lng},${this.userLocation.lat}`,
									50,
									canvasHeight - 20
								);
								// 一定要加上一个定时器否则进入到页面第一次可能会无法正常拍照,后几次才正常
								setTimeout(() => {
									// 本次绘画完重开开始绘画,并且在绘画完毕之后再保存图片,不然页面可能会出现白屏等情况
									context.draw(false, () => {
										console.log("!!!!!开始绘画", canvasWidth,
											canvasHeight);
										uni.canvasToTempFilePath({
												canvasId: "waterMarkCanvas",
												fileType: "jpg",
												width: canvasWidth,
												height: canvasHeight,
												destWidth: canvasWidth,
												destHeight: canvasHeight,
												success: ({
													tempFilePath
												}) => {
													console.log("绘制成功",
														tempFilePath
													);
													this.waterMarkParams
														.display =
														false;
													resolve(
														tempFilePath
													);
												},
												fail: (err) => {
													reject(err);
													console.log(err);
												},
											},
											this
										);
									});
								}, 1000);
							});
						},
					});
				});
			},
			// 获取用户手机当前位置
			getUserLocation() {
				uni.getLocation({
					type: "wgs84",
					success: (res) => {
						this.userLocation = {
							lng: res.longitude,
							lat: res.latitude,
						};
					},
				});
				this.username = uni.getStorageSync("username"); // 获取localStrorage中的用户名信息
			},
		},
	}
</script>

父组件:使用子组件

父组件中,使用的uni-file-picker进行图片的上传,支持拍摄和本地图库上传,在上传时,通过@select方法,为图片添加水印,添加水印后调用了后端提供的上传接口,这样回显的图片也将是有水印的图片,后端接口这块可根据个人需求灵活变化。

<template>

<view class="upload-text">上传照片</view>
					<view style="width: 400rpx; min-height: 100rpx">
						<uni-file-picker :value="arr" @delete="fileDelete($event)" @select="chooseImage($event)"
							:auto-upload="false" return-type="array" file-extname="png,jpg" limit="3"
							fileMediatype="image" mode="grid" title="最多选择3张图片上传"></uni-file-picker>
					</view>
					<!-- 上报的图片添加水印 -->
					<WaterMarker ref="waterMarker"/>
</template>

<script>
	import WaterMarker from '@/components/mapbox/waterMarker.vue'
	import {
		uploadFiles
	} from "@/api/uploadWaterMarker.js";
export default {
		data() {
			return {
arr: [],
				arrWaterMark: [],
               }
},
components: {
			WaterMarker
		},
methods: {
// 图片--上传图片
			async chooseImage(e) {
				const imgFileArr = await this.$refs.waterMarker.callAddWaterMark(e.tempFilePaths);
				imgFileArr.forEach((el) => {
					this.arr.push({
						url: el,
						extname: el.substring(el.lastIndexOf(".") + 1),
						name: el,
					});
				});
// 此处为调用后端接口,可根据个人情况灵活变化
				let res = await uploadFiles(imgFileArr);
				res.forEach((el) => {
					this.arrWaterMark.push({
						url: service_file + el.data,
						extname: el.data.substring(el.data.lastIndexOf(".") + 1),
						name: el.data,
					});
				});
			},
// 图片--删除照片
			fileDelete(err) {
				this.arr = this.arr.filter((item) => item !== err.tempFile);
			},
// 图片预览
			preview(item, index) {
				uni.previewImage({
					current: index,
					urls: item.map((o) => o.url),
				});
			},
},
}
</script>

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

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

相关文章

Keil移植库文件的方法

创建新的文件夹&#xff0c;并且添加已存在的文件&#xff1a; 点击小锤子按钮选择下图所示的界面&#xff1a; 为编译器指明编译路径&#xff1a;

【JS逆向百例】某点数据逆向分析,多方法详解

前言 最近收到粉丝的私信&#xff0c;其在逆向某个站点时遇到了些问题&#xff0c;在查阅资料未果后&#xff0c;来询问K哥&#xff0c;K哥一向会尽力满足粉丝的需求。网上大多数分析该站点的教程已经不再适用&#xff0c;本文K哥将提供 3 种解决方案&#xff0c;对于 webpack…

「51媒体」时尚类媒体邀约宣发资源

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 时尚类媒体邀约宣发资源可以多样化且针对性地满足品牌或活动的推广需求。以下是一些主要的资源及其特点&#xff1a; 时尚杂志&#xff1a;国内外知名时尚杂志&#xff0c;如《Vogue》、…

2024.6.24 IDEA中文乱码问题(服务器 控制台 TOMcat)实测已解决

1.问题产生原因&#xff1a; 1.文件编码不一致&#xff1a;如果文件的编码方式与IDEA设置的编码方式不一致&#xff0c;就会产生乱码。确保文件和IDEA使用相同的编码&#xff0c;通常是UTF-8。2.IDEA设置问题&#xff1a;检查IDEA的全局编码设置和项目编码设置是否正确。3.终端…

晨持绪科技:开好一家抖音小店运营怎么做

在数字时代&#xff0c;抖音小店以其独特的社交媒体优势迅速崛起&#xff0c;成为许多创业者的新宠。但如何有效运营&#xff0c;却是一门学问。首要任务是确定你的小店定位&#xff0c;这关系到后续的产品选择、目标客户群及营销策略。定位明确后&#xff0c;接下来便是挑选适…

智慧环保一体化平台登录

据悉&#xff0c;在当今这个数字化、智能化的时代&#xff0c;环境保护工作也需要与时俱进&#xff0c;不断创新。朗观视觉智慧环保一体化平台应运而生&#xff0c;它利用先进的信息技术手段&#xff0c;为环保工作提供了更加便捷、高效的管理方式&#xff0c;成为推动绿色发展…

对的礼物送给对的人,送礼物的技巧和学问

一、教程描述 无论是商务往来&#xff0c;还是求人办事&#xff0c;送礼都是不可或缺的一种交际手段。想要建立好的人脉关系网&#xff0c;想要把事儿办成&#xff0c;一定要把对的礼物送给对的人&#xff0c;否则必是竹篮打水一场空。送礼是一门学问&#xff0c;同时&#xf…

Kubernetes排错(十)-处理容器数据磁盘被写满

容器数据磁盘被写满造成的危害: 不能创建 Pod (一直 ContainerCreating)不能删除 Pod (一直 Terminating)无法 exec 到容器 如何判断是否被写满&#xff1f; 容器数据目录大多会单独挂数据盘&#xff0c;路径一般是 /var/lib/docker&#xff0c;也可能是 /data/docker 或 /o…

FLASH仿真EEPROM---基于智芯Z20K11XM

一、介绍 电可擦和可编程只读存储器(EEPROM)可以对字节或字编程和擦除。EEPROM中的数据即使断电也能保持&#xff0c;但Z20K1xx芯片不含EEPROM。然而&#xff0c;闪存可以通过EEPROM仿真软件来模拟EEPROM。Z20K1xx包含两个flash阵列。编程和擦除操作可以在一个数组上进行&#…

Spring注解源码解析

一、Spring IOC常用注解 1、用于Bean申明的注解 2、用于定义Bean配置的注解 3、其他用途的注解 二、基于注解容器AnnotationConfigApplicationContext AnnotationConfigApplicationContext的其中一个构造方法&#xff0c;传入Java config类&#xff0c;refresh过程实例化Bean…

大模型时代下的技术变革:训练、负载、部署、效率、安全……都遇到了新挑战?

随着互联网的快速发展&#xff0c;AI 大模型算的上是当前行业里最“炽手可热”的技术&#xff0c;大模型是 AI 领域的重要发展趋势。大模型需要大量的数据和计算资源&#xff0c;同时也需要强大的应用场景支持&#xff0c;对各行各业都有深远的影响&#xff0c;各厂商开始了“千…

Excel 宏录制与VBA编程 —— 11、工作表及工作簿操作(附:Worksheets与Sheets区别)

代码1 - Worksheets与Sheets区别 Worksheets表示普通工作表;Sheets即可表示普通工作表也可表示图标工作表。 下面模块中代码结果是一样的,大家理解时可结合上面区别说明进行了解 Sub Test()Worksheets("Sheet1").Range("A1").Value 100Sheets("Sheet…

农业四情监测设备——提高农业生产的效率和质量

TH-Q1农业四情监测设备是用于实时监测农业领域的四大关键监测内容的设备&#xff0c;这些内容包括土壤墒情、苗情、病虫情和灾情。以下是关于农业四情监测设备的详细介绍&#xff1a; 主要用于实时测量农田土壤的水分状况。包含土壤湿度传感器、土壤温度传感器等&#xff0c;安…

如何处理优化这个慢查询——Java全栈知识(27)

2 、如何处理优化这个慢查询 如何定位慢查询&#xff1a;1、如何定位慢查询 explain 计划 面试官&#xff1a; 那这个 SQL 语句执行很慢, 如何分析呢&#xff1f; 候选人&#xff1a; 如果一条 sql 执行很慢的话&#xff0c;我们通常会使用 mysql 自动的执行计划 explain 来…

电磁场与电磁波作业题及解析

目录 第一章 1.5 1.8 1.11 1.21 第二章 2.4 2.13 2.27 第三章 3.7 3.8 3.17 3.18 第四章 4.2 4.16 第五章 5.2 第六章 6.9 6.30 第七章 7.3 第一章 1.5 1.8 1.11 1.21 第二章 2.4 2.13 2.27 第三章 3.7 3.8 3.17 3.18 第四章 4.2 4.16 第五章 5.2…

【Python新手入门指南】Linux-conda环境安装与使用参考

文章目录 前言一、conda是什么&#xff1f;二、安装步骤三、使用Conda来管理Python环境1. 创建环境2. 激活环境3. 安装软件包4. 查看环境5. 删除环境&#xff1a;如果您不再需要某个环境&#xff0c;可以使用以下命令将其删除&#xff1a; 前言 如果你是一位经验丰富的Python开…

Windwos +vs 2022 编译openssl 1.0.2 库

一 前言 先说 结论&#xff0c;编译64位报错&#xff0c;查了一圈没找到解决方案&#xff0c;最后换了32位的。 使用qt访问web接口&#xff0c;因为是https&#xff0c;没有openssl库会报错 QNetworkReply* reply qobject_cast<QNetworkReply*>(sender());if (reply){…

开放式耳机哪种好用又实用?开放式耳机必入品牌推荐,内行人分享

随着数码技术的不断推出各种各样的新产品&#xff0c;开放式耳机已经逐渐成为有份音乐发烧友的选择&#xff0c;这类耳机从早期的简单音质发展至今日的高解析度&#xff0c;其技术进步&#xff0c;也吸引了一大批开放式耳机的爱好者&#xff0c;开放式耳机以其开放式的设计&…

分布式光纤测温DTS如何与第三方数据对接?

分布式光纤测温DTS与第三方数据对接可以采用多种方式和接口。常见的接口包括RS485、RJ45网口、继电器接口和RS232接口等&#xff0c;而协议种类更是多达几十种之多。主流的协议包括modbusRTU、modbusTCP、点表协议、南网协议、电力json协议、IEC104和61850协议等。根据不同的需…

巧用SOLIDWORKS进行复杂曲面模型的实体建模

SOLIDWORKS正版软件有实体建模、曲面建模、钣金建模、焊件建模、模具建模等多种建模方式&#xff0c;每种建模方式都有独特的使用环境和场景&#xff0c;如果能灵活使用这些建模命令&#xff0c;就可以起到事半功倍的效果。 如上图所示的模型&#xff0c;通过观察和分析&#x…