Web 技术研究所

我一直坚信着,Web 将会成为未来应用程序的主流

不加载图片!直接HTTP方式获取图片尺寸

  之前的文章中有介绍过类似的东西,但是那中方法依然会把整张图片加载下来,只不过是在加载完成前获取了图片尺寸而已。现在,我们要使用更直接的方法,直接从服务器上读取到图片的尺寸信息。之前的文章就介绍过了关于图片头的知识,现在我要向服务器发送一个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();

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

  好了,我想现在应该都会使用这方法了吧。对于其它图片格式当然也不是不行只不过麻烦,但是如果把它封装好就不会麻烦了。因为这个东西也不会经常用到,所以我也懒的封装这个了。
网名:
3.84.186.*
电子邮箱:
仅用于接收通知
提交 悄悄的告诉你,Ctrl+Enter 可以提交哦
神奇海螺
[查看全部主题]
各类Web技术问题讨论区
发起新主题
本模块采用即时聊天邮件通知的模式
让钛合金F5成为历史吧!
次碳酸钴的技术博客,文章原创,转载请保留原文链接 ^_^