Wie überprüfe ich, ob eine Datei eine gültige Bilddatei ist?

105

Ich benutze derzeit PIL.

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

Obwohl dies die meisten Fälle ausreichend abdeckt, werden einige Bilddateien wie xcf, svg und psd nicht erkannt. Psd-Dateien lösen eine OverflowError-Ausnahme aus.

Gibt es eine Möglichkeit, sie auch einzubeziehen?

Sujoy
quelle
21
Es ist nicht besonders üblich, Duplikate in verschiedenen Sprachen zu schließen. Wenn Sie keine anderen Python-Fragen finden, lassen Sie diese offen, da es möglicherweise Python-spezifische Lösungen gibt, die veröffentlicht werden sollen und die es nicht zu der von Ihnen gestellten Frage geschafft haben.
Paolo Bergantino
Ja, zuerst hatte ich wirklich auf eine Python-Bibliothek gehofft, von der ich nichts wusste: P und dann, wie Ben betonte, bestätigen nur die magischen Zahlen nicht das gesamte Bild.
Sujoy
@Sujoy, die Validierung eines gesamten Bildes ist nahezu unmöglich, es sei denn, Sie haben bereits eine Kopie davon, da der Computer den Unterschied zwischen einem korrekten Farbpixel und einem verstümmelten Satz von Einsen und Nullen nicht erkennen kann, solange die gesamte Steuerung vorhanden ist (magische Zahlen) sind korrekt.
DevinB
@devinb, stimmte zu, ich werde nur die magischen Zahlen bekommen und damit fertig sein, es sei denn, jemand anderes kommt mit etwas Besserem, um einen Refaktor zu rufen :)
Sujoy
xcf und psd sind nicht wirklich Bilder, sondern Projektdateien, die (oft viele) Bilder enthalten ... Sie könnten sich jedoch wahrscheinlich für svg aussprechen.
mgalgs

Antworten:

11

Oft sind die ersten paar Zeichen eine magische Zahl für verschiedene Dateiformate. Sie können dies zusätzlich zu Ihrer oben genannten Ausnahmeprüfung überprüfen.

Brian R. Bondy
quelle
10
Das wird nicht ausreichen, wenn er wirklich auf "gültige" Bilder testet; Das Vorhandensein einer magischen Zahl garantiert beispielsweise nicht, dass die Datei nicht abgeschnitten wurde.
Ben Blank
1
exzellenter Rat, jetzt muss ich nur noch herausfinden, was diese Zahlen sind. danke :)
Sujoy
@ben, autsch, daran habe ich noch nicht gedacht. Das ist in der Tat ein guter Punkt
Sujoy
@Ben, wie würden Sie erwarten, dass eine Bibliothek darauf schließen lässt, dass eine Datei abgeschnitten wurde?
DevinB
6
@ Ben Blank: Stimmt, aber ein Problem zu 99% zu lösen ist oft besser, als es überhaupt nicht zu lösen.
Brian R. Bondy
204

Ich habe gerade das eingebaute imghdr- Modul gefunden. Aus der Python-Dokumentation:

Das imghdr-Modul bestimmt den Bildtyp, der in einer Datei oder einem Byte-Stream enthalten ist.

So funktioniert es:

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

Die Verwendung eines Moduls ist viel besser als die Implementierung ähnlicher Funktionen

Nadia Alramli
quelle
2
Ja, imghdr funktioniert für die meisten Bildformate, aber nicht für alle. Nach meinem ursprünglichen Problem mit svg-, xcf- und psd-Dateien sind diese auch in imghdr unentdeckt
Sujoy
2
Ihre Antwort ist eigentlich besser, danke. Wie jemand oben sagte ... aber ein Problem zu lösen 99% des Weges ist oft besser als es überhaupt nicht zu lösen ..
RinkyPinku
2
Bemerkenswert: imghdr.what(path)Gibt zurück, Nonewenn der angegebene pathBilddateityp nicht erkannt wird. Liste der aktuell erkannten Bildtypen: rgb , gif , pbm , pgm , ppm , tiff , rast , xbm , jpeg , bmp , png , webp , exr .
patryk.beza
1
Achtung! Eine gültige Festplatte bedeutet kein gültiges Bild (z. B. wurden die Bildbytes möglicherweise verschlüsselt!)
Filippo Mazza
1
Gemäß dem Kommentar von @FilippoMazza kann ich bestätigen, dass ein schlechtes Bild, das während der Übertragung abgeschnitten wurde, diesen Test bestehen kann, aber unterbrochen wird, wenn PIL versucht, es zu lesen.
Kevinmicke
47

