這個問題,源自於上傳圖片檔案的時候,後台限制了2MB的大小,but在調起相機拍照的時候分分鐘超過了2MB,為了不影響用戶體驗和功能需求,需要前端對大小進行壓縮,然後傳到後台。
思路分析找了很多資料,發現只有canvas可以對圖片進行壓縮處理。
原理大概就是: 1.先將圖片的file檔案轉成baseURL 2、建立一個image標籤去接收檔案取得圖片的寬高和比例。 3.創建canvas畫布設定畫布的大小。 4、將圖片繪製到canvas上面。 5.對canvas進行壓縮處理,取得新的baseURL 6、將baseURL轉換回檔案。
前提的函數將file檔案轉換為base64/*** @param {二進位檔案流} file * @param {回呼函數,傳回base64} fn */function changeFileToBaseURL(file,fn){ // 建立讀取檔案物件var fileReader = new FileReader(); //如果file沒定義回傳null if(file == undefined) return fn(null); //讀取file檔,得到的結果為base64位元fileReader.readAsDataURL(file); fileReader.onload = function(){ // 把讀取到的base64 var imgBase64Data = this.result; fn(imgBase64Data); } }將base64轉換為文件流
/** * 將base64轉換為檔案* @param {baseURL} dataurl * @param {檔案名稱} filename * @return {檔案二進位流}*/function dataURLtoFile(dataurl, filename) { 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 File([u8arr], filename, {type:mime}); }壓縮方法
/*** canvas壓縮圖片* @param {參數obj} param * @param {檔案二進位流} param.file 必傳* @param {目標壓縮大小} param.targetSize 不傳初始賦值-1* @param {輸出圖片寬度} param.width 不傳初始賦值-1,等比縮放不用傳高度* @param {輸出圖片名稱} param.fileName 不傳初始賦值image* @param {壓縮圖片程度} param.quality 不傳初始賦值0.92。值範圍0~1* @param {回呼函數} param.succ 必傳*/function pressImg(param){ //如果沒有回呼函數就不執行if(param && param.succ){ //如果file沒定義返回null if(param.file == undefined) return param.succ(null); //給參數附帶初始值param.targetSize = param.hasOwnProperty(targetSize) ? param.targetSize : -1; param.width = param.hasOwnProperty(width) ? param.width : -1; param.fileName = param.hasOwnProperty(mName) ? paramfileName: image. .quality = param.hasOwnProperty(quality) ? param.quality : 0.92; var _this = this; // 得到檔案類型var fileType = param.file.type; // console.log(fileType) //image/jpeg if(fileType.indexOf(image) == -1 ){ console.log('請選擇圖片檔案^_^'); return param.succ(null); } //如果目前size比目標size小,直接輸出var size = param.file.size; if(param.targetSize > size){ return param.succ(param.file); } // 讀取file檔,得到的結果為base64位元changeFileToBaseURL(param.file,function(base64){ if(base64){ var image = new Image(); image.src = base64; image.onload = function(){ // 獲得長寬比例var scale = this.width / this.height; // console.log(scale); //建立一個canvas var canvas = document. createElement('canvas'); //取得上下文var context = canvas.getContext('2d'); //取得壓縮後的圖片寬度,如果width為-1,預設原圖寬度canvas.width = param.width == -1 ? this.width : param.width; //取得壓縮後的圖片高度,如果width為-1,預設原圖高度canvas.height = param.width == -1 ? this.height : parseInt(param.width / scale); //把圖片繪製到canvas上面context.drawImage(image, 0, 0, canvas.width, canvas.height); //壓縮圖片,取得到新的base64Url var newImageData = canvas.toDataURL(fileType,param.quality) ; //將base64轉換成檔案流var resultFile = dataURLtoFile(newImageData,param.fileName); //判斷如果targetSize有限制且壓縮後的圖片大小比目標大小大,就彈出錯誤if(param.targetSize != -1 && param.targetSize < resultFile.size){ console .log(圖片上傳尺寸太大,請重新上傳^_^); param.succ(null); }else{ //回傳檔案流param.succ(resultFile); } } } }); } }方法使用
檔案的size是依照字節,所以我們需要把要求的大小轉換成位元組。 1位元組就是1byte就是1B,1KB = 1024B,1MB = 1024 * 1024B
<input type=file id=fileImg class=fileImg/>
// 圖片檔案上傳取得url$(#fileImg).on('change',function(){ pressImg({ file:this.files[0], targetSize:2 * 1024 * 1024, quality:0.5, width:600 , succ:function(resultFile){ //如果不是null就是壓縮成功if(resultFile){ //TODO } } })});問題總結圖片壓縮程度
圖片的壓縮程度不太好確定,所以可以進行多次嘗試,並依照需求方的要求進行調整。 改變目標圖片的大小和清晰度都可以改變圖片的壓縮程度。
本來想做一個壓縮圖片的遞歸,直到圖片大小符合期望後來發現
因為ios調起系統相機拍照是逆時針旋轉了90度。 而在我壓縮圖片之後傳到後台,發現圖片的exif資訊的拍攝方向遺失,導致ios上傳的圖片都是逆時針旋轉了90度。這個問題安卓不曾發現。
目前有些懷疑,是base64轉換成file檔的時候,遺失的。 之後驗證後會在這裡進行補充說明。
@version1.0-2019-8-2-創建《使用canvas壓縮圖片大小》
©burning_韻七七
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VeVb武林網。