Schneller Weg, um Bildabmessungen zu erhalten (keine Dateigröße)

138

Ich suche nach einem schnellen Weg, um die Höhe und Breite eines Bildes in Pixel zu ermitteln. Es sollte mindestens JPG, PNG und TIFF verarbeiten, aber je mehr desto besser. Ich betone schnell, weil meine Bilder ziemlich groß sind (bis zu 250 MB) und es soooo lange dauert, bis die Größe mit ImageMagick erreicht ist, identifyda die Bilder offensichtlich zuerst als Ganzes gelesen werden.

Am besten suche ich nach einem Weg, der in Ruby oder sogar in Rails 3 gut funktioniert.

Ich kenne die Theorie (verschiedene Bildformate, ihre Überschriften und ihre Unterschiede usw.). In der Tat bitte ich um eine Art Bibliothek, die mein Problem auf ziemlich allgemeine Weise lösen kann.

Ich habe gerade eine Bildgröße gefunden, die vielversprechend aussieht, obwohl die Entwicklung tot zu sein scheint.

dAnjou
quelle
8
Dies scheint für neue Versionen von ImageMagick nicht zuzutreffen. Mit ImageMagick 6.5.4-7 habe ich bestätigt, dass identify (zumindest für TIF und PNG) nur den Header liest (bis zu 60 KB) und selbst für 335 MB-Bilder sehr schnell funktioniert.
Coderforlife

Antworten:

195
  • Der fileBefehl druckt die Abmessungen für verschiedene Bildformate (z. B. PNG, GIF, JPEG; neuere Versionen auch PPM, WEBP) und liest nur den Header.

  • Der identifyBefehl (von ImageMagick) druckt viele Bildinformationen für eine Vielzahl von Bildern. Es scheint sich darauf zu beschränken, den Header-Teil zu lesen (siehe Kommentare). Es hat auch eine einheitliche Ausgabe, die fileleider fehlt.

  • exiv2bietet Ihnen Dimensionen für viele Formate, einschließlich JPEG, TIFF, PNG, GIF, WEBP, auch wenn kein EXIF-Header vorhanden ist. Es ist jedoch unklar, ob die gesamten Daten dafür gelesen werden. In der Manpage von exiv2 finden Sie alle unterstützten Bildformate.

  • head -n1 gibt Ihnen die Abmessungen für PPM- und PGM-Formate an.

Für Formate, die im Web beliebt sind, werden beide exiv2und identifydie Arbeit erledigen. Je nach Anwendungsfall müssen Sie möglicherweise ein eigenes Skript schreiben, das die Ausgaben mehrerer Tools kombiniert / analysiert.

ypnos
quelle
3
Ich habe einige Tests mit dem ImageMagick-Identifizierungsbefehl durchgeführt und Strace verwendet, um Aufrufe zum Öffnen / Lesen / mmap / Schließen aufzuzeichnen, um festzustellen, wie viele Daten aus dem identifizierten Bild gelesen wurden. Es hängt zwar leicht vom Dateityp und der Dateigröße ab, aber ich habe 20-60 KB durch "Identifizieren" für 5-335 MB-Bilder gelesen (ich habe auch gegen "Konvertieren" getestet, bei dem alle gelesenen Bytes angezeigt wurden). Es sieht also so aus, als ob "Identifizieren" hier eine gute Wahl ist (da es alle gängigen Formate unterstützt und nur den Header liest).
Coderforlife
1
Ich denke, exiv2 macht auch PNG.
chx
Gibt es Möglichkeiten, die Ausgabe dieser Dateibefehle einfach zu analysieren? Identifizieren ist großartig, aber es funktioniert leider nicht mit WebP-Dateien
Brian Leishman
Identify funktioniert mit WebP und ImageMagick unterstützt WebP seit Jahren. Vielleicht könntest du ein Update bekommen?
Ypnos
32

Ich bin nicht sicher, ob Sie PHP installiert haben, aber diese PHP-Funktion ist ziemlich praktisch

 php -r "print_r(getimagesize('http://www.google.com/images/logos/ps_logo2.png'));"
ajreal
quelle
1
Dies ist viel schneller als "identifizieren". Guter Ansatz. Vielen Dank.
Souravb
19

Sie können die Identifizierungsfunktion von ImageMagick verwenden. So geht's in Bash (Hinweis: $ 0 ist der Pfad des Bildes):

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

Und dies verbirgt auch mögliche Fehlermeldungen. Moderne Implementierungen identifylesen nur den Header, nicht das gesamte Image, also ist es schnell. Ich bin mir nicht sicher, wie es mit anderen Methoden verglichen wird.

James L.
quelle
2
Ich glaube, es ist viel effizienter auf diese Weise: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 oder WMF)

Hier für zwei Formate PNG und JPG.

