Modo rapido per ottenere dimensioni dell'immagine (non dimensioni file)


138

Sto cercando un modo rapido per ottenere l'altezza e la larghezza di un'immagine in pixel. Dovrebbe gestire almeno JPG, PNG e TIFF, ma tanto meglio è. Sottolineo rapidamente perché le mie immagini sono piuttosto grandi (fino a 250 MB) e ci vuole davvero tanto tempo per ottenere le dimensioni con ImageMagick identifyperché ovviamente legge le immagini nel loro insieme.

Preferibilmente, cerco un modo che funzioni bene in Ruby o anche in Rails 3.

Conosco la teoria (vari formati di immagine, le loro intestazioni e le loro differenze, e così via). Anzi, chiedo un qualche tipo di libreria in grado di risolvere il mio problema in modo abbastanza generico.

Ho appena trovato la dimensione dell'immagine che sembra promettente sebbene lo sviluppo sembri essere morto.


8
Ciò non sembra essere vero per le nuove versioni di ImageMagick. Usando ImageMagick 6.5.4-7 ho confermato che identifica (almeno per TIF e PNG) legge solo l'intestazione (fino a 60 KB) e funziona molto velocemente, anche per immagini da 335 MB.
coderforlife,

Risposte:


195
  • Il filecomando stampa le dimensioni per diversi formati di immagine (ad esempio PNG, GIF, JPEG; versioni recenti anche PPM, WEBP) e legge solo l'intestazione.

  • Il identifycomando (da ImageMagick) stampa molte informazioni sull'immagine per un'ampia varietà di immagini. Sembra trattenersi dalla lettura della porzione di intestazione (vedi commenti). Ha anche un output unificato che filepurtroppo manca.

  • exiv2ti dà dimensioni per molti formati, tra cui JPEG, TIFF, PNG, GIF, WEBP, anche se non è presente alcuna intestazione EXIF. Non è chiaro se legge tutti i dati per quello però. Vedi la manpage di exiv2 per tutti i formati di immagine supportati.

  • head -n1 ti darà le dimensioni per i formati PPM, PGM.

Per i formati popolari sul Web, entrambi exiv2e identifyfaranno il lavoro. A seconda del caso d'uso, potrebbe essere necessario scrivere il proprio script che combina / analizza gli output di diversi strumenti.


3
Ho eseguito alcuni test con il comando identifica ImageMagick, usando strace per registrare chiamate open / read / mmap / close per vedere quanti dati sono stati letti dall'immagine identificata. Dipende dal tipo di file e dalla dimensione del file leggermente, ma stavo ottenendo 20-60 KB letti da "identifica" per immagini da 5-335 MB (ho anche testato contro "converti" che mostrava tutti i byte letti). Quindi sembra che "identificare" sia una buona scelta qui (poiché supporta tutti i formati più diffusi e legge solo l'intestazione).
coderforlife,

1
Penso che exiv2 faccia anche PNG.
chx,

Qualche modo per analizzare facilmente i comandi di quel file? L'identificazione è ottima, ma non funziona tristemente con i file WebP
Brian Leishman,

Identificare fa lavoro con WebP, e ImageMagick ha il supporto per WebP per anni. Forse potresti ricevere un aggiornamento?
ypnos,

32

Non sono sicuro che tu abbia installato PHP, ma questa funzione PHP è molto utile

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

1
Questo è molto più veloce di "identificare". Buon approccio. Grazie.
souravb,

19

È possibile utilizzare la funzione di identificazione di ImageMagick . Ecco come lo fai in bash (Nota $ 0 è il percorso dell'immagine):

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

E questo nasconde anche eventuali potenziali messaggi di errore. Le implementazioni moderne identifyleggono solo l'intestazione, non l'intera immagine, quindi è veloce. Non sono sicuro di come si confronta con altri metodi.


2
Credo che sia molto più efficiente in questo modo:read width height < <(identify -format "%w %h" "${1}")
Cromax

5

https://joseluisbz.wordpress.com/2013/08/06/obtain-size-or-dimension-of-images/ (BMP, PNG, GIF, JPG, TIF o WMF)

Qui per due formati PNG e JPG.

Il mio codice proviene da una classe progettata per il mio uso, è possibile modificare in base alle proprie esigenze.

Si prega di controllare queste funzioni / metodi usando 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);
  }

