vue + vant实现图片上传加水印

图片上传大家都不会陌生,就算是一个新人也会干的事儿。但说到加水印,当初我一直以为只能是在后端实现。这不,来csdn那么久了,工作中有不懂的也在csdn里找答案。昨天晚上,我特意在csdn里找了个遍。原来,在前端也是能实现图片上传加水印的。(注:以下的代码都来自于csdn,只是我把两部份代码合在一起来实现我的需求而已,在最后面,我也会附上原作者的接,大家都不容易)
【注:我自己写的注释后面会有个"(小冰)",其他的为原作者的注释】

<van-uploader v-model="fileList" multiple:after-read="afterRead"/>
data(){
	fileList:[], //vant中图片上传的双向邦定(小冰)
	wmConfig : { //用于水印的东西,下面会用到 (小冰)
		font: "microsoft yahei", //字体
		textArray: ['张三','2021/11/26 16:44'],//水印文本内容,允许数组最大长度3 即:3行水印
		density: 3  //密度 建议取值范围1-5   值越大,水印越多,可能会导致水印重叠等问题,慎重!!!
	}
}
methods:{
	//dataURLtoBlob 、 blobToFile 两个方法的意思是把base64的图片转换成file文件
	//1,先将base64转换为blob
	dataURLtoBlob(dataurl) {
		var arr = dataurl.split(','),
		mime = arr[0].match(/:(.*?);/)[1],
		bstr = atob(arr[1]),
		n = bstr.length,
		u8arr = new Uint8Array(n);
		while (n--) {
			u8arr[n] = bstr.charCodeAt(n);
		}
		return new Blob([u8arr], { type: mime });
	},
	//2,再将blob转换为file
	blobToFile(theBlob, fileName){
		theBlob.lastModifiedDate = new Date();  // 文件最后的修改日期
		theBlob.name = fileName;                // 文件名
		return new File([theBlob], fileName, {type: theBlob.type, lastModified: Date.now()});
	},


	//这个不多说,都懂,文件上传的方法(小冰)
	async afterRead(file){
		console.log(file)
		let base64 = file.content;
		let res = await this.base64AddWaterMaker(base64,this.wmConfig) //加水印的重点就是这个(小冰)
		file.content = res;
		let blob =  this.dataURLtoBlob(file.content);
		// 拿到文件名
		let fileName = file.file.name;
		// 2,在转为 file类型
		let file1 = this.blobToFile(blob,fileName);
		console.log("file1:",file1);
	},


	base64AddWaterMaker  (base64Img, wmConfig)  {
		let that = this;
		if (wmConfig.textArray.length === 0) {
			console.error("****没有水印内容*****");
			return base64Img;
		}
		return new Promise((resolve, reject) => {
			const canvas = document.createElement("canvas");
			const ctx = canvas.getContext("2d");
			const img = new Image();
			let resultBase64 = null;
			img.onload = function() {
				canvas.width = img.width;
				canvas.height = img.height;
				//canvas绘制图片,0 0  为左上角坐标原点
				ctx.drawImage(img, 0, 0);
				//写入水印
				that.drawWaterMark(ctx, img.width, img.height, wmConfig);
				resultBase64 = canvas.toDataURL("image/png");
				if (!resultBase64) {
					reject();
				} else {
					resolve(resultBase64);
				}
			};
			img.src = base64Img;
		});

	},
	
	drawWaterMark  (ctx, imgWidth, imgHeight, wmConfig)  {
		let fontSize;
		if (imgWidth >= 3456) {
			fontSize = 50;
		} else if (imgWidth >= 2700) {
			fontSize = 30;
		} else if (imgWidth >= 2000) {
			fontSize = 26;
		} else if (imgWidth >= 1436) {
			fontSize = 20;
		} else if (imgWidth >= 800) {
			fontSize = 12;
		} else if (imgWidth >= 500) {
			fontSize = 10;
		} else {
			fontSize = 8;
		}
		console.log(imgWidth, imgHeight, fontSize);
		ctx.fillStyle = "white";
		ctx.font = `${fontSize}px ${wmConfig.font}`;
		ctx.lineWidth = 1;
		ctx.fillStyle = "rgba(255,255,255,1)";
		ctx.textAlign = "left";
		ctx.textBaseline = "middle";
		//文字坐标
		const maxPx = Math.max(imgWidth, imgHeight);
		const stepPx = Math.floor(maxPx / wmConfig.density);
		let arrayX = [0];//初始水印位置 canvas坐标 0 0 点
		while (arrayX[arrayX.length - 1] < maxPx/2) {
			arrayX.push(arrayX[arrayX.length - 1] + stepPx);
		}
		arrayX.push(...arrayX.slice(1, arrayX.length).map((el) => {
			return -el;
		}));
		console.log(arrayX);
		for (let i = 0; i < arrayX.length; i++) {
			for (let j = 0; j < arrayX.length; j++) {
				ctx.save();
				ctx.translate(imgWidth / 2, imgHeight / 2); ///画布旋转原点 移到 图片中心
				ctx.rotate(-Math.PI / 5);
				if (wmConfig.textArray.length > 3) {
					wmConfig.textArray = wmConfig.textArray.slice(0, 3);
				}
				wmConfig.textArray.forEach((el, index) => {
					let offsetY = fontSize * index + 2;
					ctx.fillText(el, arrayX[i], arrayX[j] + offsetY);
				});
				ctx.restore();
			}
		}
	}
}

