Bash: la forma más rápida de determinar las dimensiones de la imagen desde la URL


8

Estoy tratando de encontrar un método realmente rápido para determinar las dimensiones de una imagen.

Sé que podría mover la imagen y luego usar imagemagick para determinar la altura y el ancho de la imagen. Me preocupa que esta no sea la forma más rápida de hacerlo.

También me preocupa tener que instalar imagemagick cuando solo necesito un subconjunto muy pequeño de funcionalidad. Estoy en un sistema integrado que tiene recursos muy limitados (CPU, RAM, almacenamiento).

¿Algunas ideas?


¿Qué tipos de imágenes necesitas admitir?
Gilles 'SO- deja de ser malvado'

Respuestas:


13

Como observa, no necesita todo el paquete ImageMagick . Sólo se necesita identify.

También necesitará las bibliotecas a las que se vincula el ejecutable (y las bibliotecas a las que se vinculan esas bibliotecas).

> whereis identify
identify: /bin/identify /usr/bin/identify /usr/share/man/man1/identify.1.gz
> ldd /bin/identify

lddmostrará una lista Cuando hice esto, incluía algunas bibliotecas X, libjpeg, etc. y dos bibliotecas claramente del paquete ImageMagick, libMagickCorey libMagickWand. Esos parecen estar vinculados al mismo grupo de cosas, así que si tienes eso, identifydebería funcionar.

No tiene que descargar una imagen completa para obtener las dimensiones, ya que están en un encabezado al comienzo del archivo y eso es lo que se identifyve. Por ejemplo, aquí estoy copiando los primeros 4 kB de un archivo JPEG completo en un nuevo archivo:

dd if=real.jpg of=test.jpg bs=1024 count=4

4 kB deberían ser más que suficientes para incluir el encabezado; estoy seguro de que podría hacerlo con 1/4 de esa cantidad. Ahora:

>identify test.jpg 
test.jpg JPEG 893x558 893x558+0+0 8-bit DirectClass 4.1KB 0.000u 0:00.000

Esas son las dimensiones correctas para real.jpg. Sin embargo, tenga en cuenta que el tamaño (4.1 KB) es el tamaño del archivo truncado, ya que esa información no proviene del encabezado de la imagen.

Entonces: solo tiene que descargar el primer kilobyte de cada imagen.


12

Puede usar curlpara descargar partes de la imagen. Todo depende de cuán robusto tenga que ser. Un caso de prueba podría ser los primeros 500 bytes. Parece funcionar por mucho tiempo pngy jpgluego usar identifyo algo similar para verificar el tamaño.

curl -o 500-peek -r0-500 "http://example.net/some-image.png"

Editar:


Hace mucho tiempo que escribí analizadores de imágenes, pero lo pensé y refresqué parte de mi memoria.

Sospecho que es todo tipo de imágenes que desea verificar (pero, de nuevo, tal vez no). Voy a describir algunos de los más comunes: PNG, JPEG (JFIF) y GIF.


PNG:

Estos son simples cuando se trata de extracción de tamaño. Un pngencabezado almacena el tamaño dentro de los primeros 24 bytes. Primero viene un encabezado fijo:

byte  value  description
   0  0x89   Bit-check. 0x89 has bit 7 set.
 1-3  PNG    The letters P,N and G
 4-5  \r\n   Newline check.
   6    ^z   MS-DOS won't print data beyond this using `print`
   7    \n   *nix newline.

Luego viene fragmentos a través del archivo. Consisten en un campo fijo de longitud, tipo y suma de verificación. Además, una sección de datos opcional de tamaño de longitud .

Afortunadamente, el primer fragmento siempre es un IHDRcon este diseño:

byte  description
0-3   Image Width
4-7   Image Height
  8   Bits per sample or per palette index
...   ...

Por esto tenemos que los tamaños son byte 16-20 y 21-24. Puede volcar los datos, por ejemplo, hexdump:

