图集1/4

正文 2256字数 540,138阅读

  之前的文章中有介绍过类似的东西,但是那中方法依然会把整张图片加载下来,只不过是在加载完成前获取了图片尺寸而已。

现在,我们要使用更直接的方法,直接从服务器上读取到图片的尺寸信息。之前的文章就介绍过了关于图片头的知识,现在我要向服务器发送一个HTTP请求,让服务器返回图片的尺寸信息,然后自己解析就行了。

这种方法比较适合PNG和GIF图片,因为他们的头信息中的尺寸位置是固定的。我们很容易就能解析出它的大小,JPG图片由于头部的描述信息在尺寸信息之前。

所以我们无法直接获取它尺寸信息在文件流中的位置。虽然可以加载整个头来分析,但是我不推荐使用这种做法来获取JPG文件的尺寸,除非你服务器上的JPG图片是固定格式生成的。

  断点续传这种技术我想大家没用过也应该听说过吧,这就是运用了HTTP协议中的Range字段来指定让服务器返回数据流中的部分信息。现在,我们就利用这个Range字段让服务器返回图片的尺寸信息。要向服务器发送这个Range字段首先要知道,图片的尺寸信息在图片文件流中的位置,我们用16进制工具打开图片就能找到。

  上图是PNG和GIF文件的尺寸信息保存的位置PNG是从第16字节到第23字节,GIF是从第6字节到第9字节。先不说啥了,来看代码
//获取浏览器版本 var isIE=navigator.userAgent.match(/MSIE (\d)/i); isIE=isIE?isIE[1]:undefined; //变量声明 var xhr,w,h,s; //创建HTTP对象 if(isIE) xhr=new ActiveXObject("Microsoft.XMLHTTP"); else{ xhr=new XMLHttpRequest; //设置返回值的类型 xhr.responseType="arraybuffer"; }; //创建HTTP请求 xhr.open("GET","onepiece.png",true); //在请求头中添加Range字段 xhr.setRequestHeader("Range","bytes=16-23"); //异步回调函数 xhr.onreadystatechange=function(){ if(xhr.readyState==4){ //获取二进制流并转换成数组 s=isIE ?new VBArray(xhr.responseBody).toArray() :new Uint8Array(xhr.response); //解析返回信息 w=(s[0]<<24)+(s[1]<<16)+(s[2]<<8)+s[3]; h=(s[4]<<24)+(s[5]<<16)+(s[6]<<8)+s[7]; alert("宽:"+w+"\n高:"+h); }; }; //发送请求 xhr.send();
Run code
Cut to clipboard


      上面就是获取PNG图片尺寸的代码。先创建一个XHR对象,这东西是AJAX的基础我就不多说了。这里关键的是非IE中的responseType必须设置成arraybuffer,要不如返回的结果会被强制转换成字符,这可能会导致字节丢失。

    致至于Range字段的参数简单的用法就是bytes=开始字节-结束字节,当然还有很多用法,这篇文字关键不是说这个所以就不介绍了。下面是接收返回的二进制数据,在浏览器上有差异,IE使用responseBody返回,但是它返回的是一个内存数组,JS的数组是经过封装的类数组所以不能直接接收。

    但是可以用VBS中的数组来接收,因为VBS的数组是内存数组,这就是为什么在微软的脚本引擎上VBS的效率比JS效率高的原因。获取VBArray之后可以用它的toArray方法转换成JS使用的数组,这个是微软提供的VBS和JS之间沟通的接口。

    接下来就是非IE浏览器的部分了。我们用response接收服务器返回的数据,这个类型我们在创建XHR对象的时候就已经设置了,所以可以直接使用Uint8Array把它转换成JS可用的无符号整型 数组。最后一个步骤就是解析这个数组,PNG的尺寸部分前4位是宽度,后4位是高度。我们只要逐个字节计算位权然后相加就可以得到宽度和高度了。

      至于GIF的获取方法,和上面这个代码大同小异。你只需要修改Range的参数和最后一部的解析返回值就可以了,我就不再演示了。这个方法加载的最大好处就是不用去请求整个图片,我去找个超级大的图片来试试

      这图片够大了吧,如果直接使用Image对象载入它,用户会奔溃的。但是使用这个方法就算网速很差也不会有什么影响。而且还可以节省服务器的资源,服务器只需要处理我们请求的几个字节的数据就可以了,不用载入整张图片。基本上一瞬间就可以获取到图片的大小。

      好了,我想现在应该都会使用这方法了吧。对于其它图片格式当然也不是不行只不过麻烦,但是如果把它封装好就不会麻烦了。因为这个东西也不会经常用到,所以我也懒的封装这个了。