2011-01-12 12 views
99

Estoy buscando manera rápida para obtener el alto y el ancho de una imagen en píxeles. Debe manejar al menos JPG, PNG y TIFF, pero cuanto más, mejor. Hago hincapié en rápido porque mis imágenes son bastante grandes (hasta 250 MB) y toma mucho tiempo para obtener el tamaño con identify de ImageMagick porque obviamente lee primero las imágenes como un todo.Forma rápida de obtener las dimensiones de la imagen (sin tamaño de archivo)

Preferiblemente, busco una manera que funcione bien en Ruby, o incluso en Rails 3.

Sé que las cosas teoría (varios formatos de imagen, sus cabeceras y sus diferencias, y así sucesivamente). De hecho, solicito algún tipo de biblioteca que pueda resolver mi problema de una manera bastante genérica.

Acabo de encontrar http://imagesize.rubyforge.org que parece prometedor aunque el desarrollo parece estar muerto.

+7

Esto no parece ser cierto para las nuevas versiones de ImageMagick. Uso de ImageMagick 6.5.4-7 He confirmado que la identificación (al menos para TIF y PNG) solo lee el encabezado (hasta 60 KB) y funciona muy rápido, incluso para imágenes de 335 MB. – coderforlife

Respuesta

0

Si tiene información EXIF ​​en las imágenes, puede leer el encabezado EXIF.

+0

Lamentablemente, no sé qué tipo de imágenes habrá y si tienen datos EXIF. – dAnjou

+3

¿Cuántas de sus imágenes * HACEN * tienen esa información? Quizás si el 90% de ellos tienen datos EXIF, entonces la lentitud de usar ImageMagick en el otro 10% será aceptable. –

+0

¿Por qué esta respuesta tiene downvotes? Es una respuesta válida a la pregunta y puede ser exactamente lo que el OP o alguien más está buscando. –

25

Yo no estoy seguro de haber instalado PHP, pero esta función PHP es bastante práctico

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

Esto es mucho más rápido que "identificar". Buen enfoque. Gracias. – souravb

1

Es las dimensiones en píxeles que desee (anchura y altura), supongo?

Creo que la mayoría de los formatos de archivo tienen información de encabezado que define las dimensiones, de modo que el software que lee el archivo puede saber cuánto espacio debe reservar antes de comenzar a leer el archivo. Algunos formatos de archivos "en bruto" pueden ser simplemente una secuencia de bytes con un byte "final de línea" al final de cada fila horizontal de píxeles (en cuyo caso el software debe leer la primera línea y dividir el tamaño de la secuencia de bytes) por la longitud de la línea para obtener la altura).

No creo que pueda hacer esto de una manera "genérica", ya que necesita comprender el formato de archivo (o utilizar una biblioteca por supuesto) para saber cómo leerlo. Probablemente pueda encontrar algún código que en la mayoría de los casos proporcione una estimación aproximada de las dimensiones sin leer todo el archivo, pero creo que algunos tipos de archivos pueden requerir que lea todo el archivo para asegurarse de qué dimensiones realmente tiene. Espero que la mayoría de los formatos de imagen centrados en web tengan un encabezado con dicha información para que el navegador pueda crear las dimensiones del cuadro antes de que se cargue la imagen completa.

Supongo que una buena biblioteca tendrá algunos métodos para obtener las dimensiones de los archivos que maneja, y que esos métodos se implementarán de la manera más eficiente posible.

Actualización: imageinfo parece que hace lo que usted quiere. (No lo he probado)

+0

Esa herramienta funciona tan rápido como lo necesito;). Veré si puedo usarlo correctamente. – dAnjou

146
  • El comando imprime file las dimensiones para varios formatos de imagen (por ejemplo, PNG, GIF y JPEG, pero no PPM), y que sólo se puede leer el encabezado.

  • exiv2 le da dimensiones JPEG y TIFF, incluso si no hay encabezado EXIF ​​presente. Sin embargo, no está claro si se lee toda la información para eso.

  • head -n1 le dará las dimensiones de los formatos PPM, PGM.

  • El comando identify (de ImageMagick) imprime mucha información de imagen para una amplia variedad de imágenes.Parece limitarse a leer la parte del encabezado (ver comentarios).

Creo que se necesita para escribir su propio guión que combina/análisis sintáctico de estas salidas ...

+2

He realizado algunas pruebas con el comando de identificación de ImageMagick, utilizando strace para grabar las llamadas de abrir/leer/mmap/cerrar para ver la cantidad de datos que se han leído de la imagen identificada. Depende del tipo de archivo y del tamaño del archivo, pero obtuve 20-60 KB de "identificación" para imágenes de 5-335 MB (también probé contra "convertir", que mostraba todos los bytes que se leían). Así que parece que "identificar" es una buena opción aquí (ya que admite todos los formatos populares y solo lee el encabezado). – coderforlife

+1

Creo que exiv2 también hace PNG. – chx

4

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

aquí por dos formatos PNG y JPG.

Mi código es de una clase diseñada para mi uso, puede editar según lo necesite.

Por favor marque estas funciones/método que utiliza 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); 
    } 

Utilización del código 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 

Ahora bien, estas funciones/método que utiliza 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)); 
    } 

Uso g el código 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] 
+1

por favor evite publicar el código en español. –

+0

Veo que está usando matrices para argumentos como un truco para obtener los parámetros 'ref' /' out' en Java, ¿se considera una práctica óptima? – Dai

+0

Esta respuesta es muy antigua, ahora no estoy dispuesto a actualizar (me olvido de muchas cosas y no tengo tiempo), pero puede verificar el código y editarlo. –

0

-ping es una opción que parece tener introducir para ese propósito.

Sin embargo, como ImageMagick 6.7.7 yo no observo desaceleración incluso para cada archivos de gran tamaño, por ejemplo .:

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 

¿Se puede producir una imagen de ejemplo de entrada para el que todavía es lento?

6

Puede utilizar la función identify de ImageMagick. He aquí cómo lo haces en bash (Nota $ 0 es el camino de la imagen):

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

Y esto también se esconde algún mensaje de error potenciales. Las implementaciones modernas de identify solo leen el encabezado, no toda la imagen, por lo que es rápido. Sin embargo, no estoy seguro de cómo se compara con otros métodos.

Cuestiones relacionadas