hexdump -vn29 -e '"Bit-test: " /1 "%02x" "\n" "Magic   : " 3/1 "%_c" "\n" "DOS-EOL : " 2/1 "%02x" "\n" "DOS-EOF : " /1 "%02x" "\n" "NIX-EOL : " /1 "%02x" "\n" "Chunk Size: " 4/1 "%02u" "\n" "Chunk-type: " 4/1 "%_c" "\n" "Img-Width : " 4/1 "%02x" "\n" "Img-Height: " 4/1 "%02x" "\n" /1 "Depth : %u bit" "\n" /1 "Color : %u" "\n" /1 "Compr.: %u" "\n" /1 "Filter: %u" "\n" /1 "Interl: %u" "\n"' sample.png

En una máquina Big Endian / Motorola, también se pueden imprimir los tamaños directamente:

hexdump -s16 -n8 -e '1/4 "%u" "\n"' sample.png

Sin embargo, en Little Endian / Intel, no es tan fácil y tampoco es muy portátil.

Con esto, podríamos implementar un script bash + hexdump como en:

png_hex='16/1 "%02x" " " 4/1 "%02x" " " 4/1 "%02x" "\n"'
png_valid="89504e470d0a1a0a0000000d49484452"

function png_wh()
{
    read -r chunk1 img_w img_h<<<$(hexdump -vn24 -e "$png_hex" "$1")
    if [[ "$chunk1" != "$png_valid" ]]; then
        printf "Not valid PNG: \`%s'\n" "$1" >&2
        return 1
    fi
    printf "%10ux%-10u\t%s\n" "0x$img_w" "0x$img_h" "$1"
    return 0
}

if [[ "$1" == "-v" ]]; then verbose=1; shift; fi

while [[ "$1" ]]; do png_wh "$1"; shift; done

Pero, esto no es directamente eficiente. Aunque requiere una porción mayor (75-100 bytes), identifyes bastante más rápido. O escriba la rutina en, por ejemplo, C, que sería más rápido que las llamadas a la biblioteca.


JPEG:

Cuando se trata de jpgeso, no es tan fácil. También comienza con un encabezado de firma , pero el tamaño del fragmento no está en un desplazamiento fijo. Después del encabezado:

 byte  value
 0-1   ffd8          SOI (Start Of Image)
 2-3   ffe0          JFIF marker
 4-5   <block-size>  Size of this block including this number
 6-10  JFIF\0        ...
11-12  <version>
   13  ...

aparece un nuevo bloque especificado por un marcador de dos bytes que comienza con 0xff . El que contiene información sobre las dimensiones tiene el valor, 0xffc0pero puede ocultarse un poco por debajo de los datos.

En otras palabras, omitir bytes de tamaño de bloque , marcar marcador, omitir bytes de tamaño de bloque , leer marcador, etc. hasta que aparezca el correcto.

Cuando se encuentran, los tamaños se almacenan en dos bytes cada uno en el desplazamiento 3 y 5 después del marcador .

 0-1   ffc0          SOF marker
 2-3   <block-size>  Size of this block including this number
   4   <bits>        Sample precision.
 5-6   <Y-size>      Height
 7-8   <X-size>      Width
   9   <components>  Three for color baseline, one for grayscale.

Escribió un programa en C simple para verificar algunos archivos y de aproximadamente 10,000 imágenes jpg, aproximadamente el 50% tenía la información de tamaño dentro de los primeros 500 bytes, principalmente el 50% entre ca. 100 y 200. Lo peor fue alrededor de 80,000 bytes. Una foto, mientras hablamos fotos:

JFIF_SOF_graph


GIF:

Aunque el GIF generalmente puede tener múltiples imágenes almacenadas, tiene un tamaño de lienzo especificado en el encabezado, esto es lo suficientemente grande como para albergar las imágenes. Es tan fácil como con PNG , y requiere incluso bytes de fiebre: 10. Después de la magia y la versión, encontramos tamaños. Ejemplo de una imagen de 364x472:

