Bash: moyen le plus rapide de déterminer les dimensions de l'image à partir d'une URL


8

J'essaie de trouver une méthode très rapide pour déterminer les dimensions d'une image.

Je sais que je pourrais mouiller l'image, puis utiliser imagemagick pour déterminer la hauteur et la largeur de l'image. Je crains que ce ne soit pas le moyen le plus rapide de le faire.

Je souhaite également installer imagemagick lorsque je n'ai besoin que d'un très petit sous-ensemble de fonctionnalités. Je suis sur un système embarqué aux ressources très limitées (CPU, RAM, stockage).

Des idées?


Quels types d'images devez-vous prendre en charge?
Gilles 'SO- arrête d'être méchant'

Réponses:


13

Comme vous le constatez, vous n'avez pas besoin de l'ensemble du package ImageMagick . Vous avez juste besoin identify.

Vous aurez également besoin des bibliothèques auxquelles les liens exécutables (et des bibliothèques vers lesquelles ces bibliothèques sont liées).

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

lddaffichera une liste. Quand j'ai fait cela, il comprenait quelques librairies X, libjpeg, etc. et deux bibliothèques clairement du paquet ImageMagick, libMagickCoreet libMagickWand. Ceux-ci semblent être liés au même groupe de choses, donc si vous en avez, cela identifydevrait fonctionner.

Vous n'avez pas besoin de télécharger une image entière pour obtenir les dimensions, car celles-ci sont dans un en-tête au début du fichier et c'est ce qui identifyse passe. Par exemple, ici, je copie les 4 premiers Ko d'un fichier jpeg complet dans un nouveau fichier:

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

4 Ko devraient être plus que suffisants pour inclure l'en-tête - je suis sûr que vous pourriez le faire avec 1/4 de cette quantité. Maintenant:

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

Ce sont les bonnes dimensions pour real.jpg. Notez cependant que la taille (4,1 Ko) est la taille du fichier tronqué, car ces informations ne proviennent pas de l'en-tête de l'image.

Donc: vous n'avez qu'à télécharger le premier kilo-octet environ de chaque image.


12

Vous pouvez utiliser curlpour télécharger des parties de l'image. Tout dépend de sa robustesse. Un cas de test pourrait être de 500 premiers octets. Semble travail pour beaucoup de pnget jpg, puis utilisez identifyou similaire pour vérifier la taille.

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

Éditer:


Il y a longtemps que j'ai écrit des analyseurs d'images, mais j'ai réfléchi et rafraîchi une partie de ma mémoire.

Je soupçonne que ce sont toutes sortes d'images que vous souhaitez vérifier (mais encore une fois, peut-être pas). Je vais vous décrire quelques - unes des plus courantes: PNG, JPEG (JFIF) et GIF.


PNG:

Celles-ci sont simples en matière d'extraction de taille. Un en- pngtête stocke la taille dans les 24 premiers octets. Vient d'abord un en-tête fixe:

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.

Viennent ensuite des morceaux à travers le fichier. Ils se composent d'un champ fixe de longueur, de type et de somme de contrôle. En outre, une section de données facultative de taille de longueur .

Heureusement, le premier morceau est toujours un IHDRavec cette disposition:

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

Par cela, nous avons que les tailles sont octets 16-20 et 21-24. Vous pouvez vider les données par exemple 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

Sur une machine Big Endian / Motorola, on pourrait également imprimer les tailles directement en:

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

Cependant, sur Little Endian / Intel, ce n'est pas si simple, et ce n'est pas très portable.

Par cela, nous pourrions implémenter un script bash + hexdump comme dans:

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

Mais ce n'est pas directement efficace. Bien qu'il nécessite un plus gros morceau (75-100 octets), il identifyest plutôt plus rapide. Ou écrivez la routine par exemple en C, ce qui serait plus rapide que les appels de bibliothèque.


JPEG:

En ce qui concerne jpgce n'est pas si simple. Il commence également par un en- tête de signature , mais le bloc de taille n'est pas à un décalage fixe. Après l'en-tête:

 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  ...

un nouveau bloc vient spécifié par un marqueur de deux octets commençant par 0xff. Celui qui contient des informations sur les dimensions a la valeur 0xffc0mais peut être enterré un peu dans les données.

En d'autres termes, on saute les octets de taille de bloc , vérifie le marqueur, saute les octets de taille de bloc , lit le marqueur, et ainsi de suite jusqu'à ce que le bon arrive.

Lorsqu'elles sont trouvées, les tailles sont stockées sur deux octets chacune aux décalages 3 et 5 après le marqueur .

 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.

A écrit un programme C simple pour vérifier certains fichiers et environ 10 000 images jpg, environ 50% avaient les informations de taille dans les 500 premiers octets, principalement 50% entre env. 100 et 200. Le pire était d'environ 80 000 octets. Une image, comme on parle d'images:

JFIF_SOF_graph


GIF:

Bien que gif puisse généralement avoir plusieurs images stockées, il a une taille de toile spécifiée dans l'en-tête, c'est assez grand pour héberger les images. C'est aussi simple qu'avec PNG , et nécessite même des octets de fièvre: 10. Après la magie et la version, nous trouvons des tailles. Exemple à partir d'une image 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 d'autres termes, vous pouvez vérifier les six premiers octets pour voir s'il s'agit d'un gif, puis lire les quatre suivants pour les tailles.


Autres formats:

Aurait pu continuer, mais je suppose que je m'arrête ici pour l'instant.


1

Suppose que vous avez "identifier". Mettez cela dans un script et chmod +x <scriptname>. Pour l'exécuter, tapez <scriptname> picture.jpget vous obtiendrez la hauteur et la largeur de l'image. Les 2 premières sections consistent à vérifier s'il y a une image puis à la définir comme variable IMAGE. La section suivante consiste à s'assurer que le fichier est bien là. Les 2 dernières sections doivent extraire les informations pertinentes de la sortie «identifier» et les afficher.

#!/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}"

joli script. cependant, ce serait bien si vous pouviez expliquer ce qu'il fait (puisque Stack Exchange concerne l'apprentissage).
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 est installé par défaut sur les distors et ne dépend que de:

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

Je pense que vous pouvez l'installer facilement pour embarqué. Vous écrivez juste un regular expressionpour sa sortie.


2
filene donne pas de dimensions pour, par exemple, les .jpgfichiers.
goldilocks

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"

Vous remplacez file://parhttp://


Je ne suis pas sûr que PHP soit bien adapté à des systèmes embarqués à faibles ressources. De plus, cela semble récupérer tout le fichier.
peterph

C'est php-cli pas un module php pour apache, il n'a pas besoin d'apache.
PersianGulf

Néanmoins, il chargera tout le moteur PHP, qui est un porc de mémoire. De plus, une partie raisonnable de PHP devrait être installée, ce qui pourrait également être un problème pour le système intégré (l'espace disque pourrait être limité). Pour un système normal, cela pourrait être une option, bien que vous deviez le modifier pour éviter de récupérer l'image entière (voir la réponse de Sukminder).
peterph
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.