笔者记录一下自己在项目中遇到的难题
不同的手机,拍照的图片大小不同,有的一张照片就是好几兆。对于一些后台来说,并不需要如此高质量的图片,这个时候,我们如果进行一个上传压缩,节省了带宽,加快了上传和反馈舒服,这就是一件双赢的事情。 上传图片,早些年使用flash,或者JavaScript实现,但是flash渐渐退出舞台,JavaScript运行的速度较慢且压缩效果不是特别明显,一般100kb,也只能压缩小10多kb。性价比较低。 h5中推出了Canvas天生就对图像有灵活处理的能力,故最终敲定使用js配合Canvas进行压缩图片,再上传服务器的方案。
- 先通过input拿到本地图片地址。
- 使用FileRead对象中的readAsDataURL读取图片的数据格式为base64,然后新建一个Img元素,让img的src属性指向图片的base64。
- 使用canvas对象中的drawImage(),对图片进行绘制
- 最后使用canvas对象中的toDataURL(),指定压缩图片为什么格式,指定图片的压缩质量。
- 直接上传服务器或转换为Blob格式再上传。
直接上代码:
<input id="file" type="file">
<script type="text/javascript">
let fileDom = document.querySelector('#file');
// 压缩图片需要的一些元素和对象
let reader = new FileReader();
//创建一个img对象
let img = new Image();
// 选择的文件对象
let file = null;
// 缩放图片需要的canvas
let canvas = document.createElement('canvas');
//指定绘制图像为2d
let context = canvas.getContext('2d');
// base64地址图片加载完毕后
img.onload = function () {
// 图片原始尺寸
let originWidth = this.width;
let originHeight = this.height;
// 最大尺寸限制,可通过国设置宽高来实现图片压缩程度
let maxWidth = 800;
let maxHeight = 800;
// 目标尺寸
let targetWidth = originWidth;
let targetHeight = originHeight;
// 图片尺寸超过400x400的限制
if (originWidth > maxWidth || originHeight > maxHeight) {
if (originWidth / originHeight > maxWidth / maxHeight) {
// 更宽,按照宽度限定尺寸
targetWidth = maxWidth;
targetHeight = Math.round(maxWidth * (originHeight / originWidth));
} else {
targetHeight = maxHeight;
targetWidth = Math.round(maxHeight * (originWidth / originHeight));
}
}
// canvas对图片进行缩放
canvas.width = targetWidth;
canvas.height = targetHeight;
// 清除画布
context.clearRect(0, 0, targetWidth, targetHeight);
// 图片压缩
context.drawImage(img, 0, 0, targetWidth, targetHeight);
/*第一个参数是创建的img对象;第二个参数是左上角坐标,后面两个是画布区域宽高*
//压缩后的图片base64 url
/*canvas.toDataURL(mimeType, quality),mimeType 默认值是'image/png';
qualityArgument表示导出的图片质量,只要导出为jpg和webp格式的时候此参数才有效果,默认值是0.92
我测试了一下,发现当quality的值为0.2到0.5时,可以保证图片的失真率比较小,且有明显的压缩图片的效果*/
let newUrl = canvas.toDataURL('image/jpeg', 0.2);//base64 格式
};
// 文件base64化,以便获知图片原始尺寸
reader.onload = function (e) {
img.src = e.target.result;
};
fileDom.addEventListener('change', function (event) {
file = event.target.files[0];
// 选择的文件是图片
if (file.type.indexOf("image") == 0) {
reader.readAsDataURL(file);
}
});
</script>
</body>
一句话总结:canvas结合js重新描述 一个 2d 图片,然后给canvas画布进行等比例缩小或剪裁,并传入压缩质量参数来进行指定压缩。
base64转Blob格式
// 获取blob对象
let data = canvas.toDataURL('image/jpeg', 0.2)
data = data.split(',')[1]
data = window.atob(data)
let ia = new Uint8Array(data.length)
for (let i = 0; i < data.length; i++) {
ia[i] = data.charCodeAt(i)
}
return new Blob([ia], {
type: 'image/png'
})
}
const blob = getBlob(canvas)
// 生成和上传文件流
const blobToFile = new window.File([blob], this.currentImage.fileName, {
type: 'image/*'
})