uni-app 实现图片上传添加水印操作

一、定义一个canvas标签,微信小程序的实现方式有所变动

	<!-- #ifdef MP-WEIXIN -->
	<canvas type="2d" id="upload-canvas" class="uploadCanvas" 
		:style="{'width':width+'px','height':height+'px','position':'absolute','z-index':'-999','left':'-1000000px'}"></canvas>
	<!-- #endif -->

	<!-- #ifdef H5 -->
	<canvas canvas-id="upload-canvas" class="uploadCanvas" 
		:style="{'width':width+'px','height':height+'px','position':'absolute','z-index':'-999','left':'-1000000px'}"></canvas>
	<!-- #endif -->

二、拿到图片后添加水印

addWatermark(fileUrl) {
			let that = this;
			return new Promise((resolve, reject) => {

				uni.getImageInfo({
					src: fileUrl, // 替换为你的图片路径
					success: async (res) => {
						console.log("res", res);
						const imageWidth = res.width;
						const imageHeight = res.height;
						that.width = imageWidth;
						that.height = imageHeight;
						await util.sleep(1000);
						// #ifdef MP-WEIXIN
						const query = wx.createSelectorQuery()
						query.select('#upload-canvas')
							.fields({
								node: true,
								size: true
							})
							.exec((resCanvas) => {
								let filePath = res.path;
								// 获取文件系统管理器
								const fs = uni.getFileSystemManager();
								// 读取图片文件为Base64编码
								fs.readFile({
									filePath: filePath,
									encoding: 'base64',
									success: function(res) {
										const base64Data = res.data;
										console.log("base64Data==",base64Data)
										const canvas = resCanvas[0].node
										canvas.width = that.width;
										canvas.height = that.height;
										const ctx = canvas.getContext('2d')
										let img = canvas
											.createImage(); // 注意是使用canvas实例 不是ctx
										img.src =
											`data:image/png;base64,${base64Data}`
										img.onload = () => {
											ctx.drawImage(img, 0, 0,that.width,that.height);
											ctx.font = '16px',
												ctx.fillStyle =
												'rgba(0, 0, 0, 1)';
											const lineHeight = 20; // 水印文字行高

											const lines = that.watermarkText
												.split('\n');
											const x = 10; // 水印左上角 x 坐标
											let y = 20; // 水印左上角 y 坐标

											lines.forEach((line) => {
												ctx.fillText(line, x,
													y);
												y += lineHeight;
											});
											ctx.stroke();
											// 保存Canvas绘制结果为临时文件
											uni.canvasToTempFilePath({
												canvas: canvas,
												success: (res) => {
													// 将临时文件路径保存到数组中
													resolve(res
														.tempFilePath
													)
												},
												fail: (error) => {
													console.error(
														'Failed to save canvas:',
														error);
												},
											});


										}
									},
									fail: function(error) {
										console.log("eee", error);
									}
								});

							})
						// #endif

						// #ifdef H5
						const ctx = uni.createCanvasContext('upload-canvas', this);
						ctx.drawImage(res.path, 0, 0, imageWidth,
							imageHeight);
						ctx.setFontSize(16);
						ctx.setFillStyle('rgba(0, 0, 0, 1)'); // 设置水印颜色和透明度
						const lineHeight = 20; // 水印文字行高
						const lines = that.watermarkText
							.split('\n');
						const x = 10; // 水印左上角 x 坐标
						let y = 20; // 水印左上角 y 坐标

						lines.forEach((line) => {
							ctx.fillText(line, x,
								y);
							y += lineHeight;
						});
						ctx.stroke();
						ctx.draw(false, () => {
							// 保存Canvas绘制结果为临时文件
							uni.canvasToTempFilePath({
								canvasId: 'upload-canvas',
								success: (res) => {
									// 将临时文件路径保存到数组中
									resolve(res.tempFilePath)
								},
								fail: (error) => {
									console.error('Failed to save canvas:',
										error);
								},
							}, this);
						});
						// #endif
					},
					fail: (error) => {
						console.error(error);
					},
				});
			})
		},

三、改进版本

改进原因:
1、Canvas 2D(新接口)需要显式设置画布宽高,默认:300150,最大:13651365
ios 无法上传较大图片的尺寸,固对超过此尺寸的图片进行了等比缩放的处理;

