微信小程序使用Canvas做图片压缩
最近在工作中接触了一个小程序上传图片并将大于500k的图片压缩的需求,由于小程序本身的的压缩功能无法自定义比例,所以决定使用Canvas进行图片压缩。开发过程中也踩了一些坑,因此决定将其分享,如果你也在使用Canvas进行图片压缩的过程中遇到了问题,那么希望本文对你有所帮助。
1.使用Cnavas压缩图片的原理
canvas元素用于在网页上绘制图形,无论你是绘画直线,曲线,文字还是图片,我们使用Canvas做图片压缩,就是用到了它绘制图片这一点。
// 第一步,我们需要在wxml中加上一个Canvas标签
<view style="hiddenCanvas">
<canvas canvas-id='myCanvas' class='press-canvas'
style='width: {{ windowWidth }}px; height: {{ windowWidth }}px;'></canvas>
</view>
//第二部,我们需要想选择一张图片,想要让Canvas绘制图片,需要先获取图片路径
wx.chooseImage({
sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有
sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有
success: function (res) {
// 返回选定照片的本地文件路径列表,tempFilePath可以作为img标签的src属性显示图片
that.setData({
[photoflag + ".loading"]: true
})//遮罩
var tempFilePaths = res.tempFilePaths[0];//选择的图片的路径
let tempFiles = res.tempFiles[0];//选择的图片的大小
wx.getFileSystemManager().readFile({
filePath: tempFilePaths,
encoding: "base64",
success: res => {
//这一步是获取base64格式的图片用来上传
let data = { base64: res.data };
//判断获取的图片文件是否大于500k,若大于500k则执行图片压缩方法,若小于则直接上传
if (tempFiles && (tempFiles.size / 1024 > 500)) {
//压缩上传
that.compressImg(tempFilePaths, data that)
} else {
//正常上传
that.uploadImg(data, that);
}
}
})
},
});
//因为本文主要讲解图片压缩,所以上传部分就不写了,接下来就是第三步,使用Canvas压缩图片
//图片压缩
compressImg(path, data, that) { //path:未经压缩的图片地址,data:上传的参数 that:当前组件对象
wx.getImageInfo({
src: path,
success: function (res) {
const ctx = wx.createCanvasContext('myCanvas', that)//画布
let ratio = res.width / res.height;
ctx.width = 200;
ctx.height = ctx.width / ratio;
//这里的三行代码,是根据选择的图片的长宽比例,同比缩放
ctx.drawImage(path, 0, 0, ctx.width, ctx.height)//使用Canvas绘制图片,绘制的图片就是压缩后的图片,我们要做的就是拿到这个压缩后的图片
ctx.draw(true, setTimeout(function () {
wx.canvasToTempFilePath({
canvasId: "myCanvas",
x: 0, y: 0,
width: ctx.width,
height: ctx.height,
success: function (res) {
console.log("成功获取压缩后文件" + res);
//到这里就已经拿到了压缩后的图片文件,但是大多数情况下,我们上传的都是base64格式,所以还需要将图片转为base64并上传
wx.getFileSystemManager().readFile({
filePath: res.tempFilePath,
encoding: "base64",
success: res => {
data.base64 = res.data
that.uploadImg(data, property, photoflag, that);
ctx.draw();//清空画布
}
})
},
}, that)
}, 500))
}
})
},
2.踩过的坑
做这个功能一共用来2天的时间,百度上的有关这种压缩方式的坑也是五花八门,我只说我遇到的,并附上解决方法。
第一个坑:绘制完压缩图片后,拿不到压缩后的图片
解决方法:ctx.draw的回调中调用wx.canvasToTempFilePath就可以拿到。
第二个坑:ctx.draw的回调不执行
解决方法:在回调函数的外面套一个一次性定时器
第三个坑:进了回调后报错
解决方法:如果你是写在自定义组件中,那么你需要在wx.createCanvasContext(‘myCanvas’, that)和ctx.draw(true,setTimeout(function () {
wx.canvasToTempFilePath({},that)
},时间)中传入当前组件对象,这里去看官方文档就行,官方文档对这两个api都有描述。
第四个坑:传入that后,无任何反应,即success,fail,complete都不进
解决方法:我遇到这个问题的原因是我wxml中的Canvas标签是隐藏的,所以无法找到,但是这个错误是不报错的,所以我很长时间都不明白为什么,到底是哪里写错了才导致了这个问题,解决方法就是不隐藏Canvas标签,如果你不想在页面中看到Canvas标签,可通过CSS解决
.press-canvas {
position: absolute;
top: -1000px;
background-color: gray;
}
3.总结
这就是我在使用Canvas压缩图片过程中遇到的坑,希望能帮助到踩到这个坑的你。