Comment vérifier si un fichier est un fichier image valide?

105

J'utilise actuellement PIL.

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

Cependant, bien que cela couvre suffisamment la plupart des cas, certains fichiers image tels que, xcf, svg et psd ne sont pas détectés. Les fichiers PSD lèvent une exception OverflowError.

Y a-t-il moyen de les inclure également?

Sujoy
la source
21
Il n'est pas particulièrement courant de fermer les doublons dans différentes langues. Si vous ne trouvez aucune autre question Python avec cela, laissez-la ouverte car il pourrait y avoir des solutions spécifiques à Python que les gens veulent publier et qui n'ont pas répondu à la question que vous avez posée.
Paolo Bergantino
oui, tout d'abord j'espérais vraiment une lib python que je ne connaissais pas: P et puis comme ben l'a souligné, seuls les nombres magiques ne valident pas l'image entière.
Sujoy
@Sujoy, valider une image entière est presque impossible, sauf si vous en avez déjà une copie, car l'ordinateur ne peut pas faire la différence entre un pixel de couleur correct et un ensemble brouillé de 1 et de 0, tant que tout le contrôle (nombres magiques) sont corrects.
DevinB
@devinb, d'accord, je vais juste obtenir les chiffres magiques et en finir avec ça à moins que quelqu'un d'autre ne propose quelque chose de mieux pour appeler un refactor :)
Sujoy
xcf et psd ne sont pas vraiment des images, ce sont des fichiers de projet qui contiennent (souvent beaucoup) d'images ... vous pourriez probablement faire un cas pour svg.
mgalgs

Réponses:

11

Souvent, les deux premiers caractères seront un nombre magique pour différents formats de fichiers. Vous pouvez vérifier cela en plus de la vérification des exceptions ci-dessus.

Brian R. Bondy
la source
10
Ce ne sera pas suffisant s'il teste vraiment des images «valides»; la présence d'un nombre magique ne garantit pas que le fichier n'a pas été tronqué, par exemple.
Ben Blank
1
d'excellents conseils, maintenant j'ai juste besoin de comprendre quels sont ces chiffres. merci :)
Sujoy
@ben, aïe je n'y ai pas encore pensé. c'est un bon point en effet
Sujoy
@Ben, comment vous attendriez-vous à ce qu'une bibliothèque déduise qu'un fichier a été tronqué?
DevinB
6
@Ben Blank: C'est vrai, mais résoudre un problème à 99% est souvent mieux que de ne pas le résoudre du tout.
Brian R. Bondy
206

Je viens de trouver le module imghdr intégré. À partir de la documentation python:

Le module imghdr détermine le type d'image contenue dans un fichier ou un flux d'octets.

Voilà comment cela fonctionne:

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

L'utilisation d'un module est bien meilleure que la réimplémentation de fonctionnalités similaires