Mein Code stammt aus einer Klasse, die für meine Verwendung entwickelt wurde. Sie können ihn gemäß Ihren Anforderungen bearbeiten.

Bitte überprüfen Sie diese Funktionen / Methoden mit 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);
  }

Verwenden des PHP-Codes:

      $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

Nun diese Funktionen / Methode mit 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));
  }

Verwenden des Java-Codes:

        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]
joseluisbz
quelle
Ich sehe, dass Sie Arrays für Argumente als Hack verwenden, um ref/ outParameter in Java abzurufen - wird dies als Best Practice angesehen?
Dai
Diese Antwort ist sehr alt, jetzt bin ich nicht bereit zu aktualisieren (ich vergesse viele Dinge und ich habe keine Zeit), aber Sie können den Code überprüfen und bearbeiten.
Joseluisbz
joseluisbz.wordpress.com/2013/07/26/… (Erklärung für WMF)
joseluisbz
In diesem Beispiel empfehle ich, eine neue Klasse mit den drei Feldern Format, High und Width zu implementieren und eine Instanz dieser Klasse zurückzugeben.
Joseluisbz
1

Es sind die Pixelabmessungen, die Sie wollen (Breite und Höhe), nehme ich an?

Ich würde denken, dass die meisten Dateiformate einige Header-Informationen enthalten, die die Abmessungen definieren, sodass die Software, die die Datei liest, wissen kann, wie viel Platz sie reservieren muss, bevor sie mit dem Lesen der Datei beginnt. Einige Dateiformate vom Typ "roh" sind möglicherweise nur ein Bytestrom mit einem Byte am Zeilenende am Ende jeder horizontalen Pixelreihe (in diesem Fall muss die Software die erste Zeile lesen und die Größe des Bytestreams teilen durch die Linienlänge, um die Höhe zu erhalten).

Ich glaube nicht, dass Sie dies auf "generische" Weise tun können, da Sie das Dateiformat verstehen müssen (oder natürlich eine Bibliothek verwenden müssen), um zu wissen, wie man es liest. Sie können wahrscheinlich einen Code finden, der in den meisten Fällen eine grobe Schätzung der Abmessungen liefert, ohne die gesamte Datei zu lesen, aber ich denke, bei einigen Dateitypen müssen Sie möglicherweise die gesamte Datei lesen, um sicherzugehen, welche Abmessungen sie tatsächlich hat. Ich gehe davon aus, dass die meisten webzentrierten Bildformate einen Header mit solchen Informationen haben, damit der Browser die Boxabmessungen erstellen kann, bevor das gesamte Bild geladen wird.

Ich würde vermuten, dass eine gute Bibliothek einige Methoden hat, um die Abmessungen der Dateien zu ermitteln, die sie verarbeitet, und dass diese Methoden so effizient wie möglich implementiert werden.

Update : imageinfo scheint zu tun, was Sie wollen. (Habe es nicht getestet)

Stein G. Strindhaug
quelle
Das Tool funktioniert so schnell wie ich es brauche;). Ich werde sehen, ob ich es richtig benutzen kann.
dAnjou
0

Wenn die Bilder EXIF-Informationen enthalten, können Sie einfach den EXIF-Header lesen.

Georgi
quelle
Leider weiß ich nicht, welche Art von Bildern es geben wird und ob sie EXIF-Daten enthalten.
dAnjou
3
Wie viele Ihrer Bilder DO haben diese Informationen? Wenn 90% von ihnen EXIF-Daten haben, ist die Langsamkeit der Verwendung von ImageMagick auf den anderen 10% möglicherweise akzeptabel.
Andy Lester
Warum hat diese Antwort negative Stimmen? Es ist eine gültige Antwort auf die Frage und kann genau das sein, wonach das OP oder jemand anderes sucht.
Will Sheppard
0

-ping ist eine Option, die anscheinend zu diesem Zweck eingeführt wurde.

Ab ImageMagick 6.7.7 beobachte ich jedoch nicht einmal bei allen großen Dateien eine Verlangsamung, z.

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

Können Sie ein Beispiel für ein Eingabebild erstellen, für das es noch langsam ist?

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
quelle
0

tldr: Datei "Bildname" reicht aus

funktioniert mit webp, allen jpg-Formaten (jpeg, jpg200, ..),

Die Beispielausgabe sieht so aus

JPEG-Bilddaten, JFIF-Standard 1.02, Seitenverhältnis, Dichte 1x1, Segmentlänge 16, Grundlinie, Genauigkeit 8, 650x400, Frames 3

Laden Sie die Ausgabe der Datei in eine Python-Liste und verwenden Sie das 4. Feld in der Liste.

Zu Ihrer Information, hat mehr als 18000 Bilder optimiert, um den Netzwerkverkehr zu reduzieren.

mj-ek
quelle