Bash: il modo più veloce per determinare le dimensioni dell'immagine dall'URL


8

Sto cercando di capire un metodo molto veloce per determinare le dimensioni di un'immagine.

So che potrei wget l'immagine e quindi usare imagemagick per determinare l'altezza e la larghezza dell'immagine. Sono preoccupato che questo potrebbe non essere il modo più veloce di farlo.

Mi preoccupo anche di dover installare imagemagick quando ho solo bisogno di un piccolo sottoinsieme di funzionalità. Sono su un sistema incorporato che ha risorse molto limitate (CPU, RAM, memoria).

Qualche idea?


Quali tipi di immagine devi supportare?
Gilles 'SO- smetti di essere malvagio' il

Risposte:


13

Come nota, non è necessario l'intero pacchetto ImageMagick . Hai solo bisogno identify.

Avrai anche bisogno delle librerie a cui si collegano gli eseguibili (e delle librerie a cui si collegano le librerie).

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

lddmostrerà un elenco. Quando l'ho fatto, includevo alcune librerie X, libjpeg, ecc. E due librerie chiaramente dal pacchetto ImageMagick libMagickCoree libMagickWand. Quelli sembrano essere collegati allo stesso gruppo di cose, quindi se hai quello, identifydovrebbe funzionare.

Non è necessario scaricare un'intera immagine per ottenere le dimensioni, perché queste sono in un'intestazione all'inizio del file e questo è ciò che identifyguarda. Ad esempio, qui sto copiando i primi 4 kB da un jpeg completo in un nuovo file:

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

4 kB dovrebbero essere più che sufficienti per includere l'intestazione: sono sicuro che potresti farlo con 1/4 di tale importo. Adesso:

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

Quelle sono le dimensioni corrette per real.jpg. Si noti, tuttavia, che la dimensione (4,1 KB) è la dimensione del file troncato, poiché tali informazioni non provengono dall'intestazione dell'immagine.

Quindi: devi solo scaricare il primo kilobyte circa di ogni immagine.


12

È possibile utilizzare curlper scaricare parti dell'immagine. Tutto dipende da quanto deve essere robusto. Un caso di test potrebbe essere i primi 500 byte. Sembra funzionare per un sacco di pnge jpg, quindi utilizzare identifyo simili per controllare le dimensioni.

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

Modificare:


Molto tempo da quando ho scritto i parser di immagini, ma ci ho pensato e rinfrescato un po 'della mia memoria.

Sospetto che siano tutti i tipi di immagini che vuoi controllare (ma poi di nuovo, forse no). Descriverò alcuni di quelli più comuni: PNG, JPEG (JFIF) e GIF.


PNG:

Questi sono semplici quando si tratta di estrazione di dimensioni. pngUn'intestazione memorizza la dimensione entro i primi 24 byte. Prima arriva un'intestazione fissa:

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.

Poi arrivano i pezzi attraverso il file. Sono costituiti da un campo fisso di lunghezza, tipo e checksum. Inoltre, una sezione dati opzionale di dimensioni di lunghezza .

Fortunatamente il primo pezzo è sempre un IHDRcon questo layout:

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

Con questo abbiamo che le dimensioni sono byte 16-20 e 21-24. È possibile scaricare i dati ad es. 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

Su una macchina Big Endian / Motorola si possono anche stampare le dimensioni direttamente da:

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

Tuttavia, su Little Endian / Intel, non è così facile, né è molto portatile.

Con questo è possibile implementare uno script bash + hexdump come in:

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

Ma questo non è direttamente efficiente. Sebbene richieda un blocco più grande (75-100 byte), identifyè piuttosto più veloce. Oppure scrivi la routine in es. C, che sarebbe più veloce delle chiamate in libreria.


JPEG:

Quando si tratta di jpgnon è così facile. Comincia anche con un'intestazione della firma , ma il blocco delle dimensioni non ha un offset fisso. Dopo l'intestazione:

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

arriva un nuovo blocco specificato da un marcatore a due byte che inizia con 0xff. Quello che contiene le informazioni sulle dimensioni ha il valore 0xffc0ma può essere sepolto un po 'nei dati.

In altre parole, si salta un byte di dimensione blocco , si seleziona un marker, si salta un byte di dimensione blocco , si legge un marker e così via fino a quando viene visualizzato quello corretto.

Quando viene trovato, le dimensioni vengono memorizzate da due byte ciascuna a offset 3 e 5 dopo il marker .

 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.

Scritto un semplice programma C per controllare alcuni file e di circa 10.000 immagini jpg, circa il 50% aveva le informazioni sulla dimensione entro i primi 500 byte, per lo più il 50% tra ca. 100 e 200. Il peggio era di circa 80.000 byte. Un'immagine, mentre parliamo di immagini:

JFIF_SOF_graph


GIF:

Sebbene in genere gif possa contenere più immagini all'interno, ha una dimensione di tela specificata nell'intestazione, ma è abbastanza grande per ospitare le immagini. È facile come con PNG e richiede anche byte di febbre: 10. Dopo la magia e la versione troviamo le dimensioni. Esempio da un'immagine 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

In altre parole è possibile controllare i primi sei byte per vedere se si tratta di una gif, quindi leggere le quattro successive per le dimensioni.


Altri formati:

Avrebbe potuto continuare, ma suppongo che mi fermerò qui per ora.


1

Presuppone che tu abbia "identificato". Metti questo in una sceneggiatura e chmod +x <scriptname>. Per eseguirlo digita <scriptname> picture.jpge otterrai l'altezza e la larghezza dell'immagine. Le prime 2 sezioni servono per verificare la presenza di un'immagine, quindi impostarla come variabile IMMAGINE. La sezione successiva è assicurarsi che il file sia effettivamente lì. Le ultime 2 sezioni devono prendere le informazioni pertinenti dall'output "identifica" e visualizzarle.

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

bella sceneggiatura. tuttavia, sarebbe bello se tu potessi spiegare cosa fa (poiché Stack Exchange riguarda l'apprendimento).
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 è installato di default su distorsori e dipende solo da:

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

Penso che puoi installarlo facilmente per incorporato. Basta scrivere a regular expressionper il suo output.


2
filenon fornisce le dimensioni, ad esempio, per i .jpgfile.
Riccioli d'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"

Sostituisci file://conhttp://


Non sono sicuro che PHP sia adatto per sistemi embedded con risorse limitate. Inoltre, questo sembra recuperare l'intero file.
peterph,

È php-cli non è un modulo php per apache, non ha bisogno di apache.
Golfo Persico,

Tuttavia caricherà l'intero motore PHP che è un maiale di memoria. Inoltre, dovrebbe essere installata una parte ragionevole di PHP, il che potrebbe rappresentare un problema anche per il sistema incorporato (lo spazio su disco potrebbe essere limitato). Per un sistema normale potrebbe essere un'opzione, anche se dovresti modificarlo per evitare di recuperare l'intera immagine (vedi la risposta di Sukminder).
peterph,
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.