----- 我正在参加「掘金·启航计划」------
前言
前端同学在开发过程中,总会遇到类似的需求——上传一个图片,并压缩到2M,接下来就讲述一下如何使用canvas和递归算法处理这类需求。
html
<input type="file" id="ipt" accept="image/*" />
判断文件大小
let limitSize = 2 //限定大小 2M
const isLt = file.size / 1024 / 1024 < limitSize;
if(!isLt){
//压缩
}
使用canvas绘制图片
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = w;
canvas.height = h;
ctx.drawImage(img, 0, 0, w, h);
toDataURL压缩图片质量,生成base64图片
const base64 = canvas.toDataURL('image/jpeg', quality || 0.9);
将base64的图片转化成文件
function dataURLtoFile(dataurl, filename) {
const arr = dataurl.split(',');
const mime = arr[0].match(/:(.*?);/);
const bstr = atob(arr[1]);
let n = bstr.length;
const u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new File([u8arr], filename, { type: mime });
}
递归处理,使文件大小达到2M以下
如果得到的图片大小仍然大于2M,则继续压缩,直到图片大小<2M,返回图片文件。
存储图片
最终得到图片的file文件
全部代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>文件压缩</title>
</head>
<body>
<input type="file" id="ipt" accept="image/*" />
</body>
<script>
let limitSize = 2;
let ipt = document.querySelector('#ipt');
ipt.addEventListener('change', (e) => {
inputChange(e);
});
function inputChange(e) {
let file = e.target.files[0];
const isLt = file.size / 1024 / 1024 < limitSize;
if (!isLt) {
const filereader = new FileReader();
filereader.readAsDataURL(file);
filereader.onload = (res) => {
const src = res.target.result;
const image = new Image();
image.src = src;
image.onload = function (img) {
// 获取图片的宽高,并存放到file对象中
file.width = image.width * 0.8;
file.height = image.height * 0.8;
// alert('您的图片太大,压缩中...');
const newFile = compressImg(this, file.name, image.width * 0.8, image.height * 0.8, 0.9);
// 存储文件
// saveFilesFn(newFile);
};
};
}
}
// 压缩图片
function compressImg(img, name, w, h, quality) {
// 生成canvas
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = w;
canvas.height = h;
ctx.drawImage(img, 0, 0, w, h);
const base64 = canvas.toDataURL('image/jpeg', quality || 0.9);
const file = dataURLtoFile(base64, name);
const isLt = file.size / 1024 / 1024 < limitSize;
if (!isLt) {
// 超过2M 重新压缩
return compressImg(img, name, w, h, 0.9);
}
// 低于2M 返回数据
return dataURLtoFile(base64, name);
}
// 将base64的图片转换成文件
function dataURLtoFile(dataurl, filename) {
const arr = dataurl.split(',');
const mime = arr[0].match(/:(.*?);/);
const bstr = atob(arr[1]);
let n = bstr.length;
const u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new File([u8arr], filename, { type: mime });
}
</script>
</html>
总结
这个方法在移动端H5中作用很大,用户拍照时,图片质量往往大于2M, 使用此方法主动压缩图片质量,满足需求,减轻服务器压力。