整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

小猿圈入门html5教程之利用canvas实现图片压缩方法

在学习前端你的小伙伴都在迷茫遇到问题,找不到老师怎么办?这些也是小猿圈web前端老师担心的,以后每天小猿圈都会为大家分享一些关于学习前端中的一些小问题,今天分享的是利用canvas实现图片压缩方法。

项目中做身份证识别时,需要传送图片的base64格式编码,但是手机拍摄的照片都太大了,转成base64简直可怕,因此找了一下解决办法。

涉及到的知识点

onchange事件是在上传完文件之后触发

使用files属性获取到上传的文件对象

readAsDataURL用于转换成base64编码

区分canvas的画布和绘画环境:

画布:对应代码中的cvs,可以设置画布width,height;

绘画环境:对应代码中的ctx,可以设置fillStyle,fillRect等;

使用canvas自带的drawImage()方法将图片画到canvas上

想取到压缩后图片的base64可以使用canvas自带的toDataURL()方法

完整代码

<!DOCTYPEhtml>

<htmllang="en">

<head>

<metacharset="UTF-8">

<metaname="viewport"content="width=device-width,initial-scale=1.0">

<metahttp-equiv="X-UA-Compatible"content="ie=edge">

<title>Document</title>

</head>

<body>

<inputtype="file"onchange="loadImg(this)">

<hr>

<div>800×449,544KB</div>

<imgsrc=""alt="">

<hr>

<div>400×224,157KB</div>

<canvas></canvas>

<script>

//上传图片

functionloadImg(me){

letimg=document.querySelector('img');

letcvs=document.querySelector('canvas');

letfile=me.files[0];//获取到文件对象

//上传的图片大于500KB时才压缩

if(file&&(file.size/1024>500)){

letreader=newFileReader();

reader.readAsDataURL(file);//转成base64编码

reader.onload=function(e){

letnaturalBase64=e.target.result;//获取base64编码,这是原图的

img.src=naturalBase64;

img.onload=function(){

letratio=img.naturalWidth/img.naturalHeight;//获取原图比例,为了等比压缩

cvs.width=400;

cvs.height=cvs.width/ratio;

letctx=cvs.getContext('2d');

ctx.drawImage(img,0,0,cvs.width,cvs.height);//画在canvas上

//压缩后新图的base64

letzipBase64=cvs.toDataURL();

}

}

}

}

</script>

</body>

</html>

关于压缩后的图片大小

这里提供一个开箱即用的方法,baseStr是一个完整的Base64编码

代码:

functioncalcBase(baseStr){

vartag='base64,';

baseStr=baseStr.substring(baseStr.indexOf(tag)+tag.length);

vareqTagIndex=baseStr.indexOf('=');

baseStr=eqTagIndex!=-1?baseStr.substring(0,eqTagIndex):baseStr;

varstrLen=baseStr.length;

varfileSize=strLen-(strLen/8)*2;

console.log("文件大小:"+(fileSize/1024).toFixed(1)+'KB');

}

今天的知识点就分享到这里了,有需要的朋友欢迎点赞评论转发,想了解更多web前端开发内容的朋友可以关注小猿圈的每天的动态,会不定时更新很多更好的内容奉献给大家,希望对你的学习有所帮助。

朱哥,昨天试了几把图片上传的功能,感觉还不错,不过有个小问题!"

老朱:“什么问题?”

小白:“小图片上传还好说,大图片上传的时候经常会卡顿一下。”

老朱:“恩,很多人上传图片的时候都是直接上传原图的,很多相机照的原图大小都在4M左右,上传的图片如果都是这么大,不但用户觉得你的网站速度慢,还非常占服务器空间。”

小白:“哦,确实是,很多人压根不知道自己上传的图片到底有多大。”

老朱:“所以我们要让用户进行傻瓜式操作,图片压缩的功能就必不可少。今天我们就用canvas来做一下图片压缩的处理。我们在昨天的基础上增加canvas功能就可以了。”

