功能期望:图片需要压缩至100KB以下
注意:
1 下方用大小判断是80kb,为了防止图片输出是其大小变化有误差;
2 canvas 的大小一定要动态设置,不能写死
3 为了防止用于压缩的canvas影响页面,将其绝对定位到其他地方
index.wxml
<el-button bindtap="selectImg">选择图片</el-button>
<canvas canvas-id="myCanvas"
style="position:fixed;right:-{{canvasW/1+300}}px;bottom:{{canvasH/1+1000}}px;width: {{canvasW}}px; height: {{canvasH}}px"></canvas>
index.js
selectImg(){
wx.showLoading({title:"加载中"})
util.chooseImage({
self:this,
endSize:100,//目标压缩至100kb以下
success:(chooseImageRes) => {
wx.showLoading({title:"加载中"})
// 返回压缩后的图片
},
fail:err=>{
wx.hideLoading()
wx.showToast({
icon:"none",
title: '图片选择失败,请重新尝试',
})
}
})
},
util.js
function chooseImage(options) {
const self=options.self;
wx.chooseImage({
count: 1,
sizeType: ['compressed'],
sourceType:['album', 'camera'],
success: res => {
console.log('图片选择成功',new Date().getSeconds())
let fileSize = res.tempFiles[0].size / 1024
console.log('图fileSize',fileSize)
const endSize=options.endSize||80;
console.log('endSize',endSize)
if (fileSize > endSize) {
photoCompress({
self:self,
path:res.tempFiles[0].path,
quality:8,
endSize:endSize
},options.success,options.fail)
}else{
photoHandle({
self:self,
endSize:options.endSize,
path:res.tempFiles[0].path,
}, options.success,options.fail)
}
},
fail: err => {
// console.log(err)
if(options.fail) options.fail(err)
}
})
}
// 图片压缩
/*
self 页面this
path 图片地址,wx.getImageInfo要求path是图片的本地路径
quality 图片质量 1-10区间,因为下方会乘以0.1
callback 回调返回 (path, base64)
*/
function photoCompress(options, callback, failCallback) {
const self=options.self;
const path=options.path;
const quality=options.quality;
const endSize=options.endSize;
console.log('photoCompress压缩开始',options)
wx.getImageInfo({
src: path,
success: Infores => {
const initW= Infores.width,initH= Infores.height;
if(initW>initH){
var width = initW>800?800:initW;
var base =initW/width;
var height = parseInt(initH / base);
}else{
var height = initH>800?800:initH;
var base =initH/height;
var width = parseInt(initW / base);
}
self.setData({
canvas_quality:quality,
canvasW:width,
canvasH:height
})
// console.log('getImageInfo--',res,width,height,base,quality)
let ctx = wx.createCanvasContext('myCanvas')
ctx.drawImage(Infores.path, 0, 0, width, height)
ctx.draw(true, () => {
setTimeout(()=>{
wx.canvasToTempFilePath({
quality: quality*0.1,
fileType: 'jpg',//quality仅对jpg有效
canvasId: 'myCanvas',
width: width,
height: height,
destWidth: width,
destHeight: height,
success: res => {
// console.log('canvasToTempFilePath--',res)
photoHandle({
self:self,
endSize:endSize,
path:res.tempFilePath,
},callback,failCallback)
ctx.clearRect(0, 0, width, height)
},
fail: err => {
// console.log('canvasToTempFilePath--fail',err)
if(failCallback) failCallback(err)
}
})
},300)
})
},
fail:err=>{
if(failCallback) failCallback(err)
}
})
}
// 生成base64
function photoHandle(options, callback,failCallback) {
const self=options.self;
const path=options.path;``
const endSize=options.endSize;
console.log('photoHandle',options)
let base64Img = 'data:image/jpg;base64,' + wx.getFileSystemManager().readFileSync(path, "base64")
if(showSize(base64Img)/1>endSize){
console.log('压缩后',showSize(base64Img))
self.data.canvas_quality=self.data.canvas_quality-1;
if(self.data.canvas_quality<=4){//后面备注该处处理原因
console.log('跳出压缩',showSize(base64Img))
callback && callback({path:path, base64:base64Img})
return
}
photoCompress({
self:self,
path:path,
quality:self.data.canvas_quality,
endSize:endSize
},callback,failCallback)
}else{
console.log('压缩结束',showSize(base64Img))
callback && callback({path:path, base64:base64Img})
}
}
// 获取base64图片大小,返回kb数字
function showSize(base64url) {
//把头部去掉
var str = base64url.replace('data:image/png;base64,', '');
// 找到等号,把等号也去掉
var equalIndex = str.indexOf('=');
if(str.indexOf('=')>0) {
str=str.substring(0, equalIndex);
}
// 原来的字符流大小,单位为字节
var strLength=str.length;
// 计算后得到的文件流大小,单位为字节
var fileLength=parseInt(strLength-(strLength/8)*2);
// 由字节转换为kb
var size = "";
size = (fileLength / 1024).toFixed(2);
var sizeStr = size + ""; //转成字符串
var index = sizeStr.indexOf("."); //获取小数点处的索引
var dou = sizeStr.substr(index + 1, 2) //获取小数点后两位的值
if (dou == "00") { //判断后两位是否为00,如果是则删除00
return sizeStr.substring(0, index) + sizeStr.substr(index + 3, 2)
}
return size;
}
备注:
if(self.data.canvas_quality<=4)
防止quality过小模糊或反复的压缩无法跳出循环 最小4,该做法可能不能将图片压缩至目标值,有想过再改变canvas的宽度继续压缩,由于当前已适合业务需求,因此没有再试
实现过程中遇见的问题:
canvas绘制图片不全
原因:canvas宽高写死;
解决:canvas宽高动态读取绘制的图片的宽高对应设置
canvas绘制图片正常,图片输出不完整
现象:
检查压缩的canvas图片绘制正常且完整,但是输出的图片偶现不完整。
原因:
wx.canvasToTempFilePath 回调时机有问题,将其延迟一段时间执行