通过canvas压缩图片大小和质量之间的关系
近期项目需要对用户上传的大图片压缩后生成一个缩略图,防止列表展示时加载过于缓慢。预计对大于100KB的图片进行压缩,生成一个50KB一下大小的缩略图。使用的方法就是通过<canvas>
标签进行重新绘制、生成压缩文件。不多说,上代码
<body>
<!-- 隐藏input -->
<input type="file" id="input" title="file" placeholder="file" hidden />
<!-- 上传按钮 -->
<button type="button" id="button">点击上传</button>
<script>
const fileInput = document.querySelector('#input'),
button = document.querySelector('#button');
button.addEventListener('click', () => {
fileInput.click();
});
fileInput.addEventListener('change', () => {
button.disabled = true;
const file = fileInput.files[0], map = {};
// 原文件大小
console.log('origin file \t', file.size + 'B \t');
// 生成<img>对象
const img = new Image();
img.src = URL.createObjectURL(file);
// 加载后用canvas重画
img.addEventListener('load', () => {
const canvas = document.createElement('canvas');
canvas.width = img.width;
canvas.height = img.height;
const ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0);
// 生成100个质量在0.1 - 1之间的不同图像并将quality和size写入map
for (let i = 100; i > 0; i--) {
canvas.toBlob(blob => {
const newFile = new File([blob], 'image.jpeg', { type: 'image/jpeg' });
map[i] = newFile.size;
}, 'image/jpeg', i / 100);
}
});
// 执行完毕后打印文件大小数列
const interval = setInterval(() => {
console.log(Object.keys(map).length);
if (Object.keys(map).length === 100) {
console.log(Object.keys(map));
console.log(Object.values(map));
button.disabled = false;
clearInterval(interval);
}
}, 1000);
});
</script>
</body>
通过3个不同的jpeg图片测试,结果如下图:
可以看到,在quality > 80的情况下,图片文件大小增速明显变快。所以可以重复drawImage() + toBlob(f, t, 0.78)这个过程,直到文件大小小于50KB