uniapp上传图片之前压缩处理
原理是使用canvas
压缩函数
compressImage(filePath) {
return new Promise((resolve, reject) => {
// 先获取图片信息,了解图片大小和尺寸
uni.getImageInfo({
src: filePath,
success: (imageInfo) => {
// 创建临时文件路径
const tempFilePath = filePath;
// 如果图片本身就小于1MB,并且尺寸不大,就不压缩了
uni.getFileInfo({
filePath: tempFilePath,
success: (res) => {
console.log("原始图片大小:", res.size / 1024, "KB");
// 如果文件已经足够小,直接返回原文件路径
if (res.size < this.maxSize && imageInfo.width <= this.maxWidth) {
resolve({
path: tempFilePath,
size: res.size
});
return;
}
// 计算缩放比例
let ratio = 1;
if (imageInfo.width > this.maxWidth) {
ratio = this.maxWidth / imageInfo.width;
}
const newWidth = Math.floor(imageInfo.width * ratio);
const newHeight = Math.floor(imageInfo.height * ratio);
// 创建canvas绘制
const canvas = document.createElement('canvas');
canvas.width = newWidth;
canvas.height = newHeight;
const ctx = canvas.getContext('2d');
// 创建图片对象
const img = new Image();
img.onload = () => {
// 绘制图片到canvas
ctx.clearRect(0, 0, newWidth, newHeight);
ctx.drawImage(img, 0, 0, newWidth, newHeight);
// 初始质量
let quality = this.quality;
let base64 = canvas.toDataURL('image/jpeg', quality);
// 检查压缩后的大小
let binaryData = atob(base64.split(',')[1]);
let compressedSize = binaryData.length;
console.log("首次压缩后大小:", compressedSize / 1024, "KB");
// 如果压缩后仍然太大,则降低质量继续压缩
let maxIterations = 5; // 最多尝试5次
let currentIteration = 0;
while (compressedSize > this.maxSize && currentIteration < maxIterations) {
quality -= 0.1;
if (quality < 0.2) quality = 0.2; // 最低质量限制
base64 = canvas.toDataURL('image/jpeg', quality);
binaryData = atob(base64.split(',')[1]);
compressedSize = binaryData.length;
console.log(`第${currentIteration+1}次压缩, 质量:${quality}, 大小:${compressedSize / 1024}KB`);
currentIteration++;
}
// 转换base64为Blob
let binary = atob(base64.split(',')[1]);
let array = [];
for (let i = 0; i < binary.length; i++) {
array.push(binary.charCodeAt(i));
}
let blob = new Blob([new Uint8Array(array)], {type: 'image/jpeg'});
// 创建文件对象
let fileName = `compressed_${new Date().getTime()}.jpg`;
let file = new File([blob], fileName, {type: 'image/jpeg'});
resolve({
file: file,
size: compressedSize
});
};
img.onerror = (e) => {
reject(e);
};
// 设置图片来源
img.src = tempFilePath;
},
fail: (err) => {
reject(err);
}
});
},
fail: (err) => {
reject(err);
}
});
});
}
调用相机函数
takePhoto() {
// 直接调用相机拍照,不提供选择相册的选项
uni.chooseImage({
count: 1, // 限制只能选一张图片
sourceType: ['camera'], // 只使用相机拍照
sizeType: ['compressed', 'original'],
success: (res) => {
uni.showLoading({
title: '图片上传中,请稍后...',
mask: true
});
let fileItem = res.tempFiles[0];
// 检查文件大小,如果超过1MB则压缩
if (fileItem.size > this.maxSize) {
console.log("图片需要压缩,原始大小:", fileItem.size / 1024, "KB");
// 压缩图片
this.compressImage(fileItem.path)
.then(compressResult => {
console.log("压缩后大小:", compressResult.size / 1024, "KB");
let compressedFile = compressResult.file;
// 上传压缩后的图片
this.upload(compressedFile);
})
.catch(err => {
console.error("压缩图片失败:", err);
uni.hideLoading();
uni.showToast({
title: '图片处理失败,请重试',
icon: 'none',
duration: 2000
});
});
} else {
console.log("图片不需要压缩,大小:", fileItem.size / 1024, "KB");
// 文件大小已经符合要求,直接上传
let file = new File([fileItem], fileItem.name, {
type: fileItem.type
});
//实际上传的函数(需要自己定义)
this.upload(file);
}
},
fail: (err) => {
console.log('相机调用失败', err);
uni.showToast({
title: '相机调用失败',
icon: 'none',
duration: 2000
});
}
})
}