Utilizzando il codice 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

Ora queste funzioni / metodi usando 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));
  }

Utilizzando il codice 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]

Vedo che stai usando le matrici per argomenti come un hack per ottenere ref/ outparametri in Java - è considerata una buona pratica?
Dai,

Questa risposta è molto vecchia, ora non sono disposto ad aggiornare (ho dimenticato molte cose e non ho tempo), ma puoi controllare il codice e modificarlo.
joseluisbz,


Per questo esempio, consiglio di implementare una nuova classe con 3 campi, Format, High e Width, restituendo un'istanza di questa classe.
joseluisbz,

1

Sono le dimensioni in pixel che desideri (larghezza e altezza), suppongo?

Penso che la maggior parte dei formati di file abbia alcune informazioni di intestazione che definiscono le dimensioni, in modo che il software che legge il file possa sapere quanto spazio deve riservare prima di iniziare a leggere il file. Alcuni formati di file di tipo "raw" potrebbero essere solo un flusso di byte con qualche byte di "fine riga" alla fine di ogni riga orizzontale di pixel (nel qual caso il software deve leggere la prima riga e dividere la dimensione del flusso di byte dalla lunghezza della linea per ottenere l'altezza).

Non penso che tu possa farlo in alcun modo "generico", dato che devi capire il formato del file (o usare una libreria ovviamente) per sapere come leggerlo. Probabilmente puoi trovare del codice che nella maggior parte dei casi fornirà una stima approssimativa delle dimensioni senza leggere l'intero file, ma penso che alcuni tipi di file potrebbero richiedere di leggere l'intero file per essere sicuro di quali dimensioni abbia realmente. Mi aspetto che la maggior parte dei formati di immagine incentrati sul web abbia un'intestazione con tali informazioni in modo che il browser possa creare le dimensioni della scatola prima che venga caricata l'intera immagine.

Immagino che una buona libreria avrebbe alcuni metodi per ottenere le dimensioni dei file che gestisce e che questi metodi sarebbero implementati nel modo più efficiente possibile.

Aggiornamento : imageinfo sembra fare quello che vuoi. (Non l'ho provato)


Quello strumento funziona tanto velocemente quanto mi serve;). Vedrò se posso usarlo correttamente.
dAnjou,

0

Se hai informazioni EXIF ​​nelle immagini, puoi semplicemente leggere l'intestazione EXIF.


Sfortunatamente non so che tipo di immagini ci saranno e se hanno dati EXIF.
dAnjou,

3
Quante delle tue immagini contengono tali informazioni? Forse se il 90% di loro ha dati EXIF, la lentezza dell'uso di ImageMagick sull'altro 10% sarà accettabile.
Andy Lester,

Perché questa risposta ha dei voti negativi? È una risposta valida alla domanda e potrebbe essere esattamente ciò che l'OP o qualcun altro sta cercando.
Will Sheppard,

0

-ping è un'opzione che sembra aver introdotto a tale scopo.

Tuttavia a partire da ImageMagick 6.7.7 non osservo rallentamenti nemmeno per tutti i file di grandi dimensioni, ad esempio:

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

Potete produrre un'immagine di input di esempio per la quale è ancora lenta?


0

tldr: il file "imagename" lo farà

funziona con webp, tutti i formati jpg (jpeg, jpg200, ..),

Sembra un output di esempio

Dati immagine JPEG, standard JFIF 1.02, rapporto d'aspetto, densità 1x1, lunghezza segmento 16, linea base, precisione 8, 650x400, fotogrammi 3

carica l'output del file in un elenco Python e usa il 4 ° campo dell'elenco.

Cordiali saluti, ha ottimizzato circa 18000 immagini per ridurre il traffico di rete.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.