获取图像尺寸的快速方法(不是文件大小)

我正在寻找一个 很快的方法,以获得像素的高度和宽度的图像。它应该处理至少 JPG,PNG 和 TIFF,但越多越好。我强调 很快是因为我的图像非常大(高达250MB) ,而且用 ImageMagick 的 identify得到大小需要很长时间,因为它显然首先读取整个图像。

最好是,我在寻找一种在 Ruby 中工作得很好的方法,甚至在 Rails 3中也是如此。

我知道理论上的东西(各种图像格式,它们的标题和它们的差异,等等)。实际上,我要求使用某种类型的库,以相当通用的方式解决我的问题。

我刚刚发现的 想象一下看起来很有希望,虽然发展似乎死了。

102540 次浏览

如果图像中有 EXIF 信息,可以直接读取 EXIF 标题。

我不确定是否安装了 PHP,但是这个 PHP 函数非常方便

 php -r "print_r(getimagesize('http://www.google.com/images/logos/ps_logo2.png'));"

我猜这是你想要的像素尺寸(宽度和高度)吧?

我认为大多数文件格式都有一些定义尺寸的头信息,这样读取文件的软件就可以知道在开始读取文件之前它必须保留多少空间。一些“原始”类型的文件格式可能只是一个字节流,在每个水平像素行的末尾有一些“行尾”字节(在这种情况下,软件必须读取第一行,并除以字节流的大小除以行长来获得高度)。

我不认为您可以以任何“通用”的方式编写这个文件,因为您需要了解文件格式(当然也可以使用库) ,以便知道如何阅读它。您可能会找到一些代码,在大多数情况下,不需要读取整个文件就可以粗略地估计尺寸,但是我认为有些文件类型可能需要您读取整个文件,以确定它真正具有的尺寸。我希望大多数以网页为中心的图片格式都有一个带有此类信息的头部,这样浏览器就可以在加载整个图片之前创建框尺寸。

我猜想一个好的库应该有一些方法来获取它所处理的文件的维度,并且这些方法应该尽可能有效地实现。

更新 : 图片信息似乎可以满足您的需求。(尚未测试)

  • file命令打印几种图像格式(例如 PNG、 GIF、 JPEG; 最近的版本也是 PPM、 WEBP)的尺寸,并且只读取标题。

  • identify命令 (来自 ImageMagick)为各种图像打印大量图像信息。它似乎限制自己阅读标题部分(见注释)。它还使用了 file所缺乏的统一格式。

  • exiv2提供了多种格式的尺寸,包括 JPEG、 TIFF、 PNG、 GIF、 WEBP,即使没有 EXIF 头。不过,目前还不清楚它是否读取了这方面的全部数据。有关所有支持的图像格式,请参见 exiv2的页面。

  • head -n1将为您提供 PPM,PGM 格式的尺寸。

对于在网络上流行的格式,exiv2identify都可以。 根据不同的用例,您可能需要编写自己的脚本来组合/解析多个工具的输出。

Https://joseluisbz.wordpress.com/2013/08/06/obtaining-size-or-dimension-of-images/ (BMP、 PNG、 GIF、 JPG、 TIF 或 WMF)

这里有两种格式的 PNG 和 JPG。

我的代码是从一个类设计的,我使用,你可以根据你的需要编辑。

请使用 PHP检查这些函数/方法:

  public function ByteStreamImageString($ByteStream,&$Formato,&$Alto,&$Ancho) {
$Alto = 0;
$Ancho = 0;
$Formato = -1;
$this->HexImageString = "Error";
if (ord($ByteStream[0])==137 && ord($ByteStream[1])==80 && ord($ByteStream[2])==78){
$Formato = 1; //PNG
$Alto = $this->Byte2PosInt($ByteStream[22],$ByteStream[23]);
$Ancho = $this->Byte2PosInt($ByteStream[18],$ByteStream[19]);
}
if (ord($ByteStream[0])==255 && ord($ByteStream[1])==216
&& ord($ByteStream[2])==255 && ord($ByteStream[3])==224){
$Formato = 2; //JPG
$PosJPG = 2;
while ($PosJPG<strlen($ByteStream)){
if (sprintf("%02X%02X", ord($ByteStream[$PosJPG+0]),ord($ByteStream[$PosJPG+1]))=="FFC0"){
$Alto = $this->Byte2PosInt($ByteStream[$PosJPG+5],$ByteStream[$PosJPG+6]);
$Ancho = $this->Byte2PosInt($ByteStream[$PosJPG+7],$ByteStream[$PosJPG+8]);
}
$PosJPG = $PosJPG+2+$this->Byte2PosInt($ByteStream[$PosJPG+2],$ByteStream[$PosJPG+3]);
}
}
if ($Formato > 0){
$this->HexImageString = "";
$Salto = 0;
for ($i=0;$i < strlen($ByteStream); $i++){
$Salto++;
$this->HexImageString .= sprintf("%02x", ord($ByteStream[$i]));
if ($Salto==64){
$this->HexImageString .= "\n";
$Salto = 0;
}
}
}
}