Nadia Alramli
la source
2
oui imghdr fonctionne pour la plupart des formats d'image mais pas tous. selon mon problème initial avec les fichiers svg, xcf et psd, eh bien ceux-ci ne sont pas détectés dans imghdr également
Sujoy
2
Votre réponse est en fait meilleure, merci. Comme quelqu'un l'a dit ci-dessus ... mais résoudre un problème à 99% est souvent mieux que de ne pas le résoudre du tout ..
RinkyPinku
2
A noter: imghdr.what(path)renvoie Nonesi pathle type de fichier image n'est pas reconnu. Liste des types d'images actuellement reconnus: rgb , gif , pbm , pgm , ppm , tiff , rast , xbm , jpeg , bmp , png , webp , exr .
patryk.beza
1
Faites attention! Un hdr valide ne signifie pas une image valide (par exemple, les octets de l'image peuvent avoir été brouillés!)
Filippo Mazza
1
Selon le commentaire de @FilippoMazza, je peux confirmer qu'une mauvaise image qui a été coupée pendant le transfert peut passer ce test, mais se cassera lorsque PIL essaiera de la lire.
kevinmicke
47

En plus de ce que Brian suggère que vous pouvez utiliser PIL est de vérifier la méthode pour vérifier si le fichier est cassé.

im.verify ()

Tente de déterminer si le fichier est cassé, sans décoder réellement les données d'image. Si cette méthode rencontre des problèmes, elle soulève des exceptions appropriées. Cette méthode ne fonctionne que sur une image nouvellement ouverte; si l'image a déjà été chargée, le résultat n'est pas défini. De plus, si vous devez charger l'image après avoir utilisé cette méthode, vous devez rouvrir le fichier image. Les attributs

Nadia Alramli
la source
eh bien, le principal problème est que les fichiers svg, xcf et psd ne peuvent pas être ouverts avec Image.open () donc aucune chance de vérifier avec im.verify ()
Sujoy
16
Mon dieu, la documentation PIL est terrible. Qu'est-ce qu'une «exception appropriée»?
Timmmm
Voici le lien vers la documentation Pillow pour Image.verify () . Malheureusement, ce n'est pas mieux, et il semble qu'ils viennent de lever le paragraphe ci-dessus sans rien ajouter.
Two-Bit Alchemist
J'ai vu vérifier augmenter SyntaxError pour les fichiers png corrompus
Carl
existe-t-il un moyen de vérifier "AVEC le décodage des données d'image"?
Trevor Boyd Smith
7

En plus de la PILvérification d'image, vous pouvez également ajouter une vérification d'extension de nom de fichier comme ceci:

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

Notez que cela ne vérifie que si le nom du fichier a une extension d'image valide, cela n'ouvre pas réellement l'image pour voir si c'est une image valide, c'est pourquoi vous devez utiliser en plus PILou l'une des bibliothèques suggérées dans les autres réponses.

tsveti_iko
la source
Que faire si les extensions sont incorrectes dans les fichiers? Par exemple, un fichier texte est enregistré avec l'extension .jpg ou vice versa.
hafiz031
1
@ hafiz031 Pour obtenir le format réel, vous pouvez le faire from PIL import Image img = Image.open(filename) print(img.format), puis le vérifier comme ceci:img.format.lower() in ['png', 'jpg', 'jpeg', 'tiff', 'bmp', 'gif']
tsveti_iko
Malheureusement, cela n'a pas fonctionné pour moi. Il identifie toujours une image corrompue comme une image JPEG. Enfin, j'ai réussi à gérer ce cas de cette manière (j'utilise OpenCv): stackoverflow.com/a/63421847/6907424
hafiz031
6

Mettre à jour

J'ai également implémenté la solution suivante dans mon script Python ici sur GitHub .

J'ai également vérifié que les fichiers endommagés (jpg) ne sont souvent pas des images «cassées», c'est-à-dire qu'un fichier image endommagé reste parfois un fichier image légitime, l'image d'origine est perdue ou modifiée mais vous pouvez toujours la charger sans erreur. Mais, la troncature de fichier provoque toujours des erreurs.

Mettre fin à la mise à jour

Vous pouvez utiliser le module Python Pillow (PIL), avec la plupart des formats d'image, pour vérifier si un fichier est un fichier image valide et intact.

Dans le cas où vous souhaitez détecter des images également cassées, @Nadia Alramli suggère correctement la im.verify()méthode, mais cela ne détecte pas tous les défauts d'image possibles , par exemple, im.verifyne détecte pas les images tronquées (que la plupart des téléspectateurs chargent souvent avec une zone grisée).

Pillow est également capable de détecter ce type de défauts, mais vous devez appliquer une manipulation d'image ou un décodage / recodage d'image ou déclencher la vérification. Enfin, je suggère d'utiliser ce code:

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

En cas de défauts d'image, ce code lèvera une exception. Veuillez noter que im.verify est environ 100 fois plus rapide que la manipulation d'image (et je pense que le retournement est l'une des transformations les moins chères). Avec ce code, vous allez vérifier un ensemble d'images à environ 10 Mo / s avec Pillow standard ou 40 Mo / s avec le module Pillow-SIMD (processeur 2.5Ghz x86_64 moderne).

Pour les autres formats psd , xcf , .. vous pouvez utiliser le wrapper Wand Imagemagick , le code est le suivant:

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

Mais, d'après mes expériences, Wand ne détecte pas les images tronquées, je pense qu'il charge les parties manquantes sous forme de zone grisée sans invite.

Je rouge qu'Imagemagick a une identification de commande externe qui pourrait faire le travail, mais je n'ai pas trouvé de moyen d'invoquer cette fonction par programme et je n'ai pas testé cette route.

Je suggère de toujours effectuer une vérification préliminaire, de vérifier que la taille du fichier n'est pas nulle (ou très petite), c'est une idée très bon marché :

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

Sous Linux, vous pouvez utiliser python-magic ( http://pypi.python.org/pypi/python-magic/0.1 ) qui utilise libmagic pour identifier les formats de fichiers.

AFAIK, libmagic regarde dans le fichier et essaie de vous en dire plus que juste le format, comme les dimensions du bitmap, la version du format, etc. Vous pourriez donc voir cela comme un test superficiel de «validité».

Pour d'autres définitions de «valide», vous devrez peut-être écrire vos propres tests.

fmarc
la source
5

Vous pouvez utiliser les liaisons Python avec libmagic, python-magic puis vérifier les types mime. Cela ne vous dira pas si les fichiers sont corrompus ou intacts, mais cela devrait être en mesure de déterminer de quel type d'image il s'agit.

Kamil Kisiel
la source
3

Eh bien, je ne connais pas les entrailles de psd, mais je sais, bien sûr, que, en fait, svg n'est pas un fichier image en soi, - il est basé sur xml, donc c'est, essentiellement, un fichier texte brut.

timide
la source
aha, tu as raison. c'est xml. cependant, il contient des données d'image intégrées.
Sujoy
2

Une option est d'utiliser le filetypepackage.

Installation

python -m pip install filetype

Avantages

  1. Rapide: fait son travail en chargeant les premiers octets de votre image ( vérifiez le nombre magique )
  2. Prend en charge différents types de mime: images, vidéos, polices, audio, archives.

Exemple de solution

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

Informations supplémentaires sur le repo officiel: https://github.com/h2non/filetype.py

Alex Fortin
la source
1

La vérification des extensions de fichier serait-elle acceptable ou essayez-vous de confirmer que les données elles-mêmes représentent un fichier image?

Si vous pouvez vérifier l'extension du fichier, une expression régulière ou une simple comparaison pourrait satisfaire l'exigence.

doomspork
la source
vérifier simplement l'extension ne suffira pas, car on peut renommer un fichier txt en jpg ou quelque chose. Je suppose que si je ne trouve pas de solution, alors seulement j'utiliserai la vérification des extensions pour xcf et svg
Sujoy
Compréhensible, j'espérais juste quelques éclaircissements avant de commencer à concevoir une solution qui pourrait mieux répondre à vos besoins. Merci!
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)
rObinradOO
la source
Votre code a des problèmes d'indentation et ne fonctionnera pas correctement. Pensez également à ajouter des explications sur les raisons et la manière dont votre code résout le problème. Les réponses basées uniquement sur le code ne seront pas si utiles pour les futurs lecteurs qui viennent ici.
Tomerikoo
Ici, nous avons utilisé la méthode Agrparser.
rObinradOO