Home » Code » javascript获得图片真实宽高

javascript获得图片真实宽高

<body>
	<img id="img" src="./images/1.jpg" style="width:400px" />
</body>

以上,图片被样式控制为宽400px,它的实际宽度是1000px。如何获得它的真实宽度1000px呢。

很自然的想到width属性,js和jq都试一下:

console.log(img.width);//400
console.log($("#img").width());//400

可惜的是,输出的都是样式控制的值,400。

在HTML5中,新增了naturalWidth属性,它的值就是真实的宽度,不受样式的影响。

console.log(img.naturalWidth);//1000
console.log($("#img").prop("naturalWidth"));//1000
console.log($("#img").attr("naturalWidth"));//undefined

通过natrualWidth,可以方便的获取真实的宽度值。要注意的是jq需要使用prop()方法。

在旧版本的浏览器没有natrualWidth属性情况下怎么办呢?常规做法是新建一个Image对象,把图片的src赋予新对象中,再获取新对象的width,这时有可能获得到真实的宽度。

var Img = new Image();
Img.src = img.src;
console.log(Img.width);//1000

为什么说有可能呢,因为这样做有可能获得的值是0,尤其是第一访问该页面的时候。原因是新对象被赋予了src后读取src远程图片是一个异步过程,有可能还没有读取得到下边就输出了!可行的一个做法是在新对象的onload事件中读取其width,这时的值就不会是0了。

//把获取图片真实宽高封装为函数getNatural
function getNatural(url, type, callback){
	var Img = new Image();
	Img.src = url;
	Img.onload = function(){
		callback.call(null, Img[type]);
	}	
}
//使用时:
getNatural(img.src, 'width', function(result){
	var naturalWidth = result;//真实宽高
	console.log(naturalWidth);
	//do what you want to do...
});

2014/12/08补充:

即使是新创建的Img对象,如果其url对应的图片加载过一次也有可能是被缓存起来的,这时Img的宽高仍是真实的宽高。判断是否缓存成功可通过complete属性,为true即为缓存起来了,亲测IE8下也有效。如果没有被缓存,赋予了Img对象src属性后,返回真实宽高的数据时onload事件还没被触发,也就是在onload被触发之前就有可能Img的宽高已经不是0而是真实的数据了。但这个返回了宽高信息没有事件可以监听,可以通过定时器不断的来检查。通过这样子的做法可以更快的获得宽高信息。综上将getNatural修改为:

function getNatural(url, type, callback)
{
	var startTime = new Date().getTime();
	var img = new Image();
	img.src = url+'?'+startTime;
	if(img.complete)
	{
		console.log('from complete:'+(new Date().getTime()-startTime));
		callback.call(null, img[type]);
	}
	else
	{
		var check = function()
		{
			if(img.width || img.height)
			{
				console.log('from check:'+(new Date().getTime()-startTime));
				callback.call(null, img[type]);
				clearInterval(checkIt);
			}
		}
		var checkIt = setInterval(check, 20);

		img.onload = function()
		{
			console.log('from onload:'+(new Date().getTime()-startTime));
			callback.call(null, img[type]);
		}
	}
}

以上,为url添加时间戳,每次都请求新图片不读缓存,测试一下是onload快还是check快,请求的是网上宽度为1240的图片:

//请求真实宽高
getNatural(image.src, 'width', function(result){
	console.log(result);
})
/*
Chrome数据:
from check:2950
1240
onload:7900
1240

Firefox数据:
from check:2678
1240
from onload:5407
1240

IE8数据:
日志: from check:2471
日志: 1240
日志: from onload:4549
日志: 1240
*/

可以看到,通过定时器检查宽高可以比onload事件更快的得到结果,差距明显。如果url不添加时间戳读缓存,不同浏览器表现不一致:

/*
Chrome下,点击刷新按钮或第一次加载还是走else下的check和onload,
有时check快,有时onload快,但差距几乎可以忽略。都比不读缓存时要快多了;

from onload:633
1240
from check:662
1240

点击地址栏按enter键则肯定是走complete了,时间基本等于0
from complete:2
1240
——————————————————————————————————————————————————————————————————
Firefox缓存比较严重,除第一加载,其他都是走complete,时间基本为0

——————————————————————————————————————————————————————————————————
IE8跟谷歌一样,点击刷新和第一加载走else,按enter才是complete。
但走else居然比谷歌还快,跟直接complete没什么差别了。
日志: from check:20
日志: 1240
日志: from onload:168
日志: 1240

*/

综上,添加complete判断使用定时器检查要比只通过onload触发的版本要好!把以上getNatural里边的console去掉,onload那段去掉,时间戳去掉,就Ok了!

参考文章:http://www.css88.com/archives/5224

2016/01/21补充

对于多图,封装以下函数可行:

function imageLoaded(imgSrcArr, callback) {
  var total = imgSrcArr.length;
  var count = 0;    
  for (var i = 0;i < total;i++) {
    (function(i) {
      var imgObj = new Image();
      imgObj.src = imgSrcArr[i];
      if (imgObj.complete) {
        count++;
      } else {
        imgObj['t'] = setInterval(function() {
          if (imgObj.width || imgObj.height) {
            count++;
            clearInterval(imgObj['t']);
          }
        }, 20);
      }
    })(i);       
  }        
  var callbackInterval = setInterval(function() {
    if (count >= total) {
      clearInterval(callbackInterval);
      callback();
    }
  }, 50);  
}

Leave a Reply

Your email address will not be published. Required fields are marked *

*

Time limit is exhausted. Please reload CAPTCHA.