private function Byte2PosInt($Byte08,$Byte00) {
return ((ord($Byte08) & 0xFF) << 8)|((ord($Byte00) & 0xFF) << 0);
}

使用 PHP 代码:

      $iFormato = NULL;//Format PNG or JPG
$iAlto = NULL; //High
$iAncho = NULL;//Wide
ByteStreamImageString($ImageJPG,$iFormato,$iAlto,$iAncho);//The Dimensions will stored in  iFormato,iAlto,iAncho

现在使用 JAVA的这些函数/方法:

  private void ByteStreamImageString(byte[] ByteStream,int[] Frmt,int[] High,int[] Wide) {
High[0] = 0;
Wide[0] = 0;
Frmt[0] = -1;
this.HexImageString = "Error";
if ((int)(ByteStream[0]&0xFF)==137 && (int)(ByteStream[1]&0xFF)==80 &&(int)(ByteStream[2]&0xFF)==78){
Frmt[0] = 1; //PNG
High[0] = this.Byte2PosInt(ByteStream[22],ByteStream[23]);
Wide[0] = this.Byte2PosInt(ByteStream[18],ByteStream[19]);
}
if ((int)(ByteStream[0]&0xFF)==255 && (int)(ByteStream[1]&0xFF)==216
&&(int)(ByteStream[2]&0xFF)==255 && (int)(ByteStream[3]&0xFF)==224){
Frmt[0] = 2; //JPG
int PosJPG = 2;
while (PosJPG<ByteStream.length){
if (String.format("%02X%02X", ByteStream[PosJPG+0],ByteStream[PosJPG+1]).equals("FFC0")){
High[0] = this.Byte2PosInt(ByteStream[PosJPG+5],ByteStream[PosJPG+6]);
Wide[0] = this.Byte2PosInt(ByteStream[PosJPG+7],ByteStream[PosJPG+8]);
}
PosJPG = PosJPG+2+this.Byte2PosInt(ByteStream[PosJPG+2],ByteStream[PosJPG+3]);
}
}
if (Frmt[0] > 0){
this.HexImageString = "";
int Salto = 0;
for (int i=0;i < ByteStream.length; i++){
Salto++;
this.HexImageString += String.format("%02x", ByteStream[i]);
if (Salto==64){
this.HexImageString += "\n";
Salto = 0;
}
}
}
}




private Integer Byte2PosInt(byte Byte08, byte Byte00) {
return new Integer (((Byte08 & 0xFF) << 8)|((Byte00 & 0xFF) << 0));
}

使用 Java 代码:

        int[] iFormato = new int[1]; //Format PNG or JPG
int[] iAlto = new int[1]; //High
int[] iAncho = new int[1]; //Wide
ByteStreamImageString(ImageJPG,iFormato,iAlto,iAncho); //The Dimensions will stored in  iFormato[0],iAlto[0],iAncho[0]

Imagemagick -ping选项

它似乎就是为此而引进的。

然而,在 ImageMagick 6.7.7中,我没有观察到任何大文件的减速,例如:

head -c 100000000 /dev/urandom > f.gray
# I don't recommend that you run this command as it eats a lot of memory.
convert -depth 8 -size 20000x10000 f.gray f.png
identify f.png

你能生成一个输入图像仍然很慢的例子吗?

参见: ImageMagick 能返回图像大小吗?

可以使用 ImageMagick 的 确认身份函数,下面是在 bash 中的操作方法(注意 $0是图像的路径) :

width=$(identify -format "%w" "$0")> /dev/null
height=$(identify -format "%h" "$0")> /dev/null

这也隐藏了任何潜在的错误消息。现代的 identify实现只读头部,而不是整个图像,所以速度很快。但不确定与其他方法相比如何。

文件“ imagename”就可以了

使用 webp,所有 jpg 格式(jpeg,jpg200,. .) ,

样本输出看起来像

JPEG 图像数据,JFIF 标准1.02,长宽比,密度1x1, 片段长度16,基线,精度8,650x400,帧3

将文件的输出加载到 python 列表中并使用列表中的第4个字段。

仅供参考,确实优化了大约18000多张图片,以减少网络流量。