老朱:“在缩略图下面增加一个canvas,canvas有一个toDataURL方法,可以把当前的canvas绘制的内容进行图片压缩并转换为base64编码,有了base64编码我们就可以发送给图片上传的php页面进行图片上传了。”

老朱继续说道:“知道了压缩的方法,我们只需要解决如果把选择的文件绘制到canvas上面就可以了。还记得我们之前绘制图片的时候用到的Image对象么?”

“记得,绘制图像的时候需要实例化一个Image对象,然后设定Image对象的图片地址src,当图片加载完成以后把图片绘制到canvas上。”

老朱:“恩,流程还记得,不错。Image对象的src属性也可以接收图片base64编码,因此我们可以这样来做。”

“这里我把canvas的宽度设定在500像素,高度根据图片高度进行等比例变化,你可以看一下绘制的效果。”

你看看这张图片的原始大小信息:

“现在通过imgdata=canvas.toDataURL('image/jpeg',0.3);把canvas信息压缩并转为base64编码存到imgdata里面,然后通过jQuery的ajax把imgdata发送给图片上传的php页面就可以了。”

“通过canvas上传以后图片的大小下降到9.65K,应该说是没非常理想了。通过canvas压缩后上传最大的好处是图片在客户端进行处理,处理好以后再往服务器发送,这样传输的数据大小就非常小了。”

老朱最后说:“刚刚我们通过canvas实现了图片压缩上传,真正开发的时候情况会比这个稍微复杂点,我跟你大概说一下,你记住就行了。1、动态生成canvas,这样做的好处是canvas不会显示在页面上。2、判断图片大小,如果图片大小比较小不用压缩直接上传就可以,图片大再进行压缩。3、有时你可能需要隐藏input file,比如上传头像的功能,用户点击头像进行选择图片上传,这时就需要通过点击头像的事件调用input file的点击事件来选择图片。这几个技巧你有时间了可以自己实现一下,不是特别麻烦,我们之前学过的知识足够你解决它们了。”


想学H5的朋友可以关注老炉,您的关注是我持续更新《小白HTML5成长之路》的动力!

下截图:

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

于是图片歘歘歘地传上去了:

此时我们点击最终上传完毕的图片地址,会发现原来2M多3000多像素宽的图片被限制为400像素宽了:

保存到本地会发现图片尺寸已经变成只有70K了:

以上就是图片前端压缩并上传demo的完整演示。

二、实现原理

要想使用JS实现图片的压缩效果,原理其实很简单,核心API就是使用canvas的drawImage()方法。

Canvas本质上就是一张位图,而drawImage()方法可以把一张大大的图片绘制在小小的Canvas画布上,不久等同于图片尺寸压缩了?

对于本案例的压缩,使用的5个参数的API方法:

context.drawImage(img, dx, dy, dWidth, dHeight);复制代码

各参数具体含义可以参见“Canvas API中文文档-drawImage”,这里不展开。

举例:

一张图片(假设图片对象是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);复制代码

把大图片画在一张小画布上,压缩就这么实现了,是不是简单的有点超乎想象。

三、如果想要上传或下载?

如果想要上传图片或者下载图片,可以使用canvas.toDataURL()或者canvas.toBlob()方法先进行转换。

1. 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,是一个比较合理的图片质量输出参数,通常情况下,我们无需再设定。

更多关于toDataURL()方法的信息可以参见“Canvas API中文文档-toDataURL()”。

2. canvas.toBlob()方法

语法如下:canvas.toBlob(callback, mimeType, qualityArgument)复制代码

可以把画布转换成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); 
});复制代码

更多关于toBlob()方法的信息可以参见“Canvas API中文文档-toBlob()”。

一旦有了可传输的图像数据,上传下载就好实现了。例如下载前端压缩好的图片,可以参考我上一篇在掘金发布的文章:“纯JS生成并下载各种文本文件或图片”。

四、总结

经过“图片→canvas压缩→图片”三步曲,我们完成了图片前端压缩功能。

作者:张鑫旭

链接:https://juejin.im/post/5bec3c6cf265da614312a0fa

来源:掘金

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。