博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
前端JS利用canvas的drawImage()对图片进行压缩
阅读量:4500 次
发布时间:2019-06-08

本文共 4682 字,大约阅读时间需要 15 分钟。

  对于大尺寸图片的上传,在前端进行压缩除了省流量外,最大的意义是极大的提高了用户体验。

  这种体验包括两方面:

  1、由于上传图片尺寸比较小,因此上传速度会比较快,交互会更加流畅,同时大大降低了网络异常导致上传失败风险。

  2、最重要的体验改进点:省略了图片的再加工成本。很多网站的图片上传功能都会对图片的大小进行限制,尤其是头像上传,限制5M或者2M以内是非常常见的。然后现在的数码设备拍摄功能都非常出众,一张原始图片超过2M几乎是标配,此时如果用户想把手机或相机中的某个得意图片上传作为自己的头像,就会遇到因为图片大小限制而不能上传的窘境,不得不对图片进行再处理,而这种体验其实非常不好的。如果可以在前端进行压缩,则理论上对图片尺寸的限制是没有必要的。

HTML5 file API加canvas实现图片前端JS压缩

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

  canvasdrawImage()方法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是在前面的。如果不注意这一点,有些表现会让你无法理解。

  下图为上原理示意:

  对于本文的图片压缩,需要用的是是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表示导出的图片质量,只要导出为jpgwebp格式的时候此参数才有效果,默认值是0.92,是一个比较合理的图片质量输出参数,通常情况下,我们无需再设定。

canvas.toBlob()方法
canvas.toBlob(callback, mimeType, qualityArgument)

  可以把canvas转换成,通常用在文件上传中,因为是二进制的,对后端更加友好。

  和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代码://JS代码:var eleFile = document.querySelector('#file');// 压缩图片需要的一些元素和对象var reader = new FileReader(), img = new Image();// 选择的文件对象var file = null;// 缩放图片需要的canvasvar 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);        }});

  上传前还可以预览:

 

转载于:https://www.cnblogs.com/goloving/p/8260206.html

你可能感兴趣的文章
Selenium学习第一章:搭建测试环境
查看>>
SASS笔记
查看>>
2.学习Application
查看>>
php第二十五节课
查看>>
CS224d lecture 6札记
查看>>
[NOIP 2011]聪明的质监员
查看>>
[Sdoi2013]spring
查看>>
TopCoder SRM 633 Div.2 500 Jumping
查看>>
iOS 相关博客清单
查看>>
GLSL新手上路 -- 《交互式计算机图形学》附录中GLSL代码有误 -- 修改如下
查看>>
xss挑战赛小记 0x02(prompt(1))
查看>>
软件工程 第四课(毕业论文管理系统——面向对象)
查看>>
springboot 获取post请求参数
查看>>
Netty4/Android6 SSL双向认证 攻略 2016.10.13
查看>>
webpack的在开发生产时的具体功能
查看>>
平衡二叉树
查看>>
Web 应用
查看>>
KAFKA跨主机部署网络不通解决思路
查看>>
适配器模式--Adapter Pattern
查看>>
linux 安装jdk
查看>>