微信小程序开发过程中,有上传图片的需求,但是由于微信自带的压缩功能无法把图片压缩到指定大小,或者根据情况来压缩或者不压缩,那就就需要用到自己的压缩处理办法。
本我我已我的在线客服发送图片为例,讲解一下微信图片压缩的实现。
1 微信图片选择进行压缩的场景。
我的在线客服系统,支持发送图片,但是小程序中默认打开相册之后,往往图片比较大,而且由于手机的不同像素往往都比较高,图片就比较大,但是在线客服系统,往往不需要这么高质量图片,而且受限于socket的连接时间限制,上传时间就必须要快,所以我这里就需要对微信选择的图片进行压缩。
注意:由于微信上传和canvas的接口已经变更,网上有一些代码已经不符合现在新版微信canvas的接口要求了,所以这里代码是确定保证能够正常运行的代码。
uniapp小程序开发:
chooseImage() {
let _this = this;
_this.imguploading = true;
wx.chooseImage({
count: 1,
sizeType: ["compressed"],
success: (res) => {
const tempFilePath = res.tempFilePaths[0];
wx.getFileSystemManager().getFileInfo({
filePath: tempFilePath,
success: function (res) {
let cW = res.width,
cH = res.height,
rat = 1.1;
_this.cWidth = cW;
_this.cHeight = cH;
},
});
// wx.getFileInfo({
// filePath: tempFilePath,
// success: function (res) {
// let cW = res.width,
// cH = res.height,
// rat = 1.1;
// _this.cWidth = cW;
// _this.cHeight = cH;
// },
// });
getLessLimitSizeImage(
"canvas",
_this,
tempFilePath,
400,
500,
function (img) {
console.log(img, "---");
wx.uploadFile({
// url: `${http_protocol}://${hostname}:${http_port}/im/image/upload.html?userid=${_this.config.userid}&appid=${_this.config.appid}&username=${_this.config.name}&orgi=${_this.config.orgi}`,
url: `${http_protocol}://${hostname}/im/image/upload.html?userid=${_this.config.userid}&appid=${_this.config.appid}&username=${_this.config.name}&orgi=${_this.config.orgi}`,
name: "imgFile",
filePath: img,
success: function (res) {
_this.imguploading = false;
//上传成功
// debugger;
},
fail: function (res) {
_this.imguploading = false;
_this.$u.func.showToast({ title: "发送图片失败,请重试" });
debugger;
},
});
}
);
},
fail: (res) => {
_this.imguploading = false;
// _this.$u.func.showToast({ title: "发送图片失败,请重试" });
},
complete: (res) => {
_this.imguploading = false;
},
});
},
如上代码
sizeType: ["compressed"]
这个地方是微信自带的压缩方式,但是并不满足我们的需求,所以需要配合我们的自定义函数和canvas实现。
wx.getFileSystemManager().getFileInfo() 这里是微信新版接口获取图片信息的接口。有好处也有缺点。后面会讲旧版wx.getFileInfo接口的优点。
2 通过自定义函数getLessLimitSizeImage实现对图片的压缩。
getLessLimitSizeImage函数参数。
canvasId: 微信canvas 2.0的id值
currentInstance: 这个很重要,这就是当前页面组件的实例,这个就是自定义函数内部用来使用wx.createSelector的api中in(this)的对象,不让我们是无法从过query方法去获取当前页面的canvas的。
imagePath: 这个这就微信wx.chooseImage API返回的临时图片经验,也是通过这个图片我们实现再canvas上绘制截图的。
limitSize = 100 这个是对小于100KB的图片不进行压缩限制。
drawWidth: 这个就是我们要压缩到的目标宽度
callBack: 这个就是我们压缩完成后重新拿到的图片回调函数。
3 接下来就是我们这个函数的封装
//*************** 图片压缩 ***********
// 判断图片大小是否满足需求
function imageSizeIsLessLimitSize(
imagePath,
limitSize,
lessCallBack,
moreCallBack
) {
wx.getFileSystemManager().getFileInfo({
filePath: imagePath,
success(res) {
console.log("压缩前图片大小:", res.size / 1024, "kb");
if (res.size > 1024 * limitSize) {
moreCallBack();
} else {
lessCallBack();
}
},
});
}
/**
* 获取画布图片
*/
// 利用cavas进行压缩
function getCanvasImage(
canvasId,
currentInstance,
imagePath,
imageW,
imageH,
getImgsuccess
) {
// const ctx = wx.createCanvasContext(canvasId);
wx.createSelectorQuery()
.in(currentInstance)
.select("#" + canvasId)
.node(({ node: canvas }) => {
canvas.width = imageW;
canvas.height = imageH;
const ctx = canvas.getContext("2d");
const bg = canvas.createImage();
bg.src = imagePath;
bg.onload = () => {
ctx.save();
ctx.translate(canvas.width / 2, canvas.height / 2);
ctx.translate(-canvas.width / 2, -canvas.height / 2);
ctx.drawImage(bg, 0, 0, imageW, imageH);
ctx.restore();
wx.canvasToTempFilePath({
canvas,
fileType: "jpg",
quality: 1,
success: (res) => {
getImgsuccess(res.tempFilePath);
},
});
};
})
.exec();
}
// 主调用方法
/**
* 获取小于限制大小的Image
*/
function getLessLimitSizeImage(
canvasId,
currentInstance,
imagePath,
limitSize = 100,
drawWidth,
callBack
) {
imageSizeIsLessLimitSize(
imagePath,
limitSize,
(lessRes) => {
callBack(imagePath);
},
(moreRes) => {
wx.getImageInfo({
src: imagePath,
success: function (imageInfo) {
var maxSide = Math.max(imageInfo.width, imageInfo.height);
var windowW = drawWidth;
var scale = 1;
if (maxSide > windowW) {
scale = windowW / maxSide;
}
var imageW = Math.trunc(imageInfo.width * scale);
var imageH = Math.trunc(imageInfo.height * scale);
getCanvasImage(
canvasId,
currentInstance,
imagePath,
imageW,
imageH,
(pressImgPath) => {
console.log("callback", pressImgPath);
getLessLimitSizeImage(
canvasId,
currentInstance,
pressImgPath,
limitSize,
drawWidth * 0.95,
callBack
);
}
);
},
});
}
);
}
function getBase64(img) {
return new Promise(function (resolve, reject) {
const FSM = wx.getFileSystemManager();
FSM.readFile({
filePath: img,
encoding: "base64",
success(data) {
resolve(data);
},
});
});
}
export {
getLessLimitSizeImage,
imageSizeIsLessLimitSize,
getCanvasImage,
getBase64,
};
以上就是对自定义函数的分装,本文结合了最新的微信api实现。
createSelectorQuery这个微信提供的查找页面dom的方法,这里如果要查找canvas的话,按照目前新版微信api的话,要确保再in(this)的情况下才会找到,并且canvas的写法上也有所不同。
<canvas
class="canvas"
id="canvas"
type="2d"
:style="{
width: cWidth + 'px',
height: cHeight + 'px',
visibility: 'hidden',
position: 'absolute',
'z-index': '-1',
left: '-10000rpx',
top: '-10000rpx',
}"
></canvas>
这就是本人目前再小程序中实现的图片压缩的方法。欢迎指正。
如上图是一张大图片
经过压缩
目前从整体情况来看,非常符合我们的实际需求。