Vue+vant實現(xiàn)圖片上傳添加水印
圖片上傳大家都不會陌生,就算是一個新人也會干的事兒。但說到加水印,當(dāng)初我一直以為只能是在后端實現(xiàn)。
原來,在前端也是能實現(xiàn)圖片上傳加水印的。(注:以下的代碼都來自于網(wǎng)絡(luò),只是我把兩部份代碼合在一起來實現(xiàn)我的需求而已,在最后面,我也會附上原作者的接,大家都不容易)
【注:我自己寫的注釋后面會有個"(小冰)",其他的為原作者的注釋】
<van-uploader v-model="fileList" multiple:after-read="afterRead"/>
data(){ fileList:[], //vant中圖片上傳的雙向邦定(小冰) wmConfig : { //用于水印的東西,下面會用到 (小冰) font: "microsoft yahei", //字體 textArray: ['張三','2021/11/26 16:44'],//水印文本內(nèi)容,允許數(shù)組最大長度3 即:3行水印 density: 3 //密度 建議取值范圍1-5 值越大,水印越多,可能會導(dǎo)致水印重疊等問題,慎重?。?! } }
methods:{ //dataURLtoBlob 、 blobToFile 兩個方法的意思是把base64的圖片轉(zhuǎn)換成file文件 //1,先將base64轉(zhuǎn)換為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轉(zhuǎn)換為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,在轉(zhuǎn)為 file類型 let file1 = this.blobToFile(blob,fileName); console.log("file1:",file1); }, base64AddWaterMaker (base64Img, wmConfig) { let that = this; if (wmConfig.textArray.length === 0) { console.error("****沒有水印內(nèi)容*****"); 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 為左上角坐標(biāo)原點 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"; //文字坐標(biāo) const maxPx = Math.max(imgWidth, imgHeight); const stepPx = Math.floor(maxPx / wmConfig.density); let arrayX = [0];//初始水印位置 canvas坐標(biāo) 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); ///畫布旋轉(zhuǎn)原點 移到 圖片中心 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轉(zhuǎn)file兩個不同的博文混在一起寫的。
圖片加水印 :JavaScript實現(xiàn)為圖片添加水印的方法
base64轉(zhuǎn)file:JS中將圖片base64轉(zhuǎn)file文件的兩種方式
順便我也把file文件轉(zhuǎn)base64的封裝函數(shù)也發(fā)一下。當(dāng)然,這個我也是在網(wǎng)上找的。
function fileToBase64(file, callback) { //callback 是一個回調(diào)函數(shù),而回調(diào)函數(shù)往這兒走一回,它結(jié)果就是base64 const fileReader = new FileReader() fileReader.readAsDataURL(file) fileReader.onload = function () { callback(this.result) } }, function callbaseFun(res){ console.log(res,'res打印出來就是base64') },
//---------------------------分割線--------------------
第二種方法,跟上面的方法差不多,只是這種方法可以隨意去調(diào)整水印的位置和大小什么的。
//將base64轉(zhuǎn)化為二進(jìn)制 dataURItoBlob(base64Data) { var date = new Date(); //console.log('將base64轉(zhuǎn)化為二進(jìn)制', 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轉(zhuǎn)化為二進(jìn)制 dataURItoBlob(base64Data) { var date = new Date(); //console.log('將base64轉(zhuǎn)化為二進(jìn)制', 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轉(zhuǎn)Canvas async imgToCanvas(base64) { var date = new Date(); //console.log('Base64轉(zhuǎn)Canvas', date.getMinutes(), date.getSeconds()) // 創(chuàng)建img元素 const img = document.createElement('img') img.setAttribute('src', base64) await new Promise((resolve) => (img.onload = resolve)) // 創(chuàng)建canvas DOM元素,并設(shè)置其寬高和圖片一樣 const canvas = document.createElement('canvas') //console.log(img.height) //console.log(img.width) canvas.width = img.width canvas.height = img.height // 坐標(biāo)(0,0) 表示從此處開始繪制,相當(dāng)于偏移。 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轉(zhuǎn)圖片文件(Image) convasToImg(canvas) { var date = new Date(); //console.log('Canvas轉(zhuǎn)圖片文件(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)轉(zhuǎn)文件(File) base64ToFile(urlData, fileName) { var date = new Date(); //console.log('圖片文件(Image)轉(zhuǎn)文件(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對象轉(zhuǎn)base64 fileToBase64(file, callback) { //callback 是一個回調(diào)函數(shù),而回調(diào)函數(shù)往這兒走一回,它結(jié)果就是base64 var date = new Date(); //console.log('file對象轉(zhuǎn)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('成功時執(zhí)行') 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'); //這兒水印的參數(shù)是根據(jù) addWatermark()方法里面的 ctx.fillText(txt1, 20, canvas.height - 240) 進(jìn)行修改 const img = this.convasToImg(canvas); //Canvas轉(zhuǎn)圖片文件(Image) let newFile = this.base64ToFile(img.src) //圖片文件轉(zhuǎn)file對象 let res = await this.fileToBase64(newFile, this.callbaseFun) //file轉(zhuǎn)base64, 注意 第二個參數(shù)是一個回調(diào)函數(shù),也就是說回調(diào)函數(shù)里面的參數(shù)就是base64的值 }
到此這篇關(guān)于Vue+vant實現(xiàn)圖片上傳添加水印的文章就介紹到這了,更多相關(guān)Vue vant圖片加水印內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
基于vue-upload-component封裝一個圖片上傳組件的示例
這篇文章主要介紹了基于vue-upload-component封裝一個圖片上傳組件的示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-10-10Avue自定義formslot調(diào)用rules自定義規(guī)則方式
在Avue框架中,使用formslot自定義表格列時可能會遇到無法調(diào)用Avue的自定義校驗規(guī)則的問題,這通常發(fā)生在嘗試通過formslot自定義設(shè)置列的場景中,解決這一問題的一個有效方法是將自定義列與Avue的校驗規(guī)則通過特定方式連接起來2024-10-10vue init webpack myproject構(gòu)建項目 ip不能訪問的解決方法
下面小編就為大家分享一篇vue init webpack myproject構(gòu)建項目 ip不能訪問的解決方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-03-03Vue項目代碼之路由拆分、Vuex模塊拆分、element按需加載詳解
這篇文章主要介紹了Vue項目代碼之路由拆分、Vuex模塊拆分、element按需加載,項目較大路由較多時,路由拆分是一個不錯的代碼優(yōu)化方案,按不同業(yè)務(wù)分為多個模塊,結(jié)構(gòu)清晰便于統(tǒng)一管理,本文通過示例給大家詳細(xì)講解,需要的朋友可以參考下2022-11-11詳解Vue Elementui中的Tag與頁面其它元素相互交互的兩三事
這篇文章主要介紹了詳解Vue Elementui中的Tag與頁面其它元素相互交互的兩三事,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-09-09vue.js+element-ui動態(tài)配置菜單的實例
今天小編就為大家分享一篇vue.js+element-ui動態(tài)配置菜單的實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-09-09關(guān)于vue-cli3+webpack熱更新失效及解決
這篇文章主要介紹了關(guān)于vue-cli3+webpack熱更新失效及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-04-04