代码就是这些,然而,在此中,我是把图片加水印和图片base64转file两个不同的博文混在一起写的。
图片加水印 :【https://blog.csdn.net/King0217/article/details/121562949】
base64转file:【https://blog.csdn.net/qq_43886365/article/details/126729188】

顺便我也把file文件转base64的封装函数也发一下。当然,这个我也是在网上找的。

function fileToBase64(file, callback) { //callback 是一个回调函数,而回调函数往这儿走一回,它结果就是base64
	const fileReader = new FileReader()
	fileReader.readAsDataURL(file)
	fileReader.onload = function () {
		callback(this.result)
	}
},
function callbaseFun(res){
	console.log(res,'res打印出来就是base64')
},

//---------------------------分割线--------------------
第二种方法,跟上面的方法差不多,只是这种方法可以随意去调整水印的位置和大小什么的。

//将base64转化为二进制
dataURItoBlob(base64Data) {
     var date = new Date();
     //console.log('将base64转化为二进制', date.getMinutes(), date.getSeconds())
     var byteString;
     if (base64Data.split(',')[0].indexOf('base64') >= 0)
         byteString = atob(base64Data.split(',')[1]);
     else
         byteString = unescape(base64Data.split(',')[1]);
     var mimeString = base64Data.split(',')[0].split(':')[1].split(';')[0];
     var ia = new Uint8Array(byteString.length);
     for (var i = 0; i < byteString.length; i++) {
         ia[i] = byteString.charCodeAt(i);
     }
     return new Blob([ia], { type: mimeString });
},
//将base64转化为二进制
dataURItoBlob(base64Data) {
     var date = new Date();
     //console.log('将base64转化为二进制', date.getMinutes(), date.getSeconds())
     var byteString;
     if (base64Data.split(',')[0].indexOf('base64') >= 0)
         byteString = atob(base64Data.split(',')[1]);
     else
         byteString = unescape(base64Data.split(',')[1]);
     var mimeString = base64Data.split(',')[0].split(':')[1].split(';')[0];
     var ia = new Uint8Array(byteString.length);
     for (var i = 0; i < byteString.length; i++) {
         ia[i] = byteString.charCodeAt(i);
     }
     return new Blob([ia], { type: mimeString });
},
//Base64转Canvas
async imgToCanvas(base64) {
     var date = new Date();
     //console.log('Base64转Canvas', date.getMinutes(), date.getSeconds())
     // 创建img元素
     const img = document.createElement('img')
     img.setAttribute('src', base64)
     await new Promise((resolve) => (img.onload = resolve))
     // 创建canvas DOM元素,并设置其宽高和图片一样
     const canvas = document.createElement('canvas')
     //console.log(img.height)
     //console.log(img.width)
     canvas.width = img.width
     canvas.height = img.height
     // 坐标(0,0) 表示从此处开始绘制,相当于偏移。
     canvas.getContext('2d').drawImage(img, 0, 0)
     return canvas
},
//写入水印
addWatermark(canvas, txt1, txt2, txt3, tex4) {
     //alert(canvas.height)
     var date = new Date();
     //console.log('写入水印', date.getMinutes(), date.getSeconds())
     const ctx = canvas.getContext('2d')
     //ctx.font = '50px Arial'
     //ctx.strokeText(text, 0, 0)
     ctx.font = '20px Arial'
     ctx.fillStyle = 'white'
     ctx.fillText(txt1, 20, canvas.height - 240)
     ctx.fillText(txt2, 20, canvas.height - 200)
     ctx.fillText(txt3, 20, canvas.height - 160)
     ctx.fillText(tex4, 20, canvas.height - 120)
     ctx.fillText(tex4, 20, canvas.height - 80)
     return canvas
},
//Canvas转图片文件(Image)
convasToImg(canvas) {
     var date = new Date();
     //console.log('Canvas转图片文件(Image)', date.getMinutes(), date.getSeconds())
     // 新建Image对象,可以理解为DOM
     let image = new Image()
     // canvas.toDataURL 返回的是一串Base64编码的URL
     // 指定格式 PNG
     image.src = canvas.toDataURL('image/png')
     return image
},
//图片文件(Image)转文件(File)
base64ToFile(urlData, fileName) {
     var date = new Date();
     //console.log('图片文件(Image)转文件(File)', date.getMinutes(), date.getSeconds())
     let arr = urlData.split(',');
     let mime = arr[0].match(/:(.*?);/)[1];
     let bytes = atob(arr[1]); // 解码base64
     let n = bytes.length
     let ia = new Uint8Array(n);
     while (n--) {
         ia[n] = bytes.charCodeAt(n);
     }
     return new File([ia], fileName, { type: mime });
},
//file对象转base64
fileToBase64(file, callback) { //callback 是一个回调函数,而回调函数往这儿走一回,它结果就是base64
     var date = new Date();
     //console.log('file对象转base64', date.getMinutes(), date.getSeconds())
     return new Promise((resolve, reject) => {
         const fileReader = new FileReader()
         fileReader.readAsDataURL(file)
         fileReader.onload = function () {
             let res = callback(this.result)
             resolve(res)
         }
     })
},
callbaseFun(res) {
     //console.log('上传的方法')
     return new Promise((resolve, reject) => {
         let that = this;
         //console.log(res, 'base64')
         let str = res.split(',');
         str[0] = 'data:image/jpeg;base64';
         let r = str.toString();
         let url = "/ServerAPI/ServerBase64API.ashx"
         var obj = {
             imgbase64: r,
             method: "ServerBase64png",
             Module: "DaKa",
             id: "a4e89358-9465-4295-87ea-4d0af2bd9133"
         }
         jQuery.ajax({
             url: url,
             type: 'POST',
             data: obj,
             dataType: 'json',
             timeout: 8000,
         })
             .done(res => {
                 var date = new Date();
                 //console.log('上传成功', date.getMinutes(), date.getSeconds())
                 //console.log('成功时执行')
                 resolve(res)
             })
             .fail(err => {
                 //console.log(err, '上传失败')
                 reject({ msg: '上传失败' })
             })
     })
},
async oneUpload(e){
     let base64 = e.content;
     let tempCanvas = await this.imgToCanvas(base64)  //得到canvas的值
     const canvas = this.addWatermark(tempCanvas , '水印1' , '水印2' , '水印3'); //这儿水印的参数是根据 addWatermark()方法里面的 ctx.fillText(txt1, 20, canvas.height - 240) 进行修改
     const img = this.convasToImg(canvas); //Canvas转图片文件(Image)
     let newFile = this.base64ToFile(img.src) //图片文件转file对象
     let res = await this.fileToBase64(newFile, this.callbaseFun) //file转base64, 注意 第二个参数是一个回调函数,也就是说回调函数里面的参数就是base64的值
}
  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
移动端Vue VantUploader组件可以很方便地实现上传、压缩和旋转图片功能。首先,我们需要在Vue项目中引入Vue Vant库,并在需要使用Uploader的组件中注册该组件。 在页面中使用Uploader组件时,我们可以设置相关的属性来实现功能需求。首先是上传图片功能,可以通过设置`action`属性来指定图片上传的后端接口地址。上传成功后,可以通过监听`@success`事件来处理上传成功的逻辑,例如显示上传成功的提示信息或者将上传成功的图片URL保存到数据库等。 对于压缩图片的功能,我们可以使用该组件提供的`beforeRead`方法来获取用户要上传的图片文件对象。然后,利用`HTMLCanvasElement`的`toBlob`方法对图片进行压缩,并将压缩后的图片对象传给Uploader组件进行上传。在压缩图片时,可以设置压缩的尺寸或者压缩的质量、压缩比等参数,以控制压缩后的图片大小适应实际需求。 要实现图片旋转的功能,我们可以利用`EXIF.js`库来读取图片的EXIF信息,获取图片的拍摄方向。然后,根据拍摄方向来确定图片需要旋转的角度,再借助`canvas`的`rotate`方法对图片进行旋转。旋转后的图片可以在`@success`事件触发后重新渲染到页面上,或者直接发送到后端进行保存。 总结来说,移动端Vue VantUploader组件通过设置相关属性和监听事件,配合压缩工具和EXIF库,可以非常方便地实现图片上传、压缩和旋转功能,满足移动端图片处理的需求。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值