文章目录
前言
关于微信小程序、H5兼容性问题,今天就压缩以及上传图片做一个可实现方法的简要阐述。
一、为什么要压缩图片
在使用uni-app开发小程序及H5的具体业务中,我们会遇到需要让用户上传本地图片的场景,随着现在的手机像素越来越高,图片的大小也越来越大,上传原图后一方面是难以上传成功,另一方面是上传成功后在列表中图片太大加载时间过长或者加载失败。若是直接提示用户 “无法上传xxM以上的图片” ,用户体验会不好,于是需要我们对用户上传的图片进行压缩。而不同平台之间压缩图片的方式并不完全兼容,需要提供不同的方法来实现。本文主要记录了在不同平台实现图片压缩上传的其中一种可实现方法。
二、图片压缩方式
uni-app官方提供了关于图片的一系列内置API
首先从选择图片开始
uni.chooseImage(OBJECT) 从本地相册选择图片或使用相机拍照。
// 该方法兼容小程序、H5
uni.chooseImage({
count:1,
sizeType: ['compressed'],
success: res => { // success: 成功则返回图片的本地文件路径列表
let size = res.tempFiles[0].size // 选择第一张图片
console.log('图片大小', size, `${size/1000}KB`, `${size/1000/1000}MB`)
}
})
1. 微信小程序
小程序压缩图片的方式相对比较简单,不过有一定的局限性,仅对 jpg 格式有效。
uni.compressImage(OBJECT) 压缩图片接口,可选压缩质量。
// 该方法兼容app和小程序,不兼容h5,且仅对jpg格式有效
uni.compressImage({
src: src, // 图片路径
quality: 10, // 图片压缩质量,0~100,默认80,仅对jpg有效
success: res => {
console.log(res.tempFilePath,'压缩后的图片路径')
// 接下来可以在这里处理图片上传
}
})
uni.getFileSystemManager() 获取全局唯一的文件管理器
readFile() 读取文件,可转换编码格式
// 该方法不兼容h5
uni.getFileSystemManager().readFile({
filePath: path, // 要读取的文件路径
encoding: 'base64', // 编码格式
success: file => {
wx_uploadImage({ // 调用接口实现上传图片,使用其他方式也可以
image: `data:image/png;base64,${file.data}`
}).then(res => {
console.log('上传图片成功', res)
this.image = res.storage_path // 赋值或者其他操作
})
}
})
2. H5
H5需要使用另外的方式来压缩图片,这里用到了canvas。
- 分三步 -
1. 使用canvas限制图片大小(压缩图片),并转换为"blob路径";
uni.getImageInfo() 获取图片信息
uni.getImageInfo({
src,
success(res) {
console.log('压缩前', res);
let canvasWidth = res.width; // 图片原始宽度
let canvasHeight = res.height; // 图片原始高度
console.log('宽度-',canvasWidth,'高度-',canvasHeight);
let img = new Image();
img.src = res.path;
let canvas = document.createElement('canvas');
let ctx = canvas.getContext('2d');
// 这里根据要求限制图片宽高
if (canvasWidth >= 1000) {
canvas.width = canvasWidth * .1;
} else {
canvas.width = canvasWidth;
}
if (canvasHeight >= 1000) {
canvas.height = canvasHeight * .1;
} else {
canvas.height = canvasHeight;
}
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
//toBlob()方法创造Blob对象,用以展示canvas上的图片
canvas.toBlob(function(fileSrc) {
let imgSrc = window.URL.createObjectURL(fileSrc);
console.log('压缩后的blob路径', imgSrc);
});
}
});
2. 将 "blob路径" 转换为 "blob文件"(待会转换base64格式图片需要用到 "blob文件" 的格式)
// 传入blob路径,.then()获取blob文件
httpRequest(src) {
let that = this
return new Promise((resolve, reject) => {
let xhr = new XMLHttpRequest()
xhr.open('GET', src, true)
xhr.responseType = 'blob'
xhr.onload = function (e) {
if (this.status == 200) {
let myBlob = this.response
let files = new window.File(
[myBlob],
myBlob.type,
{ type: myBlob.type }
) // myBlob.type 自定义文件名
resolve(files)
} else {
reject(false)
}
}
xhr.send()
})
},
3. 将 "blob文件" 转换为 base64格式的图片,最后上传图片。
const fileReader = new FileReader()
fileReader.readAsDataURL(file) // 读取blob类型的图像文件(不是blob路径),读取成功触发onload方法,并得到result(base64格式的图片)
fileReader.onload = (event) => {
console.log(fileReader.result,'fileReader.result - base64格式');
if (fileReader.result) {
// 调用wx_uploadImage接口,图片大小必须是1M以下,否则报错
wx_uploadImage({
image: fileReader.result
}).then(res => {
console.log('上传图片成功', res)
this.image = res.storage_path
})
}
}
总结
总结一下以上逻辑经过封装后的完整代码:
// 使用条件编译区分微信小程序、H5的图片压缩上传方式
// 点击上传图片
chooseImage(){
uni.chooseImage({
count:1,
sizeType: ['compressed'],
success: res => {
let size = res.tempFiles[0].size
console.log('图片大小', size, `${size/1000}KB`, `${size/1000/1000}MB`)
let path = this.picture_show = res.tempFilePaths[0] //本地图片路径 - path
let file = res.tempFiles[0] //本地图片文件 - file
let compressPath = ''
console.log(path,'路径');
console.log(file,'图片文件');
// 先压缩,再转换为base64图片,再上传
// #ifdef MP-WEIXIN
if (size > 1048576) {
this.mp_compressImage(path)
} else {
this.mp_filetobase64(path)
}
// #endif
// #ifdef H5
if (size > 1048576) {
this.h5_compressImage(path);
} else {
this.h5_filetobase64(file)
}
// #endif
}
})
},
// 微信小程序 - 图片压缩方法
mp_compressImage(src) {
let _this = this
// 该方法兼容app和小程序,不兼容h5,且仅对jpg格式有效
uni.compressImage({
src: src, // 图片路径
quality: 10, // 图片压缩质量,0~100,默认80,仅对jpg有效
success: res => {
console.log(res.tempFilePath,'压缩后的图片路径')
// 接下来可以在这里处理图片上传
_this.mp_filetobase64(res.tempFilePath)
}
})
}
// 微信小程序 - 'blob路径'转base64图片的方法
mp_filetobase64(path) {
// 该方法不兼容h5
uni.getFileSystemManager().readFile({
filePath: path, // 要读取的文件路径
encoding: 'base64', // 编码格式
success: file => {
wx_uploadImage({ // 调用接口实现上传图片,使用其他方式也可以
image: `data:image/png;base64,${file.data}`
}).then(res => {
console.log('上传图片成功', res)
this.image = res.storage_path // 赋值或者其他操作
})
}
})
}
// h5 - 图片压缩方法
h5_compressImage(src) {
let _this = this;
uni.getImageInfo({
src,
success(res) {
console.log('压缩前', res);
let canvasWidth = res.width; // 图片原始宽度
let canvasHeight = res.height; // 图片原始高度
console.log('宽度-',canvasWidth,'高度-',canvasHeight);
let img = new Image();
img.src = res.path;
let canvas = document.createElement('canvas');
let ctx = canvas.getContext('2d');
// 这里根据要求限制图片宽高
if (canvasWidth >= 1000) {
canvas.width = canvasWidth * .1;
} else {
canvas.width = canvasWidth;
}
if (canvasHeight >= 1000) {
canvas.height = canvasHeight * .1;
} else {
canvas.height = canvasHeight;
}
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
//toBlob()方法创造Blob对象,用以展示canvas上的图片
canvas.toBlob(function(fileSrc) {
let imgSrc = window.URL.createObjectURL(fileSrc);
console.log('压缩后的blob路径', imgSrc);
// 调用httpRequest方法,把bloburl转换成blob文件
_this.httpRequest(imgSrc).then(res => {
console.log(res,'成功转换为blob文件');
_this.h5_filetobase64(res); // 调用方法,把blob文件转换成base64图片
})
});
}
});
}
// 传入blob路径,.then()获取blob文件
httpRequest(src) {
let that = this
return new Promise((resolve, reject) => {
let xhr = new XMLHttpRequest()
xhr.open('GET', src, true)
xhr.responseType = 'blob'
xhr.onload = function (e) {
if (this.status == 200) {
let myBlob = this.response
let files = new window.File(
[myBlob],
myBlob.type,
{ type: myBlob.type }
) // myBlob.type 自定义文件名
resolve(files)
} else {
reject(false)
}
}
xhr.send()
})
},
// h5 - 'blob文件'转base64图片的方法
h5_filetobase64(file) {
const fileReader = new FileReader()
fileReader.readAsDataURL(file) // 读取blob类型的图像文件(不是blob路径),读取成功触发onload方法,并得到result(base64格式的图片)
fileReader.onload = (event) => {
console.log(fileReader.result,'fileReader.result - base64格式');
if (fileReader.result) {
// 调用wx_uploadImage接口,图片大小必须是1M以下,否则报错
wx_uploadImage({
image: fileReader.result
}).then(res => {
console.log('上传图片成功', res)
this.image = res.storage_path
})
}
}
}