在做商城管理后台的时候运用到了小程序,需求中遇到了需要上传图片压缩。本来以为比较容易。也踩过一些坑。特此记录下来。
wxml部分
项目中使用了canvas的形式进行图片的压缩。所以这里需要有一个canvas标签。因为canvas有默认宽高所以需要通过js获取 。
<canvas canvas-id="attendCanvasId" class="canvasImg" style="display:block;width:{{canvasSize.width}}px;height:{{canvasSize.height}}px;"></canvas>
wxss 部分
canvas是默认为块元素。所以为了不影响页面的布局。我们引入的canvas需要移入到屏幕外
/* 图片上传用的canvas */
.canvasImg{
position:fixed;
left:-9999px;
top:0;
z-index:-1000;
}
good.js部分初始化canvas
var common = require("../../common/common.js"); //操作库
var goodApi = require("../../apis/goodAd.js"); //商品api
/*
** compress 是图片压缩插件我们先导入。
下方具体解释插件的注意事项
***
*/
var imgPress = require("../../utils/compress.js");
Page({
data:{
//画布宽高
canvasSize:{
width:0,
height:0
}
}
})
compress.js 代码
compress.js主要负责调用小程序的图片选择和图片上传api
var common = require("../common/common.js"); //个人的操作库封装。这里只是用到了类似浏览器环境下的alert
/*
**
这里的插件接受两个回调函数一个是图片上传成功的回调函数用于显示图片
第二个回调函数是获取本地选择图片尺寸的回调函数用来回写Canvas宽和高
**
*/
var imgCompress = {
takePhoto: function(fn,sizeCallBack) {
var that = this;
//调用微信选择图片api
wx.chooseImage({
count: 1,
sizeType: ['compressed'],
sourceType: ['album', 'camera'],
success: function(res) {
console.log("这里拿到图片");
console.log(res);
//这一部分很重要我们要从这获取图片的宽高也就是canvas的宽高
//坑点1 ,canvas如果宽高不等于图片的宽高会导致压缩之后的图片绘制不完全。或者是被压扁
wx.getImageInfo({
src: res.tempFilePaths[0],
success: function (imgInfoRes) {
var width = imgInfoRes.width;
var height = imgInfoRes.height;
//回写canvas的宽和高
sizeCallBack({
width: width,
height:height
});
var tempFilePaths = res.tempFilePaths;//这个是选择后返回的图片列表
that.getCanvasImg(0, 0, tempFilePaths, width, height, fn);//进行压缩
}
});
}
});
},
getCanvasImg: function(index, failNum, tempFilePaths,width,height, fn) {
var that = this;
if(index < tempFilePaths.length) {
const ctx = wx.createCanvasContext('attendCanvasId');
ctx.drawImage(tempFilePaths[index], 0, 0, width, height);
ctx.draw(true, function () {
index = index + 1; //上传成功的数量,上传成功则加1
//坑点2 wx.canvasToTempFilePath有默认的canvas的宽高300*300
//所以这里需要接受上一步图片选择的时候的宽和高传递过去
wx.canvasToTempFilePath({
canvasId: 'attendCanvasId',
width:width, //这里是绘制canvas图片的宽
height:height,
destHeight: height, //输出图片也需要设置因为默认等于上方的width和Height的值所以这里可以不用设置
destWidth: width,
success: function success(res) {
console.log("这里开始压缩");
console.log(JSON.stringify(res));
that.uploadCanvasImg(res.tempFilePath, fn);
that.getCanvasImg(index, failNum, tempFilePaths, width, height);
},
fail: function (e) {
failNum += 1; //失败数量,可以用来提示用户
that.getCanvasImg(inedx, failNum, tempFilePaths, width, height);
console.log("压缩失败的配置");
}
});
});
}
},
uploadCanvasImg: function(canvasImg, fn) {
var that = this;
var tempImg = canvasImg;
wx.showLoading({
title: '上传中',
})
wx.uploadFile({
url: url, //你的服务器的地址
filePath: tempImg,
formData: {
paramPath: "gift"
},
name: 'file',
success: function(res) {
//上传成功返回的图片数据
var json2map = JSON.parse(res.data);
if(fn && typeof fn == "function" && json2map.iRet == 0) {
wx.hideLoading();
//回写图片路径用于显示
fn(json2map.objData.sUrl);
}
},
fail: function(err) {
wx.hideLoading();
//上传失败抛出提示
common.messageBox.showModal(JSON.stringify(err));
}
})
},
init: function(fn,sizeCallBack) {
this.takePhoto(fn, sizeCallBack);
}
}
module.exports = imgCompress;
最后使用的坑
/*
在good.js中通过uploadImg函数触发图片进行上传
*/
uploadImg: function(e) {
console.log("这里上传");
var self = this;
console.log(e);
var judeImg = e.target.dataset.name;
console.log(judeImg);
//这里使用到了compresss插件中的init方法
//笔者的需求是上传不同类型的图片所以这里做了处理
imgPress.init(function(res) {
switch(judeImg) {
case "mainImg":
self.setData({
['goodItem.mainImg']: res
})
break;
case "detailImg":
self.setData({
['goodItem.detailImg']: res
})
break;
default:
self.setData({
['plusModal.img']: res
})
break;
}
/*
**坑点3**。因为canvas会记住上次我们上传图片的宽和高如果不进行重
置,就相当于上传了一个小尺寸的图片,
然后上传一个大图。因为画布太小。所以画出来的图片就不完整了
*/
self.setData({
['canvasSize.width']: 0,
['canvasSize.height']: 0
});
},function(size){
//这里是第二个回调我们拿到了图片尺寸之后正确的初始化了canvas宽和高
self.setData({
['canvasSize.width']: size.width,
['canvasSize.height']: size.height
});
});
},
写在最后的话
开发小程序特别是图片上传的时候当初以为特别容易来着,最后发现也是有不少的坑。这些都是个人的经验总结。希望对你有所帮助。