前端JS利⽤canvas的drawImage()对图⽚进⾏压缩
对于⼤尺⼨图⽚的上传,在前端进⾏压缩除了省流量外,最⼤的意义是极⼤的提⾼了⽤户体验。
这种体验包括两⽅⾯:
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)的
原始尺⼨是40003000,现在需要把尺⼨限制为400300⼤⼩,很简单,原理如下代码⽰意:
var canvas = ateElement('canvas');
var context = Context('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();
// 读⽂件成功的回调
// sult就是图⽚的base64地址信息
img.src = sult;
};jquery是什么有什么作用
eleFile.addEventListener('change',function(event){
});
于是,包含图⽚信息的context.drawImage()⽅法中的img图⽚就有了。
2、如何把canvas画布转换成img图像
canvas天然提供了2个转图⽚的⽅法,⼀个是:
可以把图⽚转换成base64格式信息,纯字符的图⽚表⽰法。
其中:
mimeType表⽰canvas导出来的base64图⽚的类型,默认是png格式,也即是默认值是’image/png’,我们也可以指定为jpg格
式’image/jpeg’或者webp等格式。
file对象中的pe就是⽂件的mimeType类型,在转换时候正好可以直接拿来⽤(如果有file对象)。
qualityArgument表⽰导出的图⽚质量,只要导出为jpg和webp格式的时候此参数才有效果,默认值是0.92,是⼀个⽐较合理的图⽚质量输出参数,通常情况下,我们⽆需再设定。
可以把canvas转换成Blob⽂件,通常⽤在⽂件上传中,因为是⼆进制的,对后端更加友好。
和toDataURL()⽅法相⽐,toBlob()⽅法是异步的,因此多了个callback参数,这个callback回调⽅法默认的第⼀个参数就是转换好的blob ⽂件信息。
将canvas图⽚转换成⼆进制的blob⽂件,然后再ajax上传的,代码如下:
// canvas转为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 = ateElement('canvas');
var context = Context('2d');
// base64地址图⽚加载完毕后
// 图⽚原始尺⼨
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 = und(maxWidth * (originHeight / originWidth));
} else {
targetHeight = maxHeight;
targetWidth = und(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并上传
// 图⽚ajax上传
var xhr = new XMLHttpRequest();
// ⽂件上传成功
if (xhr.status == 200) {
// sponseText就是返回的数据
}
};
// 开始上传
xhr.open("POST", 'upload.php', true);
xhr.send(blob);
}, pe || 'image/png');
};
// ⽂件base64化,以便获知图⽚原始尺⼨
img.src = sult;
};
eleFile.addEventListener('change', function (event) {
file = event.target.files[0];
// 选择的⽂件是图⽚
// 选择的⽂件是图⽚
if (pe.indexOf("image") == 0) {
}
});
上传前还可以预览:
<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">
var eleFile = document.querySelector('#jjfxSoft_iconPath');
// 压缩图⽚需要的⼀些元素和对象
var reader =new FileReader(),
img =new Image();
// 选择的⽂件对象
var file =null;
// 缩放图⽚需要的canvas
var canvas = ateElement('canvas');
var context = Context('2d');
// base64地址图⽚加载完毕后
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 = und(maxWidth *(originHeight / originWidth));
}else{
targetHeight = maxHeight;
targetWidth = und(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 = DataURL(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 = ateObjectURL(blob);
$("#ceshi").attr("src",url);
};
// ⽂件base64化,以便获知图⽚原始尺⼨
img.src = sult;
};
eleFile.addEventListener('change',function(event){
file = event.target.files[0];
// 选择的⽂件是图⽚
pe.indexOf("image")==0){
}
});
}
</script>
</head>
<body>
<img id="ceshi">
<img id="ceshi1">
<input name="file"type="file"id="jjfxSoft_iconPath"> </body>
</html>
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论