微信小程序?qū)D片進(jìn)行canvas壓縮的方法示例詳解
微信小程序其實(shí)自帶一個(gè)圖片壓縮的API wx.compressImage,但是這玩意目前感受就是個(gè)垃圾。IOS大多數(shù)情況下?lián)f(shuō)還可以,安卓有的時(shí)候降低質(zhì)量壓縮后體積反而變大,而且沒(méi)辦法控制其壓縮至具體指定的大小,壓縮后多大看天意。所以需要使用畫(huà)布去自己實(shí)現(xiàn)一個(gè)圖片壓縮方法。
簡(jiǎn)單來(lái)講原理就是:找個(gè)不顯示在頁(yè)面上的畫(huà)布畫(huà)上去,再取出,如果體積還是太大,縮小尺寸后再畫(huà),再取,遞歸下去,直到體積滿足要求。(所以限制的越小,圖片越大,壓縮越久,遞歸次數(shù)越多)
第一步:新建一個(gè)zipPic.js文件(名字你開(kāi)心就好),里面的代碼如下
//通過(guò)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()
}
}
})
}
//將圖片畫(huà)在畫(huà)布上并獲取畫(huà)好之后的圖片的路徑
function getCanvasImage(canvasId,imagePath,imageW,imageH,getImgSuccess){
//創(chuàng)建畫(huà)布內(nèi)容
const ctx=wx.createCanvasContext(canvasId);
//圖片畫(huà)上去,imageW和imageH是畫(huà)上去的尺寸,圖像和畫(huà)布間隔都是0
ctx.drawImage(imagePath,0,0,imageW,imageH);
//這里一定要加定時(shí)器,給足夠的時(shí)間去畫(huà)(所以每次遞歸最少要耗時(shí)200ms,多次遞歸很耗時(shí)?。?
ctx.draw(false,setTimeout(function(){
wx.canvasToTempFilePath({
canvasId:canvasId,
x:0,
y:0,
width:imageW,
height:imageH,
quality:1, //最高質(zhì)量,只通過(guò)尺寸放縮去壓縮,畫(huà)的時(shí)候都按最高質(zhì)量來(lái)畫(huà)
success:(res)=>{
getImgSuccess(res.tempFilePath);
}
})
},200));
}
//主函數(shù),默認(rèn)限制大小1024kb即1mb,drawWidth是繪畫(huà)區(qū)域的大小
//初始值傳入為畫(huà)布自身的邊長(zhǎng)(我們這是一個(gè)正方形的畫(huà)布)
function getLessLimitSizeImage(canvasId,imagePath,limitSize=1024,drawWidth,callback){
//判斷圖片尺寸是否滿足要求
imageSizeIsLessLimitSize(imagePath,limitSize,
(lessRes)=>{
//滿足要求走callback,將壓縮后的文件路徑返回
callback(imagePath);
},
(moreRes)=>{
//不滿足要求需要壓縮的時(shí)候
wx.getImageInfo({
src:imagePath,
success:(imageInfo)=>{
let maxSide=Math.max(imageInfo.width,imageInfo.height);
let windowW=drawWidth;
let scale=1;
/*
這里的目的是當(dāng)繪畫(huà)區(qū)域縮小的比圖片自身尺寸還要小的時(shí)候
取圖片長(zhǎng)寬的最大值,然后和當(dāng)前繪畫(huà)區(qū)域計(jì)算出需要放縮的比例
然后再畫(huà)經(jīng)過(guò)放縮后的尺寸,保證畫(huà)出的一定是一個(gè)完整的圖片。由于每次遞歸繪畫(huà)區(qū)域都會(huì)縮小,
所以不用擔(dān)心scale永遠(yuǎn)都是1繪畫(huà)尺寸永遠(yuǎn)不變的情況,只要不滿足壓縮后體積的要求
就會(huì)縮小繪畫(huà)區(qū)域,早晚會(huì)有繪畫(huà)區(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('調(diào)用壓縮',imageW,imageH);
//圖片在規(guī)定繪畫(huà)區(qū)域上畫(huà)并獲取新的圖片的path
getCanvasImage(canvasId,imagePath,imageW,imageH,
(pressImgPath)=>{
/*
再去檢查是否滿足要求,始終縮小繪畫(huà)區(qū)域,讓圖片適配繪畫(huà)區(qū)域
這里乘以0.95是必須的,如果不縮小繪畫(huà)區(qū)域,會(huì)出現(xiàn)尺寸比繪畫(huà)區(qū)域小,
而體積比要求壓縮體積大的情況出現(xiàn),就會(huì)無(wú)窮遞歸下去,因?yàn)閟cale的值永遠(yuǎn)是1
但0.95不是固定的,你可以根據(jù)需要自己改,0到1之間,越小則繪畫(huà)區(qū)域縮小的越快
但不建議取得太小,繪畫(huà)區(qū)域縮小的太快,壓出來(lái)的將總是很糊的
*/
getLessLimitSizeImage(canvasId,pressImgPath,limitSize,drawWidth*0.95,callback);
}
)
}
})
}
)
}
export default getLessLimitSizeImage
好的接下來(lái)是使用的方法:
在你想壓縮圖片的js代碼所對(duì)應(yīng)的頁(yè)面中。先放置一個(gè)用戶看不見(jiàn)的畫(huà)布。
(就是如果我想在index.js中chooseImage再壓縮,就需要你在index.html中加上下面的html代碼)
<!--用于圖片壓縮的canvas畫(huà)布,不在頁(yè)面中展示,且id固定不可變-->
<canvas
style="width: {{cw}}px; height: {{cw}}px;position: absolute; z-index: -1; left: -10000rpx;; top: -10000rpx;"
canvas-id="zipCanvas"
></canvas>
<!--畫(huà)布結(jié)束-->
其中cw的值我個(gè)人建議選擇用戶屏幕的寬度,如下,在page({…})的data中添加
//畫(huà)板邊長(zhǎng)默認(rèn)是屏幕寬度,正方形畫(huà)布 cw:wx.getSystemInfoSync().windowWidth,
個(gè)人建議畫(huà)布和繪畫(huà)區(qū)域都是正方形的,畢竟你也不知道要壓縮的圖片是橫向的還是縱向的。
然后,引入,不解釋
import getLessLimitSizeImage from '../../utils/zipPic'
在js代碼中:
wx.chooseImage({
count:1, //只傳一張
sizeType:'original', //原圖質(zhì)量好,然后通過(guò)canvas壓縮,縮略圖壓縮就太糊了
sourceType: ['album', 'camera'], // 來(lái)源是相冊(cè)和相機(jī)
success:(res)=>{
let canvasId='zipCanvas' //注意這里的id和你在頁(yè)面中寫(xiě)的html代碼的canvas的id要一致
let imagePath=res.tempFilePaths[0];//原圖的路徑
let limitSize=2048;//大小限制2048kb
let drawWidth=wx.getSystemInfoSync().windowWidth;//初始繪畫(huà)區(qū)域是畫(huà)布自身的寬度也就是屏幕寬度
wx.showLoading({title:'圖片壓縮中...',mask:true}) //不需要你可以刪掉
getLessLimitSizeImage(canvasId,imagePath,limitSize,drawWidth,(resPath)=>{
wx.hideLoading(); //不需要你可以刪掉
//resPath就是壓縮后圖片的路徑,然后想做什么都隨你
})
}
})
補(bǔ)充:
- 這里代碼的主體不是我做的,網(wǎng)上一搜基本都是這個(gè)寫(xiě)法,這里是經(jīng)過(guò)項(xiàng)目實(shí)踐測(cè)試后沒(méi)問(wèn)題了做的講解。
- 這里圖片是只選了一張去壓縮,如果你需要選多張?jiān)侔€(gè)壓縮那就去寫(xiě)個(gè)循環(huán),找個(gè)數(shù)組存壓縮后的結(jié)果,網(wǎng)上也有很多內(nèi)容。
- 回調(diào)函數(shù)中有l(wèi)essRes和moreRes,細(xì)心的會(huì)發(fā)現(xiàn)這兩個(gè)參數(shù)并沒(méi)有被用到,他們只是個(gè)提醒作用,表明當(dāng)前是less回調(diào)還是more回調(diào),如果你不怕弄混刪掉了或者自己另外寫(xiě)了兩個(gè)新方法那都隨你。
- 極限情況下比如說(shuō)將圖片強(qiáng)制壓縮至10kb,這個(gè)東西我沒(méi)測(cè)試過(guò),不知道會(huì)不會(huì)有問(wèn)題。
- 圖片壓縮體積的減小不是線性的,給人的感覺(jué)有點(diǎn)像二次函數(shù)(y=x^2左面那一半),越往后壓縮的尺寸變化會(huì)越小。當(dāng)然,這和用戶的分辨率,屏幕本身的大小都有關(guān)系。
- 還是那句話,由于每次遞歸都要給至少200ms的時(shí)間去畫(huà),所以遞歸很耗時(shí)!??!而不遞歸進(jìn)行壓縮的話,網(wǎng)絡(luò)傳輸又會(huì)很耗時(shí)!??!所以這個(gè)地方怎么取舍,壓縮至多大,繪畫(huà)區(qū)域縮小的多快,都要靠你自己的經(jīng)驗(yàn)去調(diào)試。
- 圖片的壓縮,長(zhǎng)寬比理論上來(lái)講是不變的,但是因?yàn)樯釛壛诵?shù),可能會(huì)有肉眼難以察覺(jué)的誤差,但是問(wèn)題不大。如果前端想展示一下壓縮后的圖片的話,不要忘記在image中加入mode=“aspectFit” 。
到此這篇關(guān)于微信小程序?qū)D片進(jìn)行canvas壓縮的文章就介紹到這了,更多相關(guān)微信小程序?qū)D片canvas壓縮內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
BootStrap Table后臺(tái)分頁(yè)時(shí)前臺(tái)刪除最后一頁(yè)所有數(shù)據(jù)refresh刷新后無(wú)數(shù)據(jù)問(wèn)題
這篇文章主要介紹了BootStrap Table后臺(tái)分頁(yè)時(shí)前臺(tái)刪除最后一頁(yè)所有數(shù)據(jù)refresh刷新后無(wú)數(shù)據(jù)問(wèn)題,需要的朋友可以參考下2016-12-12
javascript實(shí)現(xiàn)平滑無(wú)縫滾動(dòng)
這篇文章主要為大家詳細(xì)介紹了javascript實(shí)現(xiàn)平滑無(wú)縫滾動(dòng)的具體代碼,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-05-05
在knockoutjs 上自己實(shí)現(xiàn)的flux(實(shí)例講解)
下面小編就為大家分享一篇在knockoutjs 上自己實(shí)現(xiàn)的flux方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2017-12-12
javascript 單例模式詳解及簡(jiǎn)單實(shí)例
這篇文章主要介紹了javascript 單例模式詳解及簡(jiǎn)單實(shí)例的相關(guān)資料,需要的朋友可以參考下2017-02-02
JS 刪除字符串最后一個(gè)字符的實(shí)現(xiàn)代碼
本篇文章主要是對(duì)JS刪除字符串最后一個(gè)字符的實(shí)現(xiàn)代碼進(jìn)行了介紹,需要的朋友可以過(guò)來(lái)參考下,希望對(duì)大家有所幫助2014-02-02
JS獲取html元素的標(biāo)記名實(shí)現(xiàn)方法
下面小編就為大家?guī)?lái)一篇JS獲取html元素的標(biāo)記名實(shí)現(xiàn)方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-10-10
詳解js中構(gòu)造流程圖的核心技術(shù)JsPlumb
這篇文章主要介紹了js中構(gòu)造流程圖的核心技術(shù)JsPlumb,jsPlumb是一個(gè)強(qiáng)大的JavaScript連線庫(kù),它可以將html中的元素用箭頭、曲線、直線等連接起來(lái),適用于開(kāi)發(fā)Web上的圖表、建模工具等,需要的朋友可以參考下2015-12-12
JavaScript閉包和作用域鏈的定義實(shí)現(xiàn)
這篇文章主要為大家介紹了JavaScript閉包和作用域鏈的定義與實(shí)現(xiàn),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-05-05
交叉觀察器?IntersectionObserver用法詳解
這篇文章主要為大家介紹了交叉觀察器?IntersectionObserver用法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-10-10

