HTML5 file API加canvas实现图片前端JS压缩并上传
一、图片上传前端压缩的现实意义
对于大尺寸图片的上传,在前端进行压缩除了省流量外,最大的意义是极大的提高了用户体验。
这种体验包括两方面:
- 由于上传图片尺寸比较小,因此上传速度会比较快,交互会更加流畅,同时大大降低了网络异常导致上传失败风险。
- 最最重要的体验改进点:省略了图片的再加工成本。很多网站的图片上传功能都会对图片的大小进行限制,尤其是头像上传,限制5M或者2M以内是非常常见的。然后现在的数码设备拍摄功能都非常出众,一张原始图片超过2M几乎是标配,此时如果用户想把手机或相机中的某个得意图片上传作为自己的头像,就会遇到因为图片大小限制而不能上传的窘境,不得不对图片进行再处理,而这种体验其实非常不好的。如果可以在前端进行压缩,则理论上对图片尺寸的限制是没有必要的。
二、图片前端JS压缩并上传功能体验
特意制作了一个图片前端压缩并上传的完整demo,您可以狠狠的点击这里:使用canvas在前端压缩图片并上传demo
进入demo会看到一个相貌平平的文件输入框:

啊,不对,应该是这张图:

点击文件选择框,我们不妨选一张尺寸比较大的图片,例如下面这种2M多的钓鱼收获照:

