领导让图片上传前做校验并进行压缩,给了一个vue的案例,是需要传入base64的,但是小程序是获取到图片地址。虽然最后用了别的方法进行图片压缩,但是既然搜到了转base64,那就记录一下,防止自己忘记。
比如我是在van-uploader的 before-read 中进行的,
以下是图片url转base64的方式:
.wxml中:
<van-uploader file-list="{{ imgList }}" max-count="5" upload-icon="scan" bind:after-read="afterRead" bind:delete="imgDelete" use-before-read="{{ true }}" bind:before-read="beforeRead" />
.js中:
beforeRead(event) {
const { file, callback } = event.detail;
this.getImageBase64_readFile(file.tempFilePath).then((res) => {
callback(res); //res 为 base64流
})
},
//图片转base64
async getImageBase64_readFile(tempFilePath) {
return await new Promise(resolve => {
//获取全局唯一的文件管理器
wx.getFileSystemManager().readFile({ //读取本地文件内容
filePath: tempFilePath, // 文件路径
encoding: 'base64', // 返回格式
success: ({
data
}) => {
// 这里必须要用'data:image/png;base64,'前缀,
resolve('data:image/png;base64,' + data);
}
});
});
},
该代码块是base64转图片url↓:
// base64: 图片的base64文件流,最后用callback返出去
base64ImgtoFile(base64, callback) {
const fsm = wx.getFileSystemManager();
const FILE_BASE_NAME = new Date().getTime(); //自定义文件名(这里以时间戳为文件名)
const [, format, bodyData] = /data:image\/(\w+);base64,(.*)/.exec(base64) || [];
if (!format) {
return (new Error('ERROR_BASE64SRC_PARSE'));
}
const imageUrl= `${wx.env.USER_DATA_PATH}/${FILE_BASE_NAME}.png`;
const buffer = wx.base64ToArrayBuffer(bodyData);
fsm.writeFile({
imageUrl,
data: buffer,
encoding: 'binary',
success() {
callback(imageUrl); //返出图片url
},
fail() {
return (new Error('ERROR_BASE64SRC_WRITE'));
},
});
}
使用时:
base64ImgtoFile(base64, resCurrent => {
let imageUrl = resCurrent // resCurrent 是返回的图片地址
// 这里可以进行自己的业务逻辑
})
在这里延伸一个小程序的图片压缩方法(因为我的业务用到的地方比较多,所以提出来放在了utils里面,随时使用):
// 压缩图片
const compressImg = (imageUrl) => {
let _this = this;
return new Promise((resolve, reject) => {
//获取原图片信息 canvas压缩实现
wx.getImageInfo({
src: imageUrl,
success: function (res) {
// let canvasRatio = 1.1;
var quality = 0.8; //压缩系数0-1之间,越小越模糊(这里是用来压缩图片体积达到压缩效果的,和下面的修改图片大小为两种类型)
let picWidth = res.width/2 //图片原始长宽
let picHeight = res.height/2
// while (picWidth > 600 || picHeight > 600) { // 保证宽高在600以内(通过宽高修改来修改图片大小,如果你要通过改变图片大小来控制图片体积的话,就可以放开这里的代码)
// picWidth = Math.trunc(res.width / canvasRatio)
// picHeight = Math.trunc(res.height / canvasRatio)
// canvasRatio = canvasRatio + 0.1;
// }
const query = wx.createSelectorQuery()
query.select('#picCanvas').fields({
node: true,
size: true
}).exec((res) => {
try {
const canvas = res[0].node
const ctx = canvas.getContext('2d')
// let dpr = wx.getSystemInfoSync().pixelRatio
//这里是设置css样式的宽高。
//属性宽高是css样式宽高的dpr倍,兼容不同机型,避免绘制的内容模糊。
// _this.setData({
// canvasWidth: picWidth / dpr,
// canvasHeight: picHeight / dpr
// })
canvas.width = picWidth
canvas.height = picHeight
const img = canvas.createImage()
img.src = imageUrl
img.onload = () => {
ctx.drawImage(img, 0, 0, picWidth, picHeight); //先画出图片
var base64 = canvas.toDataURL("image/jpeg",quality ); //压缩语句(压缩体积,不改变宽高大小,quality可以动态改变,这里压缩后返回的是图片base64)
//这里可以用base64转图片url的方法,转化成图片url然后给resolve出去,也可以直接在resolve
resolve(base64)
//延迟600ms,避免部分机型未绘制出图片内容就执行保存操作,导致最终的图片是块白色画板。
// setTimeout(() => {
// wx.canvasToTempFilePath({
// fileType: "jpg",
// canvas: canvas,
// destWidth: picWidth,
// destHeight: picHeight,
// success: function (res) {
// return resolve(res.tempFilePath) //返回压缩后的图片
// }
// }, _this)
// }, 600)
}
} catch (e) {
//异常后的操作
}
})
}
})
})
}
完毕,我是把压缩和转url放在了一个方法里面,如果你们也需要压缩后的图片Url,也可以像我一样,直接放在一起
注意:在使用canvas压缩图片的时候,wxml文件中一定要加上,以下代码,不然无法上传图片以后无法显示
<!-- 在压缩中需要用到,这里通过css控制在界面上不可见 -->
<canvas style="width:{{canvasWidth}}px;height:{{canvasHeight}}px;position:fixed;left:100%;" id="picCanvas" type="2d"></canvas>
参考地址: