前端JS利用canvas的drawImage()对图片进行压缩
2018-01-10 18:39
836 查看
对于大尺寸图片的上传,在前端进行压缩除了省流量外,最大的意义是极大的提高了用户体验。
这种体验包括两方面:
1、由于上传图片尺寸比较小,因此上传速度会比较快,交互会更加流畅,同时大大降低了网络异常导致上传失败风险。
2、最重要的体验改进点:省略了图片的再加工成本。很多网站的图片上传功能都会对图片的大小进行限制,尤其是头像上传,限制5M或者2M以内是非常常见的。然后现在的数码设备拍摄功能都非常出众,一张原始图片超过2M几乎是标配,此时如果用户想把手机或相机中的某个得意图片上传作为自己的头像,就会遇到因为图片大小限制而不能上传的窘境,不得不对图片进行再处理,而这种体验其实非常不好的。如果可以在前端进行压缩,则理论上对图片尺寸的限制是没有必要的。
后面最复杂的语法虽然看上去有9大参数,但不用慌,实际上可以看出就3个参数:
img 就是图片对象,可以是页面上获取的DOM对象,也可以是虚拟DOM中的图片对象。 dx, dy, dWidth, dHeight 表示在
下图为MDN上原理示意:
对于本文的图片压缩,需要用的是是5个参数语法。举个例子,一张图片(假设图片对象是
把一张大的图片,直接画在一张小小的画布上。此时大图片就天然变成了小图片,压缩就这么实现了,是不是简单的有点超乎想象。
当然,若要落地于实际开发,我们还需要做些其他的工作,就是要解决图片来源和图片去向的问题。
于是,包含图片信息的
2、如何把canvas画布转换成img图像
canvas.toDataURL()方法
可以把图片转换成base64格式信息,纯字符的图片表示法。
其中:
canvas.toBlob()方法
可以把canvas转换成Blob文件,通常用在文件上传中,因为是二进制的,对后端更加友好。
和
将
于是,经过“图片→canvas压缩→图片”三步曲,我们完成了图片前端压缩并上传的功能。
上传前还可以预览:
这种体验包括两方面:
1、由于上传图片尺寸比较小,因此上传速度会比较快,交互会更加流畅,同时大大降低了网络异常导致上传失败风险。
2、最重要的体验改进点:省略了图片的再加工成本。很多网站的图片上传功能都会对图片的大小进行限制,尤其是头像上传,限制5M或者2M以内是非常常见的。然后现在的数码设备拍摄功能都非常出众,一张原始图片超过2M几乎是标配,此时如果用户想把手机或相机中的某个得意图片上传作为自己的头像,就会遇到因为图片大小限制而不能上传的窘境,不得不对图片进行再处理,而这种体验其实非常不好的。如果可以在前端进行压缩,则理论上对图片尺寸的限制是没有必要的。
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文件信息。
将
canvas图片转换成二进制的
blob文件,然后再
ajax上传的,代码如下:
// canvas转为blob并上传 canvas.toBlob(function (blob) { // 图片ajax上传 var xhr = new XMLHttpRequest(); // 开始上传 xhr.open("POST", 'upload.php', true); xhr.send(blob); });
于是,经过“图片→canvas压缩→图片”三步曲,我们完成了图片前端压缩并上传的功能。
//HTML代码: <input id="file" type="file"> //JS代码: var eleFile = document.querySelector('#file'); // 压缩图片需要的一些元素和对象 var reader = new FileReader(), img = new Image(); // 选择的文件对象 var file = null; // 缩放图片需要的canvas var canvas = document.createElement('canvas'); var context = canvas.getContext('2d'); // base64地址图片加载完毕后 img.onload = function () { // 图片原始尺寸 var originWidth = this.width; var originHeight = this.height; // 最大尺寸限制 var maxWidth = 400, maxHeight = 400; // 目标尺寸 var targetWidth = originWidth, 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); // canvas转为blob并上传 canvas.toBlob(function (blob) { // 图片ajax上传 var xhr = new XMLHttpRequest(); // 文件上传成功 xhr.onreadystatechange = function() { if (xhr.status == 200) { // xhr.responseText就是返回的数据 } }; // 开始上传 xhr.open("POST", 'upload.php', true); xhr.send(blob); }, file.type || 'image/png'); }; // 文件base64化,以便获知图片原始尺寸 reader.onload = function(e) { img.src = e.target.result; }; eleFile.addEventListener('change', function (event) { file = event.target.files[0]; // 选择的文件是图片 if (file.type.indexOf("image") == 0) { reader.readAsDataURL(file); } });
上传前还可以预览:
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <script type="text/javascript" src="jquery-1.11.3.min.js"></script> <script language="javascript"> window.onload=function(){ var eleFile = document.querySelector('#jjfxSoft_iconPath'); // 压缩图片需要的一些元素和对象 var reader = new FileReader(), img = new Image(); // 选择的文件对象 var file = null; // 缩放图片需要的canvas var canvas = document.createElement('canvas'); var context = canvas.getContext('2d'); // base64地址图片加载完毕后 img.onload = function () { debugger // 图片原始尺寸 var originWidth = this.width; var originHeight = this.height; // 最大尺寸限制 var maxWidth = 300, maxHeight = 300; // 目标尺寸 var targetWidth = originWidth, targetHeight = originHeight; // 图片尺寸超过300x300的限制 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); var type = 'image/jpeg'; //将canvas元素中的图像转变为DataURL var dataurl = canvas.toDataURL(type); $("#ceshi1").attr("src",dataurl); //抽取DataURL中的数据部分,从Base64格式转换为二进制格式 var bin = atob(dataurl.split(',')[1]); //创建空的Uint8Array var buffer = new Uint8Array(bin.length); //将图像数据逐字节放入Uint8Array中 for (var i = 0; i < bin.length; i++) { buffer[i] = bin.charCodeAt(i); } //利用Uint8Array创建Blob对象 var blob = new Blob([buffer.buffer], {type: type}); var url = window.URL.createObjectURL(blob); $("#ceshi").attr("src",url); }; // 文件base64化,以便获知图片原始尺寸 reader.onload = function(e) { img.src = e.target.result; }; eleFile.addEventListener('change', function (event) { file = event.target.files[0]; // 选择的文件是图片 if (file.type.indexOf("image") == 0) { reader.readAsDataURL(file); } }); } </script> </head> <body> <img id="ceshi"> <img id="ceshi1"> <input name="file" type="file" id="jjfxSoft_iconPath"> </body> </html>
相关文章推荐
- 利用H5Canvas进行前端图片压缩再上传笔记
- 上传图片前将图片利用canvas进行压缩
- 利用canvas对上传图片进行上传前压缩
- 利用gulp对项目html,js,css,图片进行压缩
- js上传图片之前利用canvas压缩和转base64
- Js利用Canvas实现图片压缩功能
- 利用HTML5,前端js实现图片压缩
- 关于图片上传和利用canvas进行压缩
- Js利用Canvas实现图片压缩
- 利用canvas前端实现图片压缩后上传
- 利用canvas实现前端压缩图片
- 使用HTML5的两个api,前端js完成图片压缩。
- JS和Canvas实现图片的预览压缩和上传功能
- 利用UIImageJPEGRepresentation与UIGraphicsBeginImageContext进行图片压缩的简单比较
- 计算机学院研发第二轮考核-------利用WebSetting来浏览网页进行优化(js脚本加载,图片,可放大缩小等)
- 利用html5 canvas实现纯前端上传图片的裁剪
- 使用HTML5的两个api,前端js完成图片压缩
- html5 FileReader+Canvas 前端压缩图片(IE9及以下浏览器不支持)
- 利用js将图片地址进行转义
- 一步步教你利用Canvas对图片进行处理