插件图片元素操作API

388 阅读6分钟

近在做图片上传,接触了一些图片相关的转化操作。主要涉及blob,canvas,dataurl。做一下笔记,以免时间长了忘记。

名词解释

Blob

Blob对象表示不可变的类似文件对象的原始数据。Blob表示不一定是JavaScript原生形式的数据。File接口基于Blob,继承了blob的功能并将其扩展使其支持用户系统的文件。

摘自MDN

File对象的区别

File对象就是一个文件,当我们使用input type="file"标签来上传文件,我们在代码里得到的对象就是一个File对象。

Blob对象就是二进制数据,用来包装二进制文件的容器,可以通过new Blob()创建的对象就是Blob对象。又比如,在XMLHttpRequest里,如果指定responseType为blob,那么得到的返回值也是一个blob对象。

File继承于Blob

fileReader

fileReader对象允许Web应用程序异步读取存储在计算机上的文件(原始数据缓冲区)的内容,使用File或Blob对象指定要读取的文件或数据。

摘自MDN

FileReader是用来读取内存中的文件的API,支持FileBlob两种格式。

转化关系

这边从使用场景出发,来整理一下。

file转化为DataURL

场景: 获取到一个file类型的图片,直接在页面中预览。如果等图片上传完服务器返回图片的地址,再赋值给img的src属性,无疑浪费了时间和带宽。如果直接在html中预览?这里就是利用html5的新特性,将图片转换为Base64的形式显示出来。

下面的方法可以用于在浏览器上预览本地图片或者视频。

方法1:URL.createObjectURL

该方法会根据传入的参数创建一个指向该参数对象的URL,这个URL是一个基于当前文件并且存储在内存中的URL,直到document触发了unload事件或者执行revokeObjectURL来释放。

可以用于在浏览器上预览本地图片或者视频

使用方法如下

objectURL = URL.createObjectURL(param);
  • 参数:可以为File或者Blob对象
  • 返回:一段带hash的url,类似blob:null/2c5e93e3-f06e-4bf2-8942-1708759bf7a7

注意:在每次调用 createObjectURL()方法时,都会创建一个新的 URL 对象。当不再需要这些 URL 对象时,每个对象必须通过调用URL.revokeObjectURL()方法来释放,让浏览器知道这个URL已经不再需要指向对应的文件。URL.revokeObjectURL()方法会释放一个通过URL.createObjectURL()创建的对象URL。浏览器关闭后自动释放这个对象,但是为了获得最佳性能和内存使用状况,你应该在安全的时机主动释放掉它们。

代码如下

let img = document.createElement("img");
img.src = window.URL.createObjectURL(files[i]);
img.width = 200;
img.onload = function() {
	window.URL.revokeObjectURL(this.src);
}
document.body.appendChild(img);

方法2:FileReader.readAsDataURL

该方法会读取指定的 Blob 或 File 对象。读取操作完成的时候,readyState 会变成已完成(DONE),并触发 loadend 事件,同时 result 属性将包含一个data:URL格式的字符串(base64编码)以表示所读取文件的内容。

使用方法如下

FileReader.readAsDataURL(blob);
  • 参数:可以为File或者Blob对象
  • 返回:图片的base64编码。类似data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEASABIA

代码如下

let reader = new FileReader();
reader.onload = function(e) {
  // result属性是包含data:URL格式的字符串(base64编码)表示读取的文件内容
  img.src = e.target.result;
  img.onload = function() {
    dosomething()
  }
}
// 读取file对象
reader.readAsDataURL(files[i]);

两种方法的区别

1、执行时机

  • createObjectURL是同步执行(立即的)
  • FileReader.readAsDataURL是异步执行

2、内存使用

  • createObjectURL返回一段带hashurl,并且一直存储在内存中。
  • FileReader.readAsDataURL则返回包含很多字符的base64,并会比blob url消耗更多内存,但是在不用的时候会自动从内存中清除(通过垃圾回收机制)

3、兼容性

  • createObjectURL支持从IE10往上的所有现代浏览器
  • FileReader.readAsDataURL同样支持从IE10往上的所有现代浏览器

从上面答案不难看出,两者的优劣势

  • 使用createObjectURL可以节省性能并更快速,只不过需要在不使用的情况下手动释放内存

  • 如果不太在意设备性能问题,并想获取图片的base64,则推荐使用

canvas 转化为DataURL

场景: canvas画出来的图片,需要在其它地方预览或者作为组件之间通信的参数。

使用方法如下

canvas.toDataURL(type, encoderOptions);
  • 参数:
    • type:图片格式,默认为 image/png
    • encoderOptions:在指定图片格式为 image/jpegimage/webp的情况下,可以从 0 到 1 的区间内选择图片的质量。如果超出取值范围,将会使用默认值 0.92。其他参数会被忽略。
  • 返回:图片的base64编码。类似data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEASABIA

使用

  • 当一个内容画到canvas上时,我们可以将它生成任何一个格式支持的图片文件。
  • 这个方法也可以用来对图片进行格式转化。比如,file(png格式) -> canvas -> base64(webp格式),参考下图。
  • 这个方法还可以用来压缩图片。

canvas 转化为blob

场景: canvas画出来的图片,或者利用canvas完成截图功能之后,我们需要把对应的文件上传到服务器。

使用方法如下

canvas.toBlob(callback, type, encoderOptions);
  • 参数:
    • callback:回调函数,可获得一个单独的Blob对象参数
    • type:DOMString类型,指定图片格式,默认格式为image/png
    • encoderOptions:Number类型,值在0与1之间,当请求图片格式为image/jpeg或者``image/webp时用来指定图片展示质量。如果这个参数的值不在指定类型与范围之内,则使用默认值,其余参数将被忽略。
  • 返回:无返回值

得到Blob对象以后,可以利用XML2的FormData对象上传,模拟表单控件,异步上传这个二进制文件。

代码如下

canvas.toBlob && canvas.toBlob(function(blob) {
 let myForm = new FormData();
	myForm.append('image', blob); //向表单中添加一个键值对
};

DataURL或img转canvas

场景: 想要对图片想要进行一些操作,比如加蒙层,修饰,裁剪等等,这些操作可以利用canvas的特性去完成。

使用方法如下

context.drawImage(img,sx,sy,swidth,sheight,x,y,width,height);
  • 参数
    • image:绘制到上下文的元素。
    • sx:需要绘制到目标上下文中的,image的矩形(裁剪)选择框的左上角 X 轴坐标。
    • sy:需要绘制到目标上下文中的,image的矩形(裁剪)选择框的左上角 Y 轴坐标。
    • swidth:需要绘制到目标上下文中的,image的矩形(裁剪)选择框的宽度。如果不说明,整个矩形(裁剪)从坐标的sxsy开始,到image的右下角结束。
    • sheight:需要绘制到目标上下文中的,image的矩形(裁剪)选择框的高度。

drawImage

代码如下

function dataURLToCanvas(dataurl){
	let canvas = document.createElement('canvas');
	let ctx = canvas.getContext('2d');
	let img = new Image();
	img.onload = function(){
		canvas.width = img.width;
		canvas.height = img.height;
		ctx.drawImage(img, 0, 0);
	};
	img.src = dataurl;
}

博客都会先发布在github上。 如果有错误或者不严谨的地方,欢迎给予指正,十分感谢。 如果喜欢或者有所帮助,欢迎star。新手需要鼓励,希望大家不要吝啬自己的赞哦,赠人玫瑰,手有余香。

传送门github