开篇语
在我的博客,“生活”这模块里,经常需要上传图片。这些图片一般都是我用手机拍摄的,图片质量一般在2-5M左右。所以,我会在图片上传后,使用tinypng
接口进行图片压缩。这样,显示的图片会在几百KB左右,点击大图预览才会加载原图。
惊人,后端竟对前端提出这样的要求
就在前两个月,在团队项目里。甲方提出了一个需求,要求对上传的图片进行压缩。在我的思维逻辑里,压缩工作是在图片上传后,后端去进行处理的。
经过小组的讨论分析,后端想要把图片质量压缩的工作放在前端去进行处理,这样可以减少请求时间,客户体验感会更好。当时的有点懵逼,前端还能去处理图片的压缩?
常用的压缩方法
- 图片上传到阿里云或者七牛云,云端会压缩图片;
- 后端对图片尺寸大小进行压缩,比如
tinypng
等接口,都可以完成,但压缩时间很久; - 前端用
Canvas
作为媒介压缩图片;
显然团队的项目更适用于第三种方法。而且网上一大堆相关的资料。
Canvas压缩图片的重要知识点
详细代码解释如下:
function compress (file,callback) {
var reader = new FileReader();
// 将file 对象转成 Data URL
reader.readAsDataURL(file);
reader.onload = function(e) {
// 新建一个img 标签(还没嵌入DOM节点)
var image = new Image();
image.src = e.target.result;
image.onload = function() {
// canvas.getContext 进行宽高的改变,从而达到压缩质量的目的
var canvas = document.createElement('canvas'),
context = canvas.getContext('2d');
imageWidth = 300, // 压缩质量宽度
imageHeight = 300, // 压缩质量高度
compactData = '';
canvas.width = imageWidth;
canvas.height = imageHeight;
context.drawImage(image, 0, 0, imageWidth, imageHeight);
// 将canvas 元素所展示的图片再次转换成 Data URL
// 到这已经压缩完成了
compactData = canvas.toDataURL(file.type);
// 最后把Data URL 转成 blob
var byteString, mimeString, u8arr, blob;
if ( compactData.split(",")[0].indexOf("compactData") >= 0 ) {
byteString = atob(compactData.split(",")[1]);
} else{
byteString = unescape(compactData.split(",")[1]);
}
mimeString = compactData .split(",")[0] .split(":")[1] .split(";")[0];
u8arr = new Uint8Array(byteString.length);
for ( var i = 0; i < byteString.length; i++ ) {
u8arr[i] = byteString.charCodeAt(i);
}
blob = new Blob([u8arr], { type: mimeString });
// 返回原file 对象、压缩后的file 对象、压缩后的 Data URL
callback && callback(file, blob, compactData);
};
};
};
在上述样例中,主要是经历了图片 -->
canvas
缩放压缩 --> 图片的过程。在图片压缩完成后,看个人所需,可以做不同的处理。例如将压缩后的图片显示在页面,作为略缩图,或者直接上传压缩图片。
但要注意的是,上传图片必须是
blob
对象,所以在压缩后,必须转换成blob
对象才能进行上传。转换blob
对象的方法好几种,原生的canvas
也提供转换blob
的方法。有兴趣可以去了解。
demo下载
- 前端压缩图片样例资源下载
- 样例地址:www.qiuzhipeng.com/resource/demo/compress.html)