于是图片歘歘歘地传上去了:
此时我们点击最终上传完毕的图片地址,会发现原来2M多3000多像素宽的图片被限制为400像素宽了:
保存到本地会发现图片尺寸已经变成只有70K了:
以上就是图片前端压缩并上传demo的完整演示。
三、HTML5 file API加canvas实现图片前端JS压缩
要想使用JS实现图片的压缩效果,原理其实很简单,核心API就是使用canvas的drawImage()方法。
canvas的drawImage()方法API如下:
context.drawImage(img, dx, dy);
context.drawImage(img, dx, dy, dWidth, dHeight);
context.drawImage(img, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);
后面最复杂的语法虽然看上去有9大参数,但不用慌,实际上可以看出就3个参数:
- img
- 就是图片对象,可以是页面上获取的DOM对象,也可以是虚拟DOM中的图片对象。
- dx, dy, dWidth, dHeight
- 表示在
canvas画布上规划处一片区域用来放置图片,dx, dy为canvas元素的左上角坐标,dWidth, dHeight指canvas元素上用在显示图片的区域大小。如果没有指定sx,sy,sWidth,sHeight这4个参数,则图片会被拉伸或缩放在这片区域内。 - sx,sy,swidth,sheight
- 这4个坐标是针对图片元素的,表示图片在
canvas画布上显示的大小和位置。sx,sy表示图片上sx,sy这个坐标作为左上角,然后往右下角的swidth,sheight尺寸范围图片作为最终在canvas上显示的图片内容。
drawImage()方法有一个非常怪异的地方,大家一定要注意,那就是5参数和9参数里面参数位置是不一样的,这个和一般的API有所不同。一般API可选参数是放在后面。但是,这里的drawImage()9个参数时候,可选参数sx,sy,swidth,sheight是在前面的。如果不注意这一点,有些表现会让你无法理解。
下图为MDN上原理示意:
对于本文的图片压缩,需要用的是是5个参数语法。举个例子,一张图片(假设图片对象是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作为中间媒介进行处理。
好,以上就是本文的全部内容,感谢阅读,欢迎纠错,欢迎交流!
HTML5 file API加canvas实现图片前端JS压缩并上传的更多相关文章
- 利用vue-cropper做的关于图片裁剪、压缩、上传、预览等做的一个公共组件
公共组件: <template> <div> <div class="upload-box"> <div class="imag ...
- 图片纯前端JS压缩的实现
一.图片上传前端压缩的现实意义 对于大尺寸图片的上传,在前端进行压缩除了省流量外,最大的意义是极大的提高了用户体验. 这种体验包括两方面: 由于上传图片尺寸比较小,因此上传速度会比较快,交互会更加流畅 ...
- Resumable.js – 基于 HTML5 File API 的文件上传
Resumable.js 是一个 JavaScript 库,通过 HTML5 文件 API 提供,稳定和可恢复的批量上传功能.在上传大文件的时候通过每个文件分割成小块,每块在上传失败的时候,上传会不断 ...
- HTML5 File API — 让前端操作文件变的可能
前言 在 HTML5 File API 出现之前,前端对于文件的操作是非常有局限性的,大多需要配合后端实现.出于安全角度考虑,从本地上传文件时,代码不可能获取文件在用户本地的地址,所以纯前端不可能完成 ...
- 图片上传插件ImgUploadJS:用HTML5 File API 实现截图粘贴上传、拖拽上传
一 . 背景及效果 当前互联网上传文件最多的就是图片文件了,但是传统web图片的截图上传需要:截图保存->选择路径->保存后再点击上传->选择路径->上传->插入. 图片 ...
- HTML5 File API 全介绍
在 HTML5 File API 出现之前,前端对于文件的操作是非常有局限性的,大多需要配合后端实现.出于安全角度考虑,从本地上传文件时,代码不可能获取文件在用户本地的地址,所以纯前端不可能完成一些类 ...
- php canvas 前端JS压缩,获取图片二进制流数据并上传
<?php if(isset($_GET['upload']) && $_GET['upload'] == 'img'){ //二进制数据流 $data = file_get_c ...
- HTML5 File api 实现断点续传
目前市场上大多数的网站的断点上传都是需要安装浏览器插件的,本文就针对高级浏览器的环境下,通过HTML5 File api实现断点上传进行说明 一.实现文件多选 HTML5的<input>新 ...
- HTML5 file api读取文件的MD5码工具
1.工具的用途:用HTML5 file api读取文件的MD5码.MD5码在文件的唯一性识别上有很重要的应用,业内常用MD5进行文件识别.文件秒传.文件安全性检查等: 2.适用性:IE.Chrome皆 ...
随机推荐
- [Algo] 131. Deep Copy Linked List With Random Pointer
Each of the nodes in the linked list has another pointer pointing to a random node in the list or nu ...
- 吴裕雄--天生自然TensorFlow2教程:numpy [ ] 索引
import tensorflow as tf a = tf.ones([1, 5, 5, 3]) a.shape a[0][0] numpy : 索引 a = tf.random.normal([4 ...
- CodeForces - 1243D. 0-1 MST(补图连通分量个数)
Ujan has a lot of useless stuff in his drawers, a considerable part of which are his math notebooks: ...
- DB---WAL技术
摘要:这个WAL技术也需要加以整理,即 write-ahead logging (预写式日志),待整理...
- [CTSC2008]祭祀(二分图匹配)
没有SPJ时显然是不需要输出方案的.不需要输出方案很好做,先把边扩展(因为会往下流),然后求最大独立集,最大独立集=n-最小点覆盖,因为其是最大独立集的补集.如何求最小点覆盖呢?毕竟我写过最大权闭合子 ...
- 模仿u-boot的makefile结构
u-boot(2014.04)是通过顶层makefile调用各子目录中的makefile来实现整个工程的编译的,实际上子目录的makefile是include进来的.这里仿照这种结构写个模板测试一下. ...
- linux中 su 与 su - 的区别
linux中 su 与 su - 的区别 su只是切换了用户身份,shell环境仍然是切换前用户的shell环境 su -是用户和shell环境一起切换成. 备注:1.切换了shell环境会相应的用户 ...
- FHQ treap板子
感觉这个玩意就是拆来拆去,所以没啥可学习的 粘一下两个题的代码吧 LGOJ 普通平衡树 #include <bits/stdc++.h> using namespace std; #def ...
- Android之UI View与ViewGroup
1.基本概念 View:所有可视化控件的父类,Android App屏幕上用户可以交互的对象(例如 按钮 下拉框 文本框等). ViewGroup:View的子类,存放View和ViewGroup对象 ...
- 共享出行疯狂并购背后,打造全交通链条才能让Uber们更快乐
一直以来,携程.滴滴.摩拜等与出行相关的企业总是会因各种负面问题而饱受诟病.但不能否认的是它们极大地提升了出行便利性,让人们的出行更有效率,也更加方便.而与此同时,Uber.Lyft.滴滴等共享打车企 ...