画像サイズ(ファイルサイズではない)をすばやく取得する方法


138

画像の高さと幅をピクセル単位で取得する高速な方法を探しています。少なくともJPG、PNG、TIFFを処理する必要がありますが、多いほど良いです。私の画像はかなり大きい(最大250 MB)ため、高速で強調します。ImageMagickをidentify使用すると、最初に画像全体を読み取るため、サイズを取得するのに時間がかかりすぎます。

できれば、Ruby、またはRails 3でもうまく機能する方法を探します。

私は理論に関することを知っています(さまざまな画像形式、そのヘッダーとその違いなど)。確かに、かなり一般的な方法で私の問題を解決できる何らかのライブラリを求めています。

私はちょうど開発が死んでいるようですが有望に見える画像サイズを見つけました。


8
これは、ImageMagickの新しいバージョンには当てはまらないようです。ImageMagick 6.5.4-7を使用して、identify(少なくともTIFおよびPNGの場合)がヘッダー(最大60KB)のみを読み取り、335MBの画像でも非常に高速に動作することを確認しました。
coderforlife 2014

回答:


195
  • このfileコマンドは、いくつかの画像フォーマット(PNG、GIF、JPEG、最近のバージョンではPPM、WEBPなど)の寸法を印刷し、ヘッダーのみを読み取ります。

  • identifyコマンド(ImageMagickのから)は、画像の多種多様な画像情報の多くを印刷します。ヘッダー部分の読み取りに制限されているようです(コメントを参照)。また、file悲しいことに欠けている統一された出力を持っています。

  • exiv2EXIFヘッダーが存在しない場合でも、JPEG、TIFF、PNG、GIF、WEBPを含む多くの形式の寸法を提供します。ただし、そのためにデータ全体を読み取るかどうかは不明です。サポートされているすべての画像形式については、exiv2のマンページを参照してください。

  • head -n1 PPM、PGM形式の寸法が表示されます。

ウェブで人気のあるフォーマットの場合はexiv2identifyとの両方で十分です。ユースケースによっては、いくつかのツールの出力を結合/解析する独自のスクリプトを作成する必要がある場合があります。


3
ImageMagickのidentifyコマンドでいくつかのテストを行い、straceを使用してopen / read / mmap / close呼び出しを記録し、識別された画像から読み取られたデータ量を確認しました。ファイルタイプとファイルサイズによって多少異なりますが、5〜335 MBの画像に対して「identify」によって20〜60 KBが読み取られていました(すべてのバイトが読み取られることを示す「convert」に対してもテストしました)。したがって、ここでは「識別」が適切な選択のように見えます(すべての一般的な形式をサポートし、ヘッダーのみを読み取るため)。
coderforlife 2014

1
exiv2もPNGを実行すると思います。
chx 2014

そのファイルコマンド出力を簡単に解析する方法はありますか?識別は素晴らしいですが、悲しいことにWebPファイルでは機能しません
ブライアンリーシュマン

Identify WebPで動作し、ImageMagickは長年WebPをサポートしています。たぶん、あなたはアップデートを入手できますか?
ypnos

32

PHPがインストールされているかどうかはわかりませんが、このPHP関数はかなり便利です

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

1
これは「識別する」よりもはるかに高速です。良いアプローチ。ありがとう。
souravb

19

ImageMagickの識別機能を使用できます。bashでこれを行う方法を次に示します($ 0はイメージのパスです)。

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

そして、これは潜在的なエラーメッセージも隠します。最新の実装でidentifyは、画像全体ではなくヘッダーのみを読み取るため、高速です。しかし、それが他の方法とどのように比較されるかはわかりません。


2
この方法の方がはるかに効率的だと思いますread width height < <(identify -format "%w %h" "${1}")
。– Cromax

5

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

ここでは、PNGとJPGの2つの形式について説明します。

私のコードは、私の用途に合わせて設計されたクラスからのものであり、必要に応じて編集できます。

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]

Javaでref/ outパラメータを取得するためのハックとして、引数に配列を使用しているようです-これはベストプラクティスと見なされていますか?

この回答は非常に古く、今は更新するつもりはありませんが(多くのことを忘れており、時間がありません)、コードを確認して編集できます。
joseluisbz 2017年


この例では、Format、High、Widthの3つのフィールドを持つ新しいクラスを実装し、このクラスのインスタンスを返すことをお勧めします。
joseluisbz 2017年

1

必要なピクセル寸法(幅と高さ)だと思いますか?

ほとんどのファイル形式には、寸法を定義するいくつかのヘッダー情報があるので、ファイルを読み取るソフトウェアは、ファイルの読み取りを開始する前に予約する必要がある領域を知ることができると思います。一部の「生の」タイプのファイル形式は、ピクセルの各水平行の終わりに「行の終わり」バイトがあるバイトストリームである場合があります(この場合、ソフトウェアは最初の行を読み取り、バイトストリームのサイズを分割する必要があります)行の長さで高さを取得します)。

読み方を知るためにファイル形式を理解する(またはもちろんライブラリを使用する)必要があるため、これを「一般的な」方法で作成することはできないと思います。ほとんどの場合、ファイル全体を読み取らずに寸法の大まかな見積もりを与えるコードを見つけることができますが、一部のファイルタイプでは、ファイル全体を読み取って実際の寸法を確認する必要がある場合があります。ほとんどのWeb中心の画像フォーマットには、そのような情報を持つヘッダーがあり、画像全体がロードされる前にブラウザーがボックスの寸法を作成できると思います。

良いライブラリには、処理するファイルのサイズを取得するいくつかのメソッドがあり、それらのメソッドは可能な限り効率的に実装されると思います。

更新imageinfoはあなたが望むことをするようです。(テストしていません)


そのツールは、私が必要とするのと同じくらい速く動作します;)。私はそれを適切に使用できるかどうかを確認します。
dAnjou

0

画像にEXIF情報がある場合は、EXIFヘッダーを読み取るだけです。


残念ながら、どのような画像があり、EXIFデータがあるかどうかはわかりません。
dAnjou

3
どのように多くのあなたのイメージのDOその情報を持っていますか?多分それらの90%がEXIFデータを持っているなら、他の10%でImageMagickを使うことの遅さは受け入れられるでしょう。
アンディレスター

なぜこの回答には反対票があるのですか?これは質問に対する有効な回答であり、OPまたは他の誰かが探しているものとまったく同じかもしれません。
シェパード、

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

それでも遅い入力画像の例を作成できますか?


0

tldr:ファイル「imagename」が実行します

webp、すべてのjpg形式(jpeg、jpg200、..)、

出力例は次のようになります

JPEG画像データ、JFIF標準1.02、アスペクト比、密度1x1、セグメント長16、ベースライン、精度8、650x400、フレーム3

ファイルの出力をpythonリストに読み込み、リストの4番目のフィールドを使用します。

参考までに、ネットワークトラフィックを削減するために約18000以上の画像を最適化しました。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.