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

时间:2011-01-12 14:41:00

标签: linux image

我正在寻找一种快速方式来获取图像的高度和宽度(以像素为单位)。它应该至少处理JPG,PNG和TIFF,但越多越好。我强调快速因为我的图像非常大(高达250 MB)并且使用ImageMagick的identify获得大小需要太长时间,因为它显然首先将图像作为整体读取。 / p>

最好,我寻找一种在Ruby中运行良好的方法,甚至在Rails 3中。

我知道理论内容(各种图像格式,标题及其差异等)。实际上,我要求某种类型的库可以以相当通用的方式解决我的问题。

我刚发现imagesize看起来很有希望,虽然发展似乎已经死了。

8 个答案:

答案 0 :(得分:181)

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

  • identify命令(来自ImageMagick)可以打印各种图像的大量图像信息。它似乎限制自己阅读标题部分(见评论)。它还有一个file遗憾地缺乏的统一输出。

  • exiv2为您提供多种格式的尺寸,包括JPEG,TIFF,PNG,GIF,WEBP,即使没有EXIF标题。目前还不清楚它是否读取了整个数据。有关所有支持的图像格式,请参阅exiv2的联机帮助页。

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

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

答案 1 :(得分:31)

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

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

答案 2 :(得分:14)

您可以使用ImageMagick的identify功能。这是你在bash中的表现(注意$ 0是图像的路径):

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

这也隐藏了任何潜在的错误消息。 identify的现代实现只读取标题,而不是整个图像,所以它很快。不知道它与其他方法相比如何。

答案 3 :(得分:5)

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]

答案 4 :(得分:1)

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

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

我认为您不能以任何“通用”方式进行此操作,因为您需要了解文件格式(或使用库当然)以了解如何阅读它。您可以找到一些代码,在大多数情况下会粗略估计维度而不读取整个文件,但我认为某些文件类型可能需要您阅读整个文件以确定它的实际尺寸。我希望大多数以网络为中心的图像格式都有一个包含此类信息的标题,以便浏览器可以在加载整个图像之前创建框尺寸。

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

更新imageinfo似乎符合您的要求。 (尚未测试过)

答案 5 :(得分:0)

如果图像中有EXIF信息,则只需读取EXIF标题即可。

答案 6 :(得分:0)

-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

您能否生成一个仍然很慢的示例输入图像?

答案 7 :(得分:0)

tldr:文件“图像名称”将起作用

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

样本输出类似于

  

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

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

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