2、在页面中设置canvas宽高,导致页面有滚动条;现在采用离屏的canvas,但是离屏的canvas,canvasToTempFilePath方法又不支持,故先把canvas转化为base64,然后存储到本地文件,然后再读一遍文件

	addWatermark(fileUrl) {
			let that = this;
			return new Promise((resolve, reject) => {
				uni.getImageInfo({
					src: fileUrl,
					fail: (error) => {}, // 替换为你的图片路径
					success: async (res) => {
						console.log("res", res);

						let radio = 1365 / Math.max(res.width, res.height)
						let imageWidth = Math.round(res.width * radio)
						let imageHeight = Math.round(res.height * radio)

						that.width = imageWidth;
						that.height = imageHeight;
						// #ifdef MP-WEIXIN
						let filePath = res.path;
						// 获取文件系统管理器
						const canvas = wx.createOffscreenCanvas({
							type: '2d',
							width: imageWidth,
							height: imageHeight
						})
						let img = canvas.createImage(); // 注意是使用canvas实例 不是ctx
						// 等待图片加载
						await new Promise(resolve => {
							img.onload = resolve
							img.src = filePath; // 要加载的图片 url
						})


						canvas.width = imageWidth;
						canvas.height = imageHeight;
						const ctx = canvas.getContext('2d')
						ctx.drawImage(img, 0, 0, imageWidth,
							imageHeight);
						ctx.font = '28px arial',
							ctx.fillStyle =
							'rgba(255, 255, 255, 1.0)';
						const lineHeight = 50; // 水印文字行高

						const lines = that.watermarkText
							.split('\n');
						const x = 40; // 水印左上角 x 坐标
						let y = imageHeight -
							200; // 水印左上角 y 坐标
						// 文字添加阴影效果
						ctx.shadowColor = 'black';
						ctx.shadowBlur = 5;
						ctx.shadowOffsetX = 2;
						ctx.shadowOffsetY = 2;
						// 添加水印图标
						lines.forEach((line) => {
							ctx.fillText(line, x,
								y);
							y += lineHeight;
						});
						// 设置线条颜色和宽度
						ctx.strokeStyle = '#fff'; // 设置线条颜色为白色
						ctx.lineWidth = 3; // 设置线条宽度为 3 像素
						// 绘制竖线
						ctx.beginPath(); // 开始路径
						ctx.moveTo(20, imageHeight -
							220); // 移动到起点坐标 (x, y)
						ctx.lineTo(20, imageHeight -
							100); // 画一条竖线到终点坐标 (x, y)

						ctx.stroke();
						// 保存Canvas绘制结果为临时文件

						//ios不兼容
						if (this.navBarHeight == 44) {
							console.log('ios上传');
							//if (true) {
							//string type
							//图片格式,默认为 image/png
							//number encoderOptions
							//在指定图片格式为 image/jpeg 或 image/webp的情况下,可以从 0 到 1 的区间内选择图片的质量。如果超出取值范围,将会使用默认值 0.92。其他参数会被忽略。
							let base64 = canvas.toDataURL("image/png", 0.8);
							const time = new Date().getTime();
							const imgPath = wx.env.USER_DATA_PATH + "/poster" + time + "upload" +
								".png";
							//如果图片字符串不含要清空的前缀,可以不执行下行代码.
							const imageData = base64.replace(/^data:image\/\w+;base64,/, "");
							const fs = wx.getFileSystemManager();
							fs.writeFileSync(imgPath, imageData, "base64");
							fs.close()

							wx.getImageInfo({
								src: imgPath,
								success: (res) => {
									console.log("读取写入的文件", res)
									resolve(res.path)
								},
								fail: (res) => {
									console.log("读取写入的文件失败", res)
								}
							})

						} else {
							console.log('android 上传');
							uni.canvasToTempFilePath({
								canvas: canvas,
								fileType: "jpg",
								success: (res) => {
									uni.compressImage({ //图片压缩
										src: res
											.tempFilePath,
										success: (
											res) => {
											// // 将临时文件路径保存到数组中
											resolve(res
												.tempFilePath
											)
										}
									})
								},

								fail: (error) => {
									console.error(
										'Failed to save canvas:',
										error);
								},
							});
						}
					}
					// #endif
				});
			})
		},
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值