微信小程序對圖片進行canvas壓縮的方法示例詳解
微信小程序其實自帶一個圖片壓縮的API wx.compressImage,但是這玩意目前感受就是個垃圾。IOS大多數(shù)情況下?lián)f還可以,安卓有的時候降低質量壓縮后體積反而變大,而且沒辦法控制其壓縮至具體指定的大小,壓縮后多大看天意。所以需要使用畫布去自己實現(xiàn)一個圖片壓縮方法。
簡單來講原理就是:找個不顯示在頁面上的畫布畫上去,再取出,如果體積還是太大,縮小尺寸后再畫,再取,遞歸下去,直到體積滿足要求。(所以限制的越小,圖片越大,壓縮越久,遞歸次數(shù)越多)
第一步:新建一個zipPic.js文件(名字你開心就好),里面的代碼如下
//通過canvas將圖片壓縮至指定大小 //判斷圖片大小是否滿足需求,limitSize的單位是kb function imageSizeIsLessLimitSize(imagePath,limitSize,lessCallback,moreCallback){ //獲取文件信息 wx.getFileInfo({ filePath:imagePath, success:(res)=>{ console.log("壓縮前圖片大小",res.size/1024,'kb'); //如果圖片太大了走moreCallback if(res.size>1024*limitSize){ moreCallback() } //圖片滿足要求了走lessCallback else{ lessCallback() } } }) } //將圖片畫在畫布上并獲取畫好之后的圖片的路徑 function getCanvasImage(canvasId,imagePath,imageW,imageH,getImgSuccess){ //創(chuàng)建畫布內容 const ctx=wx.createCanvasContext(canvasId); //圖片畫上去,imageW和imageH是畫上去的尺寸,圖像和畫布間隔都是0 ctx.drawImage(imagePath,0,0,imageW,imageH); //這里一定要加定時器,給足夠的時間去畫(所以每次遞歸最少要耗時200ms,多次遞歸很耗時!) ctx.draw(false,setTimeout(function(){ wx.canvasToTempFilePath({ canvasId:canvasId, x:0, y:0, width:imageW, height:imageH, quality:1, //最高質量,只通過尺寸放縮去壓縮,畫的時候都按最高質量來畫 success:(res)=>{ getImgSuccess(res.tempFilePath); } }) },200)); } //主函數(shù),默認限制大小1024kb即1mb,drawWidth是繪畫區(qū)域的大小 //初始值傳入為畫布自身的邊長(我們這是一個正方形的畫布) function getLessLimitSizeImage(canvasId,imagePath,limitSize=1024,drawWidth,callback){ //判斷圖片尺寸是否滿足要求 imageSizeIsLessLimitSize(imagePath,limitSize, (lessRes)=>{ //滿足要求走callback,將壓縮后的文件路徑返回 callback(imagePath); }, (moreRes)=>{ //不滿足要求需要壓縮的時候 wx.getImageInfo({ src:imagePath, success:(imageInfo)=>{ let maxSide=Math.max(imageInfo.width,imageInfo.height); let windowW=drawWidth; let scale=1; /* 這里的目的是當繪畫區(qū)域縮小的比圖片自身尺寸還要小的時候 取圖片長寬的最大值,然后和當前繪畫區(qū)域計算出需要放縮的比例 然后再畫經(jīng)過放縮后的尺寸,保證畫出的一定是一個完整的圖片。由于每次遞歸繪畫區(qū)域都會縮小, 所以不用擔心scale永遠都是1繪畫尺寸永遠不變的情況,只要不滿足壓縮后體積的要求 就會縮小繪畫區(qū)域,早晚會有繪畫區(qū)域小于圖片尺寸的情況發(fā)生 */ if(maxSide>windowW){ scale=windowW/maxSide; } //trunc是去掉小數(shù) let imageW=Math.trunc(imageInfo.width*scale); let imageH=Math.trunc(imageInfo.height*scale); console.log('調用壓縮',imageW,imageH); //圖片在規(guī)定繪畫區(qū)域上畫并獲取新的圖片的path getCanvasImage(canvasId,imagePath,imageW,imageH, (pressImgPath)=>{ /* 再去檢查是否滿足要求,始終縮小繪畫區(qū)域,讓圖片適配繪畫區(qū)域 這里乘以0.95是必須的,如果不縮小繪畫區(qū)域,會出現(xiàn)尺寸比繪畫區(qū)域小, 而體積比要求壓縮體積大的情況出現(xiàn),就會無窮遞歸下去,因為scale的值永遠是1 但0.95不是固定的,你可以根據(jù)需要自己改,0到1之間,越小則繪畫區(qū)域縮小的越快 但不建議取得太小,繪畫區(qū)域縮小的太快,壓出來的將總是很糊的 */ getLessLimitSizeImage(canvasId,pressImgPath,limitSize,drawWidth*0.95,callback); } ) } }) } ) } export default getLessLimitSizeImage
好的接下來是使用的方法:
在你想壓縮圖片的js代碼所對應的頁面中。先放置一個用戶看不見的畫布。
(就是如果我想在index.js中chooseImage再壓縮,就需要你在index.html中加上下面的html代碼)
<!--用于圖片壓縮的canvas畫布,不在頁面中展示,且id固定不可變--> <canvas style="width: {{cw}}px; height: {{cw}}px;position: absolute; z-index: -1; left: -10000rpx;; top: -10000rpx;" canvas-id="zipCanvas" ></canvas> <!--畫布結束-->
其中cw的值我個人建議選擇用戶屏幕的寬度,如下,在page({…})的data中添加
//畫板邊長默認是屏幕寬度,正方形畫布 cw:wx.getSystemInfoSync().windowWidth,
個人建議畫布和繪畫區(qū)域都是正方形的,畢竟你也不知道要壓縮的圖片是橫向的還是縱向的。
然后,引入,不解釋
import getLessLimitSizeImage from '../../utils/zipPic'
在js代碼中:
wx.chooseImage({ count:1, //只傳一張 sizeType:'original', //原圖質量好,然后通過canvas壓縮,縮略圖壓縮就太糊了 sourceType: ['album', 'camera'], // 來源是相冊和相機 success:(res)=>{ let canvasId='zipCanvas' //注意這里的id和你在頁面中寫的html代碼的canvas的id要一致 let imagePath=res.tempFilePaths[0];//原圖的路徑 let limitSize=2048;//大小限制2048kb let drawWidth=wx.getSystemInfoSync().windowWidth;//初始繪畫區(qū)域是畫布自身的寬度也就是屏幕寬度 wx.showLoading({title:'圖片壓縮中...',mask:true}) //不需要你可以刪掉 getLessLimitSizeImage(canvasId,imagePath,limitSize,drawWidth,(resPath)=>{ wx.hideLoading(); //不需要你可以刪掉 //resPath就是壓縮后圖片的路徑,然后想做什么都隨你 }) } })
補充:
- 這里代碼的主體不是我做的,網(wǎng)上一搜基本都是這個寫法,這里是經(jīng)過項目實踐測試后沒問題了做的講解。
- 這里圖片是只選了一張去壓縮,如果你需要選多張再挨個壓縮那就去寫個循環(huán),找個數(shù)組存壓縮后的結果,網(wǎng)上也有很多內容。
- 回調函數(shù)中有l(wèi)essRes和moreRes,細心的會發(fā)現(xiàn)這兩個參數(shù)并沒有被用到,他們只是個提醒作用,表明當前是less回調還是more回調,如果你不怕弄混刪掉了或者自己另外寫了兩個新方法那都隨你。
- 極限情況下比如說將圖片強制壓縮至10kb,這個東西我沒測試過,不知道會不會有問題。
- 圖片壓縮體積的減小不是線性的,給人的感覺有點像二次函數(shù)(y=x^2左面那一半),越往后壓縮的尺寸變化會越小。當然,這和用戶的分辨率,屏幕本身的大小都有關系。
- 還是那句話,由于每次遞歸都要給至少200ms的時間去畫,所以遞歸很耗時!?。《贿f歸進行壓縮的話,網(wǎng)絡傳輸又會很耗時!??!所以這個地方怎么取舍,壓縮至多大,繪畫區(qū)域縮小的多快,都要靠你自己的經(jīng)驗去調試。
- 圖片的壓縮,長寬比理論上來講是不變的,但是因為舍棄了小數(shù),可能會有肉眼難以察覺的誤差,但是問題不大。如果前端想展示一下壓縮后的圖片的話,不要忘記在image中加入mode=“aspectFit” 。
到此這篇關于微信小程序對圖片進行canvas壓縮的文章就介紹到這了,更多相關微信小程序對圖片canvas壓縮內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
javascript checkbox/radio onchange不能兼容ie8處理辦法
這篇文章主要介紹了javascript checkbox/radio onchange不能兼容ie8處理辦法的相關資料,需要的朋友可以參考下2017-06-06BootStrap 圖標icon符號圖標glyphicons不正常顯示的快速解決辦法
這篇文章主要介紹了BootStrap 圖標icon符號圖標glyphicons不正常顯示的快速解決辦法,需要的朋友可以參考下2016-12-12js動態(tài)創(chuàng)建上傳表單通過iframe模擬Ajax實現(xiàn)無刷新
這篇文章主要介紹了js動態(tài)創(chuàng)建上傳表單通過iframe模擬Ajax無刷新的具體實現(xiàn),需要的朋友可以參考下2014-02-02JavaScript中Array實例方法map的實現(xiàn)方法
這篇文章主要介紹了JavaScript中Array實例方法map的實現(xiàn)方法,map() 方法創(chuàng)建一個新數(shù)組,其結果是原數(shù)組中的每個元素都調用一個提供的函數(shù)后返回的結果,文中有詳細的代碼示例供大家參考,需要的朋友可以參考下2024-03-03