Zusätzlich zu den Vorschlägen von Brian können Sie die Überprüfungsmethode von PIL verwenden, um zu überprüfen, ob die Datei beschädigt ist.

im.verify ()

Versuche festzustellen, ob die Datei beschädigt ist, ohne die Bilddaten tatsächlich zu dekodieren. Wenn diese Methode Probleme feststellt, werden geeignete Ausnahmen ausgelöst. Diese Methode funktioniert nur bei einem neu geöffneten Bild. Wenn das Bild bereits geladen wurde, ist das Ergebnis undefiniert. Wenn Sie das Bild nach dieser Methode laden müssen, müssen Sie die Bilddatei erneut öffnen. Attribute

Nadia Alramli
quelle
Nun, das Hauptproblem ist, dass SVG-, XCF- und PSD-Dateien nicht mit Image.open () geöffnet werden können, daher keine Möglichkeit zur Überprüfung mit im.verify ()
Sujoy
16
Mein Gott, die PIL-Dokumentation ist schrecklich. Was genau ist eine "geeignete Ausnahme"?
Timmmm
Hier ist der Link zur Pillow-Dokumentation für Image.verify () . Leider ist es nicht besser und es sieht so aus, als hätten sie den obigen Absatz einfach angehoben, ohne etwas hinzuzufügen.
Zwei-Bit-Alchemist
Ich habe gesehen, wie SyntaxError für beschädigte PNG-Dateien ausgelöst wurde
Carl
Gibt es eine Möglichkeit zu überprüfen, ob die Bilddaten tatsächlich dekodiert wurden?
Trevor Boyd Smith
7

Zusätzlich zur PILBildprüfung können Sie auch die Prüfung der Dateinamenerweiterung wie folgt hinzufügen:

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

Beachten Sie, dass hierdurch nur geprüft wird, ob der Dateiname eine gültige Bilderweiterung hat. Das Bild wird nicht geöffnet, um festzustellen, ob es sich um ein gültiges Bild handelt. Aus diesem Grund müssen Sie zusätzlich PILoder eine der in den anderen Antworten vorgeschlagenen Bibliotheken verwenden.

tsveti_iko
quelle
Was ist, wenn die Erweiterungen in den Dateien falsch sind? Beispielsweise wird eine Textdatei mit der Erweiterung .jpg gespeichert oder umgekehrt.
hafiz031 vor
6

Aktualisieren

Ich habe auch die folgende Lösung in meinem Python-Skript hier auf GitHub implementiert .

Ich habe auch überprüft, dass beschädigte Dateien (JPG) häufig keine "kaputten" Bilder sind, dh eine beschädigte Bilddatei bleibt manchmal eine legitime Bilddatei, das Originalbild geht verloren oder wird geändert, aber Sie können es trotzdem ohne Fehler laden. Das Abschneiden von Dateien verursacht jedoch immer Fehler.

Update beenden

Sie können das PIL-Modul ( Python Pillow ) mit den meisten Bildformaten verwenden, um zu überprüfen, ob eine Datei eine gültige und intakte Bilddatei ist.

Für den Fall, dass Sie auch fehlerhafte Bilder erkennen möchten, schlägt @Nadia Alramli die im.verify()Methode korrekt vor , erkennt jedoch nicht alle möglichen Bildfehler , z. B. im.verifyerkennt keine abgeschnittenen Bilder (die die meisten Betrachter häufig mit einem grauen Bereich laden).

Pillow kann auch diese Art von Fehlern erkennen, aber Sie müssen eine Bildmanipulation oder eine Bilddecodierung / -rekodierung anwenden oder die Prüfung auslösen. Schließlich schlage ich vor, diesen Code zu verwenden:

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

