加载File API

为什么头像上传会限制我们的文件大小? 您知道,“请选择一张图片(最大50 KB)。” 既然画布已经存在了一段时间,为什么照片处理Web应用程序没有实现呢?

这两个问题的答案都取决于性能。 到目前为止,我们需要通过服务器缓慢的插件或路由来在浏览器中创建和修改文件。 但是对于Internet Explorer 10,Firefox和Chrome用户,开发人员在其工具库中拥有很棒的File API,可以在浏览器中本地进行这些操作。

File API是一种新的JavaScript API,可让您读写表示Web应用程序中文件的二进制数据对象。 简而言之,您可以将用户选择的文件读入Web应用程序,并将新的数据对象作为文件从Web应用程序下载。 让我们更深入地看看。

分解文件API

File API( 由W3C定义 )不是一种类型,而是类型化对象,函数和方法的集合。

文件清单

FileList是存在于许多地方的类型化对象。 首先,作为类型为“文件”的表单输入元素的属性。 其次,作为在放置文件事件或剪贴板事件上分派的事件的一部分(作为复制和粘贴的结果)。

例如,假设您有一个这样的表单输入控件:

<input type=file οnchange="console.log(this.files.length)" multiple />

每当用户单击表单输入并选择一个文件时,此操作就会调度onchange事件处理程序,并且FileList对象(相对于input元素位于this.files上 )上具有一些新条目。 在此示例中,用户选择的文件数被打印到浏览器控制台。

尽管FileList对象的行为类似于本机Array,因为您可以像使用Array一样遍历其内容,但FileList仅包含File对象的不可变实例(如下所述)。

文件

File对象代表FileList的单个文件。 File对象包含有关文件的只读元数据的哈希,包括名称,上次修改日期,大小和类型。 它也用作参考,可以传递给FileReader以读取其内容。

Blob(二进制大对象)

Blob接口公开文件的原始二进制数据。 如果xhr.responseType设置为“ blob”,则可以通过XHRRequest将远程数据用作blob对象。 新的Blob对象是Blob API的实例,并且包含诸如blob.slice(i,i + n)之类的本机方法,可用于将大的Blob对象切成较小的Blob对象。 (在谈论JavaScript对象类型时,我使用的是“ Blob接口”一词,而“ blob对象”是指Blob接口的单个​​实例。)

此外,使用Blob接口构造函数,微小的Blob对象可以再次与此接口合并在一起。

new Blob([blob, blob,...])

您将在BlobBuilder演示中找到一个示例,该示例加载单个MP3文件,然后将其分解为不同的音频文件(音轨),每个音频文件都应用到它们自己的<audio>标签上进行播放。 在演示中,用户可以通过合并轨道以另一种顺序重建MP3,甚至可以将新的Blob对象下载为MP3。

注意:W3C不赞成使用BlobBuilder,而推荐使用Blob。 两者产生相同的结果,但方式不同。 另外,WebKit的BlobBuilder在Internet Explorer和Firefox之间有所不同,因此最好先对Blob进行功能检测。

文件阅读器

FileReader接口采用File或Blob对象并读取其内容-File或Blob对象只是对本地计算机上存储的内容的引用。 可以对FileReader进行优化,以读取各种类型的文件,例如Text(UTF-8),ArrayBuffer(用于二进制)或base64 data-uri。 以下示例显示在给定blob对象实例的情况下如何使用FileReader获取文件的文本。

	var reader = new FileReader();
	reader.onload = function(e){
	       console.log(e.target.result);
	}
	reader.readAsText(blob);

