您好,登錄后才能下訂單哦!
本文實例為大家分享了vue實現壓縮圖片預覽并上傳的具體代碼,供大家參考,具體內容如下
主要用到filereader、canvas 以及 formdata 這三個h6的api
過程大致分為三步:
用戶使用input file上傳圖片的時候,用filereader讀取用戶上傳的圖片數據(base64格式)
把圖片數據傳入img對象,然后將img繪制到canvas上,再調用canvas.toDataURL對圖片進行壓縮
獲取到壓縮后的base64格式圖片數據,轉成二進制塞入formdata,再通過XmlHttpRequest提交formdata。
模板:
<template> <div class="image-box"> <input type="file" accept="image/*" @change="imageHandle"> <img ref="upImg"/> </div> </template>
獲取圖片數據
methods: { //監聽input file的change事件 imageHandle(e) { //**這個是必不可少的,在下面的reader.onload中this就不再指vm了** let that = this; let maxSize = 100 * 1024; let files = e.srcElement.files; if (!files.length) return; //文件長度大于0 if (!/^image\//.test(files[0].type)) return; //必須是圖片才處理 if (!window.FileReader) return; //支持FileReader //創建filereader對象 let reader = new FileReader(); reader.readAsDataURL(files[0]); //將圖片轉成base64格式 reader.onload = function() { let result = this.result; let img = new Image(); img.src = result; let formdata = new FormData(); if (this.result.length <= maxSize) { that.$refs.upImg.src = result; //預覽圖片 img = null; //上傳圖片 formdata.append("image", that._upload(result, files[0].name, files[0].type)); that.$store.dispatch("uploadImage", formdata) .then(data => { if (data === 1) { that.$toast("上傳成功", "success"); } else if (data === -1) { that.$toast("圖片為空", "error"); } else { that.$toast("上傳失敗", "error"); } }) .catch(error => that.$toast("上傳失敗", "error")); } else { img.onload = function() { //壓縮圖片 let data = that._compress(img); //圖片預覽 that.$refs.upImg.src = data; //上傳圖片 formdata.append("image", that._upload(data, files[0].name, files[0].type)); that.$store.dispatch("uploadImage", formdata) .then(data => { if (data === 1) { that.$toast("上傳成功", "success"); } else if (data === -1) { that.$toast("圖片為空", "error"); } else { that.$toast("上傳失敗", "error"); } }) .catch(error => that.$toast("上傳失敗", "error")); }; } }; },
壓縮圖片
在IOS中,canvas繪制圖片是有兩個限制的:
首先是圖片的大小,如果圖片的大小超過兩百萬像素,圖片也是無法繪制到canvas上的,調用drawImage的時候不會報錯,但是你用toDataURL獲取圖片數據的時候獲取到的是空的圖片數據。
再者就是canvas的大小有限制,如果canvas的大小大于大概五百萬像素(即寬高乘積)的時候,不僅圖片畫不出來,其他什么東西也都是畫不出來的。
應對第一種限制,處理辦法就是瓦片繪制了。瓦片繪制,也就是將圖片分割成多塊繪制到canvas上,我代碼里的做法是把圖片分割成100萬像素一塊的大小,再繪制到canvas上。
而應對第二種限制,我的處理辦法是對圖片的寬高進行適當壓縮,我代碼里為了保險起見,設的上限是四百萬像素,如果圖片大于四百萬像素就壓縮到小于四百萬像素。四百萬像素的圖片應該夠了,算起來寬高都有2000X2000了。
如此一來就解決了IOS上的兩種限制了。
除了上面所述的限制,還有兩個坑,一個就是canvas的toDataURL是只能壓縮jpg的,當用戶上傳的圖片是png的話,就需要轉成jpg,也就是統一用canvas.toDataURL(‘image/jpeg', 0.1) , 類型統一設成jpeg,而壓縮比就自己控制了。
另一個就是如果是png轉jpg,繪制到canvas上的時候,canvas存在透明區域的話,當轉成jpg的時候透明區域會變成黑色,因為canvas的透明像素默認為rgba(0,0,0,0),所以轉成jpg就變成rgba(0,0,0,1)了,也就是透明背景會變成了黑色。解決辦法就是繪制之前在canvas上鋪一層白色的底色。
_compress(img) { let canvas = document.createElement("canvas"); let ctx = canvas.getContext("2d"); //瓦片 let tCanvas = document.createElement("canvas"); let tctx = tCanvas.getContext("2d"); let initSize = img.src.length; let width = img.width; let height = img.height; //如果圖片大于四百萬像素,計算壓縮比并將大小壓至400萬以下 let ratio; if ((ratio = (width * height) / 4000000) > 1) { ratio = Math.sqrt(ratio); widht /= ratio; height /= ratio; } else { ratio = 1; } canvas.width = width; canvas.height = height; //鋪底色 ctx.fillStyle = "#fff"; ctx.fillRect(0, 0, canvas.width, canvas.height); //如果圖片像素大于100萬則使用瓦片繪制 let count; if ((count = (width * height) / 1000000) > 1) { count = ~~(Math.sqrt(count) + 1); //計算要分成多少瓦片,~~在這里表示取整 //計算每塊瓦片的寬高 let nw = ~~(width / count); let nh = ~~(height / count); tCanvas.width = nw; tCanvas.height = nh; for (let i = 0; i < count; i++) { for (let j = 0; j < count; j++) { tctx.drawImage( img, i * nw * ratio, j * nh * ratio, nw * ratio,nh * ratio, 0, 0, nw,nh ); ctx.drawImage(tCanvas, i * nw, j * nh, nw, nh); } } } else { ctx.drawImage(img, 0, 0, canvas.width, canvas.height); } //進行壓縮 let ndata = canvas.toDataURL("image/jpeg", 0.3); tCanvas.width = tCanvas.height = canvas.width = canvas.height = 0; return ndata; },
上傳
完成圖片壓縮后,就可以塞進formdata里進行上傳了,先將base64數據轉成字符串,再實例化一個ArrayBuffer,然后將字符串以8位整型的格式傳入ArrayBuffer,再通過BlobBuilder或者Blob對象,將8位整型的ArrayBuffer轉成二進制對象blob,再將blob轉為File對象
_upload(data, name, type) { let text = window.atob(data.split(",")[1]); let buffer = new ArrayBuffer(text.length); let ubuffer = new Uint8Array(buffer); let pecent = 0, loop = null; for (var i = 0; i < text.length; i++) { ubuffer[i] = text.charCodeAt(i); } let Builder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder; let blob; if (Builder) { var builder = new Builder(); builder.append(buffer); blob = builder.getBlob(type); } else { blob = new window.Blob([ubuffer], { type: type }); } // blob 轉file var fileOfBlob = new File([blob], name, { type: type }); return fileOfBlob; } }
將圖片壓縮上傳封裝到一個js文件里
const UploadImg = { imageHandle(files, maxSize, imgDom) { let that = this; let formdata = new FormData(); let reader = new FileReader(); reader.readAsDataURL(files[0]); //將圖片轉成base64格式 //reader.onload是異步,要用到Promise對象將值返回出去 return new Promise((resolved, rejected) => { reader.onload = function () { let result = this.result; let img = new Image(); img.src = result; if (this.result.length <= maxSize) { imgDom.src = result; img = null; formdata.append("image", that._upload(result, files[0].name, files[0].type)); resolved(formdata); } else { img.onload = function () { let data = that._compress(img); imgDom.src = data; formdata.append("image", that._upload(data, files[0].name, files[0].type)); resolved(formdata); }; } }; }) }, _compress(img) { let canvas = document.createElement("canvas"); let ctx = canvas.getContext("2d"); //瓦片 let tCanvas = document.createElement("canvas"); let tctx = tCanvas.getContext("2d"); let width = img.width; let height = img.height; //如果圖片大于四百萬像素,計算壓縮比并將大小壓至400萬以下 let ratio; if ((ratio = (width * height) / 4000000) > 1) { ratio = Math.sqrt(ratio); widht /= ratio; height /= ratio; } else { ratio = 1; } canvas.width = width; canvas.height = height; //鋪底色 ctx.fillStyle = "#fff"; ctx.fillRect(0, 0, canvas.width, canvas.height); //如果圖片像素大于100萬則使用瓦片繪制 let count; if ((count = (width * height) / 1000000) > 1) { count = ~~(Math.sqrt(count) + 1); //計算要分成多少瓦片 //計算每塊瓦片的寬高 let nw = ~~(width / count); let nh = ~~(height / count); tCanvas.width = nw; tCanvas.height = nh; for (let i = 0; i < count; i++) { for (let j = 0; j < count; j++) { tctx.drawImage(img, i * nw * ratio, j * nh * ratio, nw * ratio, nh * ratio, 0, 0, nw, nh); ctx.drawImage(tCanvas, i * nw, j * nh, nw, nh); } } } else { ctx.drawImage(img, 0, 0, canvas.width, canvas.height); } //進行最小壓縮 let ndata = canvas.toDataURL("image/jpeg", 0.3); tCanvas.width = tCanvas.height = canvas.width = canvas.height = 0; return ndata; }, _upload(data, name, type) { let text = window.atob(data.split(",")[1]); let buffer = new ArrayBuffer(text.length); let ubuffer = new Uint8Array(buffer); for (var i = 0; i < text.length; i++) { ubuffer[i] = text.charCodeAt(i); } let Builder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder; let blob; if (Builder) { var builder = new Builder(); builder.append(buffer); blob = builder.getBlob(type); } else { blob = new window.Blob([ubuffer], { type: type }); } // blob 轉file var fileOfBlob = new File([blob], name, { type: type }); return fileOfBlob; } } export default UploadImg
調用代碼
import UploadImg from "../../util/uploadImg"; methods: { imageHandle(e) { let maxSize = 100 * 1024; let imgDom = this.$refs.upImg; let files = e.srcElement.files; if (!files.length) return; //文件長度大于0 if (!/^image\//.test(files[0].type)) return; //必須是圖片才處理 if (!window.FileReader) return; //支持FileReader if (this.docEntry === "" || this.lineId === "") { this.$toast("請填寫完整信息", "error"); return; } // let formdata = new FormData(); UploadImg.imageHandle(files, maxSize, imgDom).then(formdata => { formdata.append("docEntry", this.docEntry); formdata.append("lineId", this.lineId); formdata.append("action", "ProductionListImage"); this.$store .dispatch("uploadImage", formdata) .then(data => { if (data === 1) { this.$toast("上傳成功", "success"); } else if (data === -1) { this.$toast("圖片為空", "error"); } else { this.$toast("上傳失敗", "error"); } }) .catch(error => this.$toast("上傳失敗", "error")); }); } }
參考鏈接:移動端利用H5實現壓縮圖片上傳功能
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持億速云。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。