<byte>  <hex>   <value>
  0-2   474946  GIF  Magic
  3-5   383961  89a  Version (87a or 89a)
  6-7   6c01    364  Logical Screen Width
  8-9   d801    472  Logical Screen Height

En otras palabras, puede verificar los primeros seis bytes para ver si es un gif, luego leer los siguientes cuatro para ver los tamaños.


Otros formatos:

Podría haber continuado, pero supongo que me detengo aquí por ahora.


1

Asume que tienes "identificar". Pon esto en un guión y chmod +x <scriptname>. Para ejecutarlo, escriba <scriptname> picture.jpgy obtendrá el alto y el ancho de la imagen. Las primeras 2 secciones son para verificar si hay una imagen y luego configurarla como la variable IMAGEN. La siguiente sección es asegurarse de que el archivo esté realmente allí. Las últimas 2 secciones son para tomar la información relevante de la salida 'identificar' y mostrarla.

#!/bin/bash
if [[ "${#}" -ne "1" ]]
then
die "Usage: $0 <image>"
fi

IMAGE="${1}"

if [[ ! -f "${IMAGE}" ]]
then
die "File not found: ${IMAGE}"
fi

IMG_CHARS=`identify "$1" | cut -f 3 -d' '`
WIDTH=`echo $IMG_CHARS | cut -d'x' -f 1`
HEIGHT=`echo $IMG_CHARS | cut -d'x' -f 2`

echo -e "W: ${WIDTH} H: ${HEIGHT}"

Buen guión. sin embargo, sería bueno si pudieras explicar lo que hace (ya que Stack Exchange se trata de aprender).
Strugee

0
mohsen@debian:~/codes/amlak/amlak/src$ file ~/Screenshot\ from\ 2013-07-10\ 01\:25\:34.png 
/home/mohsen/Screenshot from 2013-07-10 01:25:34.png: PNG image data, 1366 x 768, 8-bit/color RGB, non-interlaced

file command se instala por defecto en los distorsores y solo depende de:

Depends: libc6 (>= 2.4), libmagic1 (= 1:5.14-2), zlib1g (>= 1:1.1.4)

Creo que puedes instalarlo fácilmente para incrustarlo. Simplemente escribe un regular expressionpara su salida.


2
fileno da dimensiones para, por ejemplo, .jpgarchivos.
Ricitos de oro

0
mohsen@debian:~/codes/amlak/amlak/src$ php -r "print_r(getimagesize('file:///archives/Picture/12 farvardin/20120331_013.jpg'));"
Array
(
    [0] => 2560
    [1] => 1440
    [2] => 2
    [3] => width="2560" height="1440"
    [bits] => 8
    [channels] => 3
    [mime] => image/jpeg
)
mohsen@debian:~/codes/amlak/amlak/src$ php -r "print_r(getimagesize('file:///archives/Picture/12 farvardin/20120331_013.jpg'));" |egrep w
    [3] => width="2560" height="1440"
mohsen@debian:~/codes/amlak/amlak/src$ php -r "print_r(getimagesize('file:///archives/Picture/12 farvardin/20120331_013.jpg'));" |egrep w | awk {'print $3'}
width="2560"
mohsen@debian:~/codes/amlak/amlak/src$ php -r "print_r(getimagesize('file:///archives/Picture/12 farvardin/20120331_013.jpg'));" |egrep w | awk {'print $4'}
height="1440"

Reemplazas file://conhttp://


No estoy seguro de que PHP sea adecuado para sistemas integrados de bajos recursos. Además, esto parece recuperar todo el archivo.
Peter

Es un módulo php-cli no php para apache, no necesita apache.
PersianGulf

Aún así, cargará todo el motor PHP, que es un cerdo de memoria. Además, tendría que instalarse una parte razonable de PHP, lo que también podría ser un problema para el sistema integrado (el espacio en disco podría ser limitado). Para un sistema normal, podría ser una opción, aunque necesitaría modificarlo para evitar recuperar toda la imagen (vea la respuesta de Sukminder).
Peter
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.