【JS 图片压缩】图片压缩至指定大小
在做图片上传的时候,为了节省带宽和减少上传时间,前端需要对图片进行压缩。前端图片压缩一般都是使用canvas绘图,然后导出图片。今天分享一下图片大小压缩至指定数值的方法。
场景描述
- 支持图片压缩指定数值
- 支持图片压缩至原文件的百分比大小
- 支持压缩之后的图片大小与指定数值误差在0-2%之间
- 支持输出特定质量的图片,默认质量参数0.85
示例图一
图片压缩至20kb左右
//压缩文件至20kb
compressImageWithFixedSize(file, 1024*20)
示例图二
图片压缩至20%左右
//压缩至原文件大小的20%
compressImageWithFixedSize(file, 0.2)
代码
- 计算压缩比,根据压缩比进行canvas绘图导出
- 计算误差范围
- 根据最大数值和误差,递归绘图导出
/**
* 压缩图片并限制其文件大小
* @param {File} file - 要压缩的图片文件
* @param {number} maxSize - 大于1时,为图片的最大文件大小(字节)
* @param {number} maxSize - 小于1大于0时,为图片最大文件大小百分比
* @param {number} quality - 图片的压缩质量,默认为0.85
* @returns {Promise<Blob>} - 压缩后的图片Blob对象
*/
function compressImageWithFixedSize(file, maxSize, quality = 0.85) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
if(maxSize<1&&maxSize>0) {
maxSize = maxSize*file.size;
}
if (file.size <= maxSize) {
resolve(file);
return;
}
reader.onload = function (event) {
const img = new Image();
img.src = event.target.result;
img.onload = function () {
const canvas = document.createElement('canvas');
let width = img.width;
let height = img.height;
// 计算初始压缩比例
// let ratio = Math.sqrt((maxSize * 1024) / (width * height));
let ratio = (maxSize / file.size);
console.log('ratio',ratio)
if (ratio < 1) {
width *= ratio;
height *= ratio;
}
canvas.width = width;
canvas.height = height;
const ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0, width, height);
const PERCENTAGE = 0.98;
const minsize = maxSize * PERCENTAGE;
const checkSize = (blob) => {
if (blob?.size <= maxSize && blob?.size >= minsize) {
resolve(blob);
} else {
if(blob?.size<minsize) {
ratio += 0.005;
}
width = Math.ceil(img.width * ratio);
height = Math.ceil(img.height * ratio);
canvas.width = width;
canvas.height = height;
ctx.drawImage(img, 0, 0, width, height);
canvas.toBlob(checkSize, 'image/jpeg', quality);
}
};
canvas.toBlob(checkSize, 'image/jpeg', quality);
};
};
reader.onerror = function (error) {
reject(error);
};
reader.readAsDataURL(file);
});
}
这种将图片压缩至指定大小的方法比较适合一些对图片质量要求不高,缩略图展示,预览图等场景,比如头像上传,商品缩略图,图片预览。