项目是用uniapp开发的,当时只是做App端,后来项目扩展到H5端, uniapp框架可以跨平台所以移动端和H5使用的是一套代码
上传头像的时候要求图片的大小在2MB一下,所以要压缩图片,App端当时使用的是uni.compressImage(OBJECT)压缩的(详情见:https://uniapp.dcloud.net.cn/api/media/image.html#compressimage 但是H5不兼容;
先搞定H5的压缩吧!网上一搜一大把
/**
* H5压缩 二分查找算法来找到一个合适的图像质量系数,使得压缩后的图片文件大小接近于目标大小
* @param {Object} imgSrc 图片url
* @param {Object} callback 回调设置返回值
* */
export function compressH5(fileItem, targetSizeKB, initialQuality = 1.0) {
const maxQuality = 1.0;
const minQuality = 0.0;
const tolerance = 0.01; // 根据需要调整公差
return new Promise((resolve, reject) => {
const binarySearch = (min, max) => {
const midQuality = (min + max) / 2;
const reader = new FileReader();
reader.readAsDataURL(fileItem);
reader.onload = function () {
const img = new Image();
img.src = this.result;
img.onload = function () {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = img.width;
canvas.height = img.height;
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
// 使用异步的 toBlob 方法
canvas.toBlob(async (blob) => {
const fileSizeKB = blob.size / 1024;
if (Math.abs(fileSizeKB - targetSizeKB) < tolerance || max - min < tolerance) {
// 当前质量足够接近目标大小,使用当前质量解析
resolve(URL.createObjectURL(blob));
} else if (fileSizeKB > targetSizeKB) {
// 如果文件大小太大,降低质量,继续二分查找
binarySearch(min, midQuality);
} else {
// 如果文件大小太小,增加质量,继续二分查找
binarySearch(midQuality, max);
}
}, 'image/jpeg', midQuality);
};
};
reader.onerror = function (error) {
reject(error);
};
};
// 开始二分查找
binarySearch(minQuality, maxQuality);
});
}
调用方法
chooseImg1() {
uni.chooseImage({
count: 1, //默认9
sizeType:['compressed'],
success: (chooseImageRes) => {
const tempFilePaths = chooseImageRes.tempFilePaths;
const filePath = tempFilePaths[0];
// 获取图片文件大小
uni.getFileInfo({
filePath: filePath,
success: (fileInfo) => {
const fileSize = fileInfo.size; // 图片文件大小,单位为B
// 判断图片大小是否超过200KB
if (fileSize > 200 * 1024) {
//#ifdef H5
//h5压缩图片
const targetSizeKB = 150; // 设置目标文件大小,单位为KB,根据需求调整
compressH5(chooseImageRes.tempFiles[0],targetSizeKB).then(file => {
console.log('file 222 = ', file)
this.uploadCompressedImage(file);
}).catch(err => {
console.log('catch', err)
})
//#endif
//#ifdef APP-PLUS || MP-WEIXIN
// 如果超过200KB,进行压缩
uni.compressImage({
src: filePath,
quality: 10, // 设置压缩质量(0-100)- 根据需求进行调整
success: (compressRes) => {
// 压缩成功后的逻辑
this.uploadCompressedImage(compressRes.tempFilePath);
},
fail: (err) => {
console.error('压缩图片失败:', err);
uni.showToast({
title: '压缩图片失败,请重试',
icon: 'none'
});
}
});
//#endif
} else {
// 如果未超过200KB,直接上传原图
this.uploadCompressedImage(filePath);
}
},
fail: (err) => {
console.error('获取文件信息失败:', err);
uni.showToast({
title: '获取文件信息失败,请重试',
icon: 'none'
});
}
});
},
fail: (err) => {
console.error('选择图片失败:', err);
uni.showToast({
title: '选择图片失败,请重试',
icon: 'none'
});
}
});
},
uploadCompressedImage(filePath) {
uni.uploadFile({
url: `${this.$VUE_APP_API_URL}/common/image/image/upload/faceImg`,
filePath: filePath,
name: 'file',
header: {
'Authorization': uni.getStorageSync('X-Token'), // 修改为你的访问令牌
},
success: (res) => {
uni.hideLoading(); // 隐藏 loading
if (res.statusCode === 200) {
console.log('上传成功:', res.data);
const responseData = JSON.parse(res.data); // 解析返回的数据
console.log(responseData,'responseData')
// 处理上传成功后的逻辑
if(responseData.code==200){
this.contractImage1 = responseData.data
uni.setStorageSync('faceUrl',this.contractImage1)
}else{
uni.$u.toast(responseData.msg);
}
} else {
console.error('上传失败', res.statusCode);
uni.showToast({
title: res.msg, // 自定义错误信息
icon: 'none'
});
}
},
fail: (err) => {
console.error('上传失败:', err);
uni.showToast({
title: '上传失败,请重试',
icon: 'none'
});
}
});
},
即能兼容h5也能兼容微信小程序和各个app
微信小程序图片压缩再次用二分查找压缩质量
// 压缩图片
export function compressImage(filePath, quality, successCallback, errorCallback) {
uni.compressImage({
src: filePath,
quality: quality,
success: (res) => {
successCallback(res.tempFilePath);
},
fail: (err) => {
errorCallback(err);
}
});
}
// 二分查找压缩质量
export function binarySearchCompress(filePath, targetSize, low, high, successCallback, errorCallback) {
if (low > high) {
errorCallback("无法达到目标大小");
return;
}
const mid = Math.floor((low + high) / 2);
compressImage(filePath, mid, (tempFilePath) => {
uni.getFileInfo({
filePath: tempFilePath,
success: (res) => {
const currentSize = res.size;
if (currentSize <= targetSize) {
successCallback(tempFilePath);
} else {
// 递归调整压缩质量
binarySearchCompress(filePath, targetSize, low, mid - 1, successCallback, errorCallback);
}
},
fail: (err) => {
errorCallback(err);
}
});
}, (err) => {
errorCallback(err);
});
}
vue文件引用
//#ifdef APP-PLUS || MP-WEIXIN
// 如果超过200KB,进行压缩
const tempFilePath = chooseImageRes.tempFilePaths[0];
const targetSizeKB = 200;
// 将目标大小转换为字节数
const targetSize = targetSizeKB * 1024;
// 初始压缩质量范围
const lowQuality = 1;
const highQuality = 100;
binarySearchCompress(tempFilePath, targetSize, lowQuality, highQuality, (compressedFilePath) => {
console.log("压缩成功,压缩后图片路径:", compressedFilePath);
this.uploadCompressedImage(compressedFilePath);
}, (err) => {
console.error("压缩失败:", err);
})
//#endif