同样,您可以使用最适合文件类型的read方法读取其他内容:readAsArrayBuffer(非常适合用于处理大型二进制文件)或readAsDataURL(如果您希望将内容快速嵌入到DOM对象(例如,图像或音频文件)。

FileReader包括几个事件侦听器:onerror,onloadstart,onabort和onprogress(这对于创建大型文件的进度条和捕获问题很有用)。

URI方案

URI方案是表示文档中对象的URI。 资源可以是文件或Blob,其相应的URL被称为对象URL。 给定Blob或文件引用,您可以使用createObjectURL创建对象URL。 例如:

var objecturl =  window.URL.createObjectURL(blob)

返回引用资源对象的URL,例如“ blob:http%3A // test.com / 666e6730-f45c-47c1-8012-ccc706f17191”。

该字符串可以放置在可以放置典型URI的任何位置,例如,如果对象URI是图像的话,则可以放置在图像标签的src上。 对象资源的使用时间与文档一样长,因此刷新页面便消失了。

文件保存器

FileSaver接口公开了将Blob写入用户的Downloads目录的方法。 实现相当简洁明了:

window.saveAs(blob, "filename")

但是,当前没有浏览器具有此功能。 仅Internet Explorer 10支持一个简单的替代方案: navigator.msSaveOrOpenBlob以及navigator.msSaveBlob 。 但是,正如您将看到的,尽管没有光滑的用户体验,但还是有一些垫片可以创建类似的功能。

因此,关于File API的所有内容都非常底层,作为一个抽象的概念,有很多要消化的地方。 但是不用担心。 上一堂烹饪课是关于如何将这些食材变成您可以咀嚼的东西的。

加入党并树立榜样

我以为我会为聚会打扮( 图1 ),并在http://adodson.com/graffiti/zh_CN/graffiti上创建自己的小照片处理工具。 一探究竟。 从文件系统中选择一个图像,在屏幕上涂鸦,然后下载您的杰作-全部使用File API(加上一些画布方法和指针事件)。

图1
图1. Graffiti File API应用程序

实施涂鸦应用程序

即使图片很华丽,此应用程序也有一个简单的前提:

  • 通过使用File + FileList和FileReader选择一个图像作为背景。
  • 将图像加载到canvas标记中,并使用HTML5 Canvas API处理图像。
  • 使用Blob(或BlobBuilder),saveAs(或saveBlob)或带有对象URL的锚点标记下载新图像。

步骤1:选择一个文件

用户可以为此应用选择图像的方式不只一种。

  • 使用表单输入选择文件
  • 拖放文件
  • 从剪贴板复制并粘贴文件

这些方法中的每一种都连接其侦听器以触发一个名为readFile()的自定义函数,该函数使用FileReader的实例提取文件数据并将用户图像添加到画布。 这是函数的代码。

	// readFile, loads File Objects (which are also images) into our Canvas
	// @param File Object
	function readFile(file){
	  // Create a new FileReader Object
	  var reader = new FileReader();
	  // Set an onload handler because we load files into it asynchronously
	  reader.onload = function(e){
	    // The response contains the Data-Uri, which we can then load into the canvas
	    applyDataUrlToCanvas( reader.result );
	  };
	  reader.reaAsDataURL(file);
	}

在这里,readFile获取File引用(稍后显示)并创建FileReader对象的新实例。 此函数以DataURL的形式读取数据,但也可以以二进制甚至ArrayBuffer的形式读取数据。

要连接该函数,可采用前面提到的方法之一,将File引用用作参数。

使用表单输入选择文件

FileAPI当前(未指定)没有定义本机方法来触发文件选择。 但是使用type = file的旧的受信任表单输入可以很好地完成此工作:

<input type="file" name="picture" accept="image/png, image/jpeg"/>

尽管表单输入元素很笨拙,但它确实具有一些新的附加属性,非常适合此应用程序。

accept属性提示可接受的文件类型。 在此示例中,就是PNG和JPEG。 留给设备适当处理(例如,Windows默认情况下会打开用户图片库,并且仅显示这些类型的文件)。

多重标签使用户可以一步选择一个或多个文件。

接下来,您需要将事件侦听器绑定到表单输入的change事件,以便用户的选择自动触发readFile:

	document.querySelector('input[name=picture]').onchange = function(e){
	     readFile(e.target.files[0]);
	}

此代码仅获取第一个用户选择的文件(无论是否使用了multi属性),然后调用readFile,将文件作为第一个参数传入。

输入一点样式

此处显示的表单输入框与我的审美观念或您的审美观念并不太相符。 因此,将其绝对定位在您选择的另一个元素上,其不透明度为零(但要使其具有固定的宽度,这可能会干扰其他元素)。 或更复杂的一点:在屏幕外的输入框上分配自定义click事件。 在此处阅读有关此讨论的更多信息

拖放文件

可以将文件从文件资源管理器中拖入,并使用与表单输入hack类似的事件模型。 当用户在画布上释放图像时,发生“放置”事件。 该事件包含一个名为dataTransfer的属性,该属性具有一个名为files的子属性。 在下面的代码中,e.dataTransfer.files是FileList的一个实例(如前所述,FileList包含一个File引用列表),并且第一个File项是readFile的参数。 Webkit,Firefox和Internet Explorer 10支持此功能。这是一个示例:

	// stop FireFox from replacing the whole page with the file.
	canvas.ondragover = function () { return false; };
	// Add drop handler
	canvas.ondrop = function (e) {
	  e.preventDefault(); e = e || window.event;
	  var files = e.dataTransfer.files;
	  if(files){
	    readFile(files[0]);
	  }
	};

复制和粘贴文件数据

当用户将内容粘贴到文档中时,可以访问剪贴板数据。 此数据可以是文本和图像的混合,而不是仅包含文件引用的FileList,例如在表单输入控件中或在拖动文件中。

在下面的代码中,遍历剪贴板数据,并过滤掉与类型和种类属性相对应的条目,分别是“ * / image”和“ file”。 使用getAsFile()获得该项目的File实例,该实例传递给readFile。

	// paste Clipboard data
	// Well not all of it just the images.
	document.onpaste = function(e){
	  e.preventDefault();
	  if(e.clipboardData&&e.clipboardData.items){
	    // pasted image
	    for(var i=0, items = e.clipboardData.items;i<items.length;i++){
	      if( items[i].kind==='file' && items[i].type.match(/^image/) ){
	        readFile(items[i].getAsFile());
	        break;
	      }
	    }
	  }
	  return false;
	};

第一步到此结束。 我已经展示了三种获取文件引用并将文件数据加载到文档中的方法。 我想知道是否还有其他方法,因此请发送评论。

步骤2:将图像加载到画布上

步骤1中的readFile函数将生成的数据URL移交给另一个自定义函数applyDataUrlToCanvas。 此功能在画布上绘制选定的图像。 运作方式如下:

  • 找到图像的宽度和高度。
  • 找到图像的方向。
  • 在画布上绘制最适合图像的图像。

查找宽度和高度

使用DOM Image功能,您可以轻松确定任何图像的尺寸。 这是一种方便的技术,它是这样的:

	var img =  new Image();
	img.onload = function(){
	  // img.width
	  // img.height
	}
	img.src = dataURL;

找到方向

不幸的是,这有一个宽度和高度的陷阱,这是一个很大的陷阱:照片可能以人像模式拍摄并保存为横向,或者图像可能颠倒了。

某些相机没有以正确的方向保存图像,而是在图像的EXIF数据中提供了Orientation属性。 可以从图像的二进制数据中读取。

将data-url转换为二进制字符串很容易:

	var base64 = dataUrl.replace(/^.*?,/,'');
	var binary = atob(base64);

幸运的是,有一个由Jacob Seidelin编写的开源EXIF客户端库 ,它将以对象形式返回EXIF数据。 是的,太棒了!

	<script src="http://www.nihilogic.dk/labs/exif/exif.js"></script>
	<script src="http://www.nihilogic.dk/labs/binaryajax/binaryajax.js"></script>
	<script>
	var exif = EXIF.readFromBinaryFile(new BinaryFile(binary));
	//exif.Orientation
	</script>

Orientation属性是1到8范围内的整数,对应于四次旋转和四次翻转(相当冗余)。

将图像绘制到画布

发现“方向”值后,您可以旋转并在画布上绘制。 如果要查看我的算法,只需深入研究源代码,您可以在http://adodson.com/graffiti/https://github.com/MrSwitch/graffiti中找到源代码。

步骤3:下载映像

最后一步是下载修改后的图像。 在FileAPI的库中,您可以使用Blob接口在客户端中创建文件。 使用Internet Explorer 10中的新msSaveBlob或其他现代浏览器中的download属性hack(即将出现)将它们包装起来,它们一起使您能够在客户端中下载文件。

演示中自己尝试。 单击下载按钮。

该演示使用Internet Explorer 10中的canvas.toBlob方法来获取canvas标记中当前绘制的图像的文件引用。 对于Chrome和FireFox, toBlob填充程序效果很好。

	canvas.toBlob(function( file ){
	  // Create a blob file,
	 
	  // then download with the FileSaver
	}

制作Blob对象实例的副本

我们应该可以跳过此步骤,但是由于所有浏览器中都有一个怪癖,您不能直接从canvas.toBlob返回的Blob实例中使用FileSave API。 您需要复制它。

Internet Explorer 10,Chrome和FireFox支持用于创建新Blob引用的BlobBuilder接口。 但是该接口已经被Blob构造函数所取代,该构造函数目前支持有限。

首先,清除BlobBuilder的供应商前缀:

	// Shim the BlobBuilder with the vendor prefixes
	window.BlobBuilder || (window.BlobBuilder = window.MSBlobBuilder||window.MozBlobBuilder||window.WebKitBlobBuilder);

接下来,对代码进行过时验证,并测试Blob构造函数。 否则,构造一个BlobBuilder来构建blob (最好将这些方法包装在try-catch中。)Blob在当前的Android版Chrome浏览器中存在错误。 这是代码。

	var blob;
	if('Blob' in window){
	  try{
	    // The new Blob interface
	    blob = new Blob([file],{ "type" : "image/png"});
	  catch(e){}
	}
	if(!blob){
	  try{
	    // The deprecated BlobBuilder interface
	    var bb = new BlobBuilder();
	    bb.append( file );
	    blob = bb.getBlob("image/png");
	  }
	  catch(e){}
	}

使用FileSaver下载Blob

FileSaver API也是目前所有浏览器尚未采用的标准。 但是,对于Internet Explorer 10,您可以使用msSaveBlob函数(非常棒),对于Chrome和FireFox,您至少可以使用供应商前缀对它们进行将来验证。 因此,saveAs函数需要大量填充:

window.saveAs || (window.saveAs == window.navigator.msSaveBlob || window.webkitSaveAs || window.mozSaveAs || window.msSaveAs /** || URL Download Hack **/ );

这种后备(在https://gist.github.com/3552985上进行了全面描述)使用我们新图像的对象URL弥补了FileSaver界面的不足。 对于支持锚标记上的download属性的浏览器,填充程序将href定义为Object URL,然后调度click事件以强制其下载或在新选项卡中打开。 哦,编织的网片缠结了什么。

最后,给定Blob和文件名,saveAs方法启动下载:

	var name = 'Graffiti.png';
	if(window.saveAs){
	  // Move the builder object content to a blob and
	  window.saveAs(blob, name);
	}
	else{
	  // Fallover, open as DataURL
	  window.open(canvas.toDataURL());
	}

在这里,如果saveAs填充程序不兼容,则故障转移将打开一个带有base64 Data-URL的新选项卡。 这在Internet Explorer 9中有效,但Internet Explorer 8的DataURI长度限制为32 KB。

包起来

如果您还没有使用File API,我强烈建议您这样做。 FileAPI为为浏览器制作类似于桌面的应用程序打开了很大的潜力。 您可能希望对保存文件的位置进行更多控制,甚至覆盖现有文件。 但是就目前而言,出于谨慎的考虑,安全性高涨,因此您不太可能很快看到此类功能。 规格仍在不断变化,但是我在本文中强调的内容已经看到了浏览器供应商的巨额投资,并且即使有可能也不会有太大变化。 请不要引用我。

如果需要支持较旧的浏览器,请查看我的Internet Explorer的dropfile.js填充程序,该填充程序将FileReader填充并创建base64 Data-URI,以及将基于Flash的填充程序替换为Fileify的Downloadify

资源资源

本文最初发布在http://msdn.microsoft.com/zh-cn/magazine/jj835793.aspx,并经许可在此处复制。

From: https://www.sitepoint.com/get-loaded-with-the-file-api/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值