订阅千锋最新开发课程视频教程、源码、ppt
HTML5 file API加canvas实现图片前端JS压缩
要想使用JS实现图片的压缩效果,原理其实很简单,核心API就是使用canvas的drawImage()方法。
canvas的drawImage()方法API如下:
context.drawImage(img,sx,sy,swidth,sheight,x,y,width,height);
虽然看上去有9大参数,但不用慌,实际上可以看出就3个参数:
img
就是图片对象,可以是页面上获取的DOM对象,也可以是虚拟DOM中的图片对象。
sx,sy,swidth,sheight
在canvas画布上画一片区域用来放置图片,sx,sy为左上角坐标,swidth,sheight指区域大小。如果没有指定后面4个参数,则图片会被拉伸或缩放在这片区域内。
x,y,width,height
就是图片在canvas画布上显示的大小和位置。如果这里的width,height的值就是图片的原始尺寸,则最终的表现效果是图片剪裁于swidth,sheight区域内。
对于本文的图片压缩,最后四个参数是用不到的,取消前面五个参数就可以了。举个例子,一张图片(假设图片对象是img)的原始尺寸是4000*3000,现在需要把尺寸限制为400*300大小,很简单,原理如下代码示意:
var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
canvas.width = 400;
canvas.height = 300;
// 核心JS就这个
context.drawImage(img,0,0,400,300);
把一张大的图片,直接画在一张小小的画布上。此时大图片就天然变成了小图片,压缩就这么实现了,是不是简单的有点超乎想象。
当然,若要落地于实际开发,我们还需要做些其他的工作,就是要解决图片来源和图片去向的问题。
1. 如何把系统中图片呈现在浏览器中?
HTML5 file API可以让图片在上传之前直接在浏览器中显示,通常使用FileReader方法,代码示意如下:
var reader = new FileReader(), img = new Image();
// 读文件成功的回调
reader.onload = function(e) {
// e.target.result就是图片的base64地址信息
img.src = e.target.result;
};
eleFile.addEventListener('change', function (event) {
reader.readAsDataURL(event.target.files[0]);
});
于是,包含图片信息的context.drawImage()方法中的img图片就有了。
2. 如果把canvas画布转换成img图像
canvas天然提供了2个转图片的方法,一个是:
canvas.toDataURL()方法
语法如下:
canvas.toDataURL(mimeType, qualityArgument)
可以把图片转换成base64格式信息,纯字符的图片表示法。
其中:
mimeType表示canvas导出来的base64图片的类型,默认是png格式,也即是默认值是'image/png',我们也可以指定为jpg格式'image/jpeg'或者webp等格式。file对象中的file.type就是文件的mimeType类型,在转换时候正好可以直接拿来用(如果有file对象)。
qualityArgument表示导出的图片质量,只要导出为jpg和webp格式的时候此参数才有效果,默认值是0.92,是一个比较合理的图片质量输出参数,通常情况下,我们无需再设定。
canvas.toBlob()方法
语法如下:
canvas.toBlob(callback, mimeType, qualityArgument)
可以把canvas转换成Blob文件,通常用在文件上传中,因为是二进制的,对后端更加友好。
和toDataURL()方法相比,toBlob()方法是异步的,因此多了个callback参数,这个callback回调方法默认的第一个参数就是转换好的blob文件信息,本文demo的文件上传就是将canvas图片转换成二进制的blob文件,然后再ajax上传的,代码如下:
// canvas转为blob并上传
canvas.toBlob(function (blob) {
// 图片ajax上传
var xhr = new XMLHttpRequest();
// 开始上传
xhr.open("POST", 'upload.php', true);
xhr.send(blob);
});
于是,经过“图片→canvas压缩→图片”三步曲,我们完成了图片前端压缩并上传的功能。
更加完整的核心代码请参见demo页面的左侧,如果对其他交互代码也敢兴趣,请参考页面源代码。
四、结束语
就在几个月前刚写过一篇文章“使用canvas在前端实现图片水印合成”,实际上所使用的技术和套路和本文是如出一辙的,也是“图片→canvas水印→图片”三步曲,区别在于水印合成是连续执行两次context.drawImage()方法,一次是原图一次水印图片,以及最后转换成图片的时候什么是toDataURL()方法,其他代码逻辑和原理都是一样的。
由此及彼,利用同样的原理和代码逻辑,我们还可以实现其它很多以前前端不太好实现的功能,比方说图片的真剪裁效果,所谓“真剪裁”指不是使用个overflow:hidden或者clip这些CSS属性的“伪剪裁”,而是真正意义上就这么大区域图片信息。甚至配合一些前端算法,我们可以直接在前端进行人脸识别,图片自动美化等一系列功能再上传等等。
原理都是一样的,都是利用canvas作为中间媒介进行处理。
好,以上就是本文的全部内容,感谢阅读,欢迎纠错,欢迎交流!