Bei Bildfehlern löst dieser Code eine Ausnahme aus. Bitte beachten Sie, dass im.verify etwa 100-mal schneller ist als die Bildmanipulation (und ich denke, dass Flip eine der billigeren Transformationen ist). Mit diesem Code überprüfen Sie eine Reihe von Bildern mit etwa 10 MByte / s mit Standardkissen oder 40 MByte / s mit Pillow-SIMD-Modul (moderne 2,5-GHz-x86_64-CPU).

Für die anderen Formate psd , xcf , .. können Sie Imagemagick Wrapper Wand verwenden . Der Code lautet wie folgt:

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

Aber aus meinen Experimenten erkennt Wand keine abgeschnittenen Bilder, ich denke, er lädt fehlende Teile als grauer Bereich ohne Aufforderung.

I rot , dass ImageMagick hat einen externen Befehl erkennen , dass könnte den Job machen, aber ich habe keinen Weg zum Aufrufen dieser Funktion programmatisch und ich habe nicht getestet , diesen Weg gefunden.

Ich schlage vor, immer eine vorläufige Überprüfung durchzuführen und zu überprüfen, ob die Dateigröße nicht Null (oder sehr klein) ist. Dies ist eine sehr billige Idee:

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

Unter Linux können Sie Python-Magic ( http://pypi.python.org/pypi/python-magic/0.1 ) verwenden, das libmagic zum Identifizieren von Dateiformaten verwendet.

AFAIK, libmagic schaut in die Datei und versucht, Ihnen mehr darüber zu erzählen als nur das Format, wie Bitmap-Dimensionen, Formatversion usw. Sie könnten dies also als oberflächlichen Test für "Gültigkeit" ansehen.

Für andere Definitionen von "gültig" müssen Sie möglicherweise Ihre eigenen Tests schreiben.

fmarc
quelle
4

Sie können die Python-Bindungen für libmagic, python-magic verwenden und dann die MIME - Typen überprüfen. Dies sagt Ihnen nicht, ob die Dateien beschädigt oder intakt sind, aber es sollte in der Lage sein zu bestimmen, um welche Art von Bild es sich handelt.

Kamil Kisiel
quelle
3

Nun, ich weiß nichts über die Innenseiten von psd, aber ich weiß sicher, dass svg tatsächlich keine Bilddatei an sich ist - es basiert auf xml, also ist es im Wesentlichen a Nur-Text-Datei.

shylent
quelle
Aha, du hast recht. es ist xml. Es enthält jedoch einige darin eingebettete Bilddaten.
Sujoy
2

Eine Möglichkeit besteht darin, das filetypePaket zu verwenden.

Installation

python -m pip install filetype

Vorteile

  1. Schnell: Funktioniert das Laden der ersten Bytes Ihres Bildes ( überprüfen Sie die magische Zahl )
  2. Unterstützt verschiedene MIME-Typen: Bilder, Videos, Schriftarten, Audio, Archive.

Lösungsbeispiel

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

Zusätzliche Informationen zum offiziellen Repo: https://github.com/h2non/filetype.py

Alex Fortin
quelle
1

Wäre es akzeptabel, die Dateierweiterungen zu überprüfen, oder versuchen Sie zu bestätigen, dass die Daten selbst eine Bilddatei darstellen?

Wenn Sie die Dateierweiterung überprüfen können, kann ein regulärer Ausdruck oder ein einfacher Vergleich die Anforderung erfüllen.

Doomspork
quelle
Es reicht nicht aus, nur die Erweiterung zu überprüfen, da man eine txt-Datei in jpg oder so umbenennen kann. Ich denke, wenn ich keine Lösung finden kann, werde ich nur dann die Erweiterungsprüfung für xcf und svg verwenden
Sujoy
Verständlicherweise hatte ich nur auf eine Klarstellung gehofft, bevor ich eine Lösung entwickelte, die Ihren Anforderungen besser entsprechen könnte. Vielen Dank!
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
quelle
Ihr Code weist einige Einrückungsprobleme auf und wird nicht ordnungsgemäß ausgeführt. Erwägen Sie außerdem, einige Erklärungen hinzuzufügen, warum und wie Ihr Code das Problem löst. Nur-Code-Antworten sind für zukünftige Leser, die hierher kommen, nicht so hilfreich.
Tomerikoo
Hier haben wir die Agrparser-Methode verwendet.
rObinradOO