Come verificare se un file è un file immagine valido?


105

Attualmente sto usando PIL.

from PIL import Image
try:
    im=Image.open(filename)
    # do stuff
except IOError:
    # filename not an image file

Tuttavia, sebbene questo copra sufficientemente la maggior parte dei casi, alcuni file di immagine come xcf, svg e psd non vengono rilevati. I file Psd generano un'eccezione OverflowError.

C'è un modo per includerli anche io?


21
Non è una pratica particolarmente comune chiudere i duplicati in lingue diverse. Se non riesci a trovare altre domande su Python con questo, lascialo aperto in quanto potrebbero esserci soluzioni specifiche per Python che le persone vogliono pubblicare che non sono arrivate alla domanda che hai pubblicato.
Paolo Bergantino

sì, prima di tutto speravo davvero in una libreria Python di cui non sapevo: P e poi, come ben ha sottolineato, solo i numeri magici non convalidano l'intera immagine.
Sujoy

@Sujoy, la convalida di un'intera immagine è quasi impossibile, a meno che tu non ne abbia già una copia, perché il computer non è in grado di distinguere tra un pixel di colore corretto e un set confuso di 1 e 0, purché tutto il controllo (numeri magici) sono corretti.
DevinB

@devinb, d'accordo, mi limiterò a prendere i numeri magici e finirò con esso a meno che qualcun altro non
tiri

xcf e psd non sono realmente immagini, sono file di progetto che contengono (spesso molte) immagini ... tuttavia potresti probabilmente creare un caso per svg.
mgalgs

Risposte:


11

Molte volte i primi due caratteri saranno un numero magico per vari formati di file. Puoi verificarlo in aggiunta al controllo delle eccezioni sopra.


10
Ciò non sarà sufficiente se sta davvero testando immagini "valide"; la presenza di un numero magico non garantisce che il file non sia stato troncato, ad esempio.
Ben Blank

1
ottimo consiglio, ora devo solo capire quali sono quei numeri. grazie :)
Sujoy

@ben, ahi non ci avevo ancora pensato. questo è davvero un buon punto
Sujoy

@ Ben, come ti aspetti che una libreria deduca che un file è stato troncato?
DevinB

6
@ Ben Blank: Vero, ma risolvere un problema al 99% è spesso meglio che non risolverlo affatto.
Brian R. Bondy

206

Ho appena trovato il modulo imghdr integrato. Dalla documentazione di Python:

Il modulo imghdr determina il tipo di immagine contenuta in un file o flusso di byte.

È così che funziona:

>>> import imghdr
>>> imghdr.what('/tmp/bass')
'gif'

Usare un modulo è molto meglio che reimplementare funzionalità simili


2
sì, imghdr funziona per la maggior parte dei formati di immagine ma non per tutti. secondo il mio problema originale con i file svg, xcf e psd, anche quelli non vengono rilevati in imghdr
Sujoy

2
La tua risposta è effettivamente migliore, grazie. Come qualcuno ha detto sopra ... ma risolvere un problema al 99% del modo è spesso meglio che non risolverlo affatto ..
RinkyPinku

2
Degno di nota: imghdr.what(path)restituisce Nonese specificato pathnon è il tipo di file immagine riconosciuto. Elenco dei tipi attualmente riconosciuti immagine: rgb , GIF , PBM , PGM , ppm , TIFF , RAST , xbm , jpeg , bmp , png , webp , exr .
patryk.beza

1
Stai attento! Un hdr valido non significa un'immagine valida (es. I byte dell'immagine potrebbero essere stati codificati!)
Filippo Mazza

1
Secondo il commento di @FilippoMazza, posso confermare che una cattiva immagine che è stata tagliata durante il trasferimento può superare questo test, ma si romperà quando PIL proverà a leggerla.
kevinmicke

47

Oltre a quello che suggerisce Brian, potresti usare il metodo di verifica di PIL per controllare se il file è danneggiato.

im.verify ()

Tenta di determinare se il file è danneggiato, senza effettivamente decodificare i dati dell'immagine. Se questo metodo rileva dei problemi, solleva le eccezioni appropriate. Questo metodo funziona solo su un'immagine appena aperta; se l'immagine è già stata caricata, il risultato non è definito. Inoltre, se è necessario caricare l'immagine dopo aver utilizzato questo metodo, è necessario riaprire il file immagine. attributi


beh, il problema principale è che i file svg, xcf e psd non possono essere aperti con Image.open () quindi, nessuna possibilità di verificare con im.verify ()
Sujoy

16
Mio dio, la documentazione del PIL è terribile. Che cos'è esattamente una "eccezione adeguata"?
Timmmm

Ecco il collegamento alla documentazione di Pillow per Image.verify () . Sfortunatamente, non è migliore e sembra che abbiano appena sollevato il paragrafo sopra senza aggiungere nulla.
Two-Bit Alchemist

Ho visto verificare sollevare SyntaxError per file png corrotti
Carl

c'è un modo per verificare "CON la decodifica effettiva dei dati dell'immagine"?
Trevor Boyd Smith,

7

Oltre al PILcontrollo dell'immagine puoi anche aggiungere il controllo dell'estensione del nome file in questo modo:

filename.lower().endswith(('.png', '.jpg', '.jpeg', '.tiff', '.bmp', '.gif'))

Nota che questo controlla solo se il nome del file ha un'estensione immagine valida, in realtà non apre l'immagine per vedere se è un'immagine valida, ecco perché è necessario utilizzare in aggiunta PILo una delle librerie suggerite nelle altre risposte.


Cosa succede se le estensioni non sono corrette nei file? Ad esempio, un file di testo viene salvato con estensione .jpg o viceversa.
hafiz031

1
@ hafiz031 Per ottenere il formato effettivo puoi farlo from PIL import Image img = Image.open(filename) print(img.format)e quindi controllarlo in questo modo:img.format.lower() in ['png', 'jpg', 'jpeg', 'tiff', 'bmp', 'gif']
tsveti_iko

Purtroppo questo non ha funzionato per me. Identifica ancora un'immagine danneggiata come immagine JPEG. Finalmente sono riuscito a gestire questo caso in questo modo (sto usando OpenCV): stackoverflow.com/a/63421847/6907424
hafiz031

6

Aggiornare

Ho anche implementato la seguente soluzione nel mio script Python qui su GitHub .

Ho anche verificato che i file danneggiati (jpg) spesso non sono immagini "rotte", ad esempio un file immagine danneggiato a volte rimane un file immagine legittimo, l'immagine originale viene persa o alterata ma puoi comunque caricarla senza errori. Tuttavia, il troncamento del file causa sempre errori.

Fine aggiornamento

È possibile utilizzare il modulo Python Pillow (PIL), con la maggior parte dei formati di immagine, per verificare se un file è un file immagine valido e intatto.

Nel caso si miri a rilevare anche immagini rotte, @Nadia Alramli suggerisce correttamente il im.verify()metodo, ma questo non rileva tutti i possibili difetti dell'immagine , es. im.verifyNon rileva immagini troncate (che la maggior parte degli spettatori spesso carica con un'area grigia).

Pillow è in grado di rilevare anche questo tipo di difetti, ma è necessario applicare la manipolazione dell'immagine o la decodifica / ricodifica dell'immagine o per attivare il controllo. Infine suggerisco di utilizzare questo codice:

try:
  im = Image.load(filename)
  im.verify() #I perform also verify, don't know if he sees other types o defects
  im.close() #reload is necessary in my case
  im = Image.load(filename) 
  im.transpose(PIL.Image.FLIP_LEFT_RIGHT)
  im.close()
except: 
  #manage excetions here

In caso di difetti dell'immagine questo codice solleverà un'eccezione. Tieni presente che im.verify è circa 100 volte più veloce rispetto all'esecuzione della manipolazione dell'immagine (e penso che il flip sia una delle trasformazioni più economiche). Con questo codice verificherai una serie di immagini a circa 10 MByte / sec con Pillow standard o 40 MByte / sec con modulo Pillow-SIMD (moderna CPU x86_64 da 2,5 Ghz).

Per gli altri formati psd , xcf , .. puoi usare Imagemagick wrapper Wand , il codice è il seguente:

im = wand.image.Image(filename=filename)
temp = im.flip;
im.close()

Ma, dai miei esperimenti, Wand non rileva immagini troncate, penso che carichi le parti mancanti come area grigia senza chiedere.

Ho letto che Imagemagick ha un comando esterno identificare che potrebbe rendere il lavoro, ma non ho trovato un modo per richiamare quella funzione di programmazione e non ho ancora testato questo percorso.

Suggerisco di effettuare sempre un controllo preliminare, controllare che la dimensione del file non sia zero (o molto piccola), è un'idea molto economica :

statfile = os.stat(filename)
filesize = statfile.st_size
if filesize == 0:
  #manage here the 'faulty image' case

5

Su Linux, potresti usare python-magic ( http://pypi.python.org/pypi/python-magic/0.1 ) che usa libmagic per identificare i formati di file.

Per quanto ne so, libmagic guarda nel file e cerca di dirti di più al riguardo oltre al formato, come dimensioni bitmap, versione del formato ecc. Quindi potresti vedere questo come un test superficiale di "validità".

Per altre definizioni di "valido" potresti dover scrivere i tuoi test.


5

Potresti usare i collegamenti Python a libmagic, python-magic e quindi controllare i tipi MIME. Questo non ti dirà se i file sono danneggiati o intatti, ma dovrebbe essere in grado di determinare di che tipo di immagine si tratta.


3

Beh, non conosco l'interno di psd, ma so che, in effetti, svg non è un file immagine di per sé, è basato su xml, quindi è, essenzialmente, un file di testo normale.


aha, hai ragione. è xml. tuttavia, contiene alcuni dati di immagine incorporati al suo interno.
Sujoy

2

Un'opzione è usare il filetypepacchetto.

Installazione

python -m pip install filetype

vantaggi

  1. Veloce: fa il suo lavoro caricando i primi byte della tua immagine ( controlla il numero magico )
  2. Supporta diversi tipi di MIME: immagini, video, caratteri, audio, archivi.

Esempio di soluzione

import filetype

filename = "/path/to/file.jpg"

if filetype.image(filename):
    print(f"{filename} is a valid image...")
elif filetype.video(filename):
    print(f"{filename} is a valid video...")

Ulteriori informazioni sul repo ufficiale: https://github.com/h2non/filetype.py


1

Il controllo delle estensioni dei file sarebbe accettabile o stai cercando di confermare che i dati stessi rappresentano un file immagine?

Se puoi controllare l'estensione del file, un'espressione regolare o un semplice confronto potrebbe soddisfare il requisito.


semplicemente controllare l'estensione non è sufficiente, poiché si può rinominare un file txt come jpg o qualcosa del genere. immagino, se non riesco a trovare una soluzione, solo allora userò il controllo delle estensioni per xcf e svg
Sujoy,

Comprensibile, speravo solo in qualche chiarimento prima di procedere all'ideazione di una soluzione che meglio si adattasse alle vostre esigenze. Grazie!
doomspork

-1
format = [".jpg",".png",".jpeg"]
 for (path,dirs,files) in os.walk(path):
     for file in files:
         if file.endswith(tuple(format)):
             print(path)
             print ("Valid",file)
         else:
             print(path)
             print("InValid",file)

Il codice presenta alcuni problemi di rientro e non verrà eseguito correttamente. Inoltre, considera l'aggiunta di alcune spiegazioni sul perché e come il tuo codice risolve il problema. Le risposte di solo codice non saranno così utili per i futuri lettori che verranno qui.
Tomerikoo

Qui abbiamo utilizzato il metodo Agrparser.
rObinradOO
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.