前段时间写过一次h5利用canvas压缩图片的方法,本以为小程序压缩也大同小异,结果不慎掉入坑中爬了好久,这里以uniapp 为例总结一下:
canvas压缩多张图片(一)
canvas压缩多张图片(二)
上传图片 chooseImage
这里要和h5利用input 上传不同,这里需要利用chooseImage上传图片
uni.chooseImage({
count: 9,
sourceType: ['album','camera'],
sizeType: ['compressed'],
success(res) {
if(res.errMsg =='chooseImage:ok'){
that.urlTobase64Fn(res.tempFilePaths)
}
}
})
遍历图片数据,进行压缩处理 ,记得要加 id 和 this
async urlTobase64Fn (arr){
for(let i=0;i<arr.length;i++){
//这里很重要 canvasId this
let base64=await urlTobase64(arr[i],"canvasId",this);
this.imgArr.push(base64)
}
},
<canvas id="canvasId" class="canvasId" canvas-id="canvasId" ></canvas>
.canvasId{
position: absolute;
top:-9999rpx;
left: -9999rpx;
z-index: 0;
width: 690rpx;
height: 690rpx;
}
对URL进行处理 urlTobase64 (这是自定义的方法)
//base64
urlTobase64 = async (fileObj,_this)=>{
//截取文件类型,转换为base64
let type=fileObj.type || fileObj.path.substring(fileObj.path.lastIndexOf('.')+1);
let base64 = await getFileSystemManagerFn({
path:fileObj.path,
type
});
base64 = base64.replace(/[\r\n]/g, "");
// console.log(base64,'base')
//如果是视频
if(type =='mp4'){
console.log('是视频,直接输出base64')
//如果上传不是获取视频,则返回空
return fileObj.fileType =='video'?base64 : ''
}
let imgSize = await getBase64SizeFn(base64);
console.log(imgSize,'是图片,判断图片大小');
//自定义图片大小限制、默认为 200kb
fileObj.limitNum = fileObj.limitNum || 1024 *0.2;
if(imgSize >fileObj.limitNum && type !='gif'){
console.log(imgSize,'需要压缩')
let imgInfo = await getImageInfoFn (fileObj.path);
fileObj.canvasId = fileObj.canvasId || 'canvasId';
return await convertImgToBase64Fn({
...fileObj,
oldH : imgInfo.height,
oldW : imgInfo.width,
// path : base64, //用微信临时地址,不要用base64 这里很重要,千万不要打开
type : imgInfo.type
},_this);
} else {
console.log(imgSize,'可以直接使用');
//在限制大小之下,直接返回base64值
return base64
}
},
//canvas 压缩
convertImgToBase64Fn = async (obj,_this) =>{
obj.minW = obj.minW || 750,
obj.minH = obj.minH || 1334;
obj.num = obj.num || 1;
var cvsw,cvsh;
//横向 图
if(obj.oldW > obj.oldH){
cvsh = obj.oldH > obj.minH ? obj.minH : obj.oldH;
cvsw = cvsh / obj.oldH * obj.oldW
} //纵向图
else if(obj.oldW < obj.oldH){
cvsw = obj.oldW > obj.minW ? obj.minW : obj.oldW;
cvsh = cvsw / obj.oldW * obj.oldH
} //正方形
else if(obj.oldW == obj.oldH && obj.oldW > obj.minW){
cvsw = obj.minW;
cvsh = obj.minH;
} //不必重置宽高
else {
cvsw = obj.oldW;
cvsh = obj.oldH;
}
//对宽高 进行取整
cvsw = parseInt(cvsw);
cvsh = parseInt(cvsh);
//设置canvas画布大小
console.log(cvsw,cvsh,'设置canvas画布大小');
_this.windowInfo ={
width:cvsw,
height:cvsh
}
let dataURL = await canvasToTempFilePathFn({...obj,cvsw,cvsh},_this);
console.log(dataURL.substring(0,50),'输出压缩后最终地址')
return dataURL;
},
//将base64 判断大小
getBase64SizeFn =(base64url) =>{
//获取base64图片大小,返回KB数字
var strLength =base64url.length;
var fileLength = parseInt(strLength - (strLength / 8) * 2);
// 由字节转换为KB
var size = "";
size = (fileLength / 1024).toFixed(2);
return parseInt(size) *1;
},
//获取图片信息
getImageInfoFn = (url)=>{
console.log(url,'去获取图片信息')
return new Promise((resolve)=>{
wx.getImageInfo({
src: url,
success: (res)=> {
console.log(res.path,'图片信息')
resolve(res)
}
});
})
},
//绘制画布,并返回图片地址
canvasToTempFilePathFn =(obj,_this)=>{
return new Promise((resolve,reject)=>{
const ctx = uni.createCanvasContext(obj.canvasId,_this);
console.log(obj.num,obj.type,'压缩开始')
ctx.drawImage(obj.path, 0, 0, obj.cvsw, obj.cvsh);
ctx.draw(false, setTimeout(()=>{
uni.canvasToTempFilePath({
canvasId :obj.canvasId,
fileType :obj.type,
quality :obj.num,
width :obj.cvsw,
height :obj.cvsh,
destWidth :obj.cvsw,
destHeight :obj.cvsh,
success: async (res1) =>{
//转换为base64
console.log('去将压缩后的地址转base64')
let base64 = await getFileSystemManagerFn({
path:res1.tempFilePath,
type:obj.type
});
base64 = base64.replace(/[\r\n]/g, "");
console.log('去后去压缩后的base64大小')
let imgSize = getBase64SizeFn(base64);
if( imgSize >= obj.limitNum && obj.num >0.6){
console.log(imgSize,'图片过大,继续压缩')
obj.num = obj.num - 0.2 ;
obj.num = obj.num.toFixed(2) *1;
//重置图片格式
if(obj.type =='png' || obj.type =='PNG'){
obj.type ='png'
} else{
obj.type ='jpg'
}
//继续压缩
canvasToTempFilePathFn({...obj},_this).then((res2)=>{
resolve(res2)
});
} else{
console.log(imgSize,'最终压缩后图片大小')
resolve(base64)
}
},
fail: function (e) {
console.log('失败')
reject(e)
}
},_this)
},200));
})
},
//将图片转 base64
getFileSystemManagerFn =(obj)=>{
// console.log(obj.path,'图片地址')
return new Promise(async (resolve,reject)=>{
let path = obj.path;
//微信图片,先去下载
if(path.indexOf('https://wx.qlogo.cn') >=0){
path = await downloadFileFn(path);
}
// console.log(path,'地址')
wx.getFileSystemManager().readFile({
filePath:path,
encoding:'base64',
success: async res=>{
console.log(obj.type,'图片类型')
let base64=`data:image/${obj.type};base64,${res.data}`;
resolve(base64)
}
});
})
},
//将图片下载到本地
downloadFileFn =(url)=>{
return new Promise ((resolve,reject)=>{
wx.downloadFile({
url,
success(res) {
resolve(res.tempFilePath)
},
fail:err=>{
reject(err)
}
})
})
}