Как проверить, является ли файл действительным файлом изображения?

106

В настоящее время я использую PIL.

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

Однако, хотя этого достаточно для большинства случаев, некоторые файлы изображений, такие как xcf, svg и psd, не обнаруживаются. Файлы Psd вызывают исключение OverflowError.

Могу ли я как-нибудь включить их?

Суджой
источник
21
Закрывать дубликаты на разных языках не очень распространенная практика. Если вы не можете найти какие-либо другие вопросы Python с этим, оставьте его открытым, поскольку могут быть специфические для Python решения, которые люди хотят публиковать, но не попали в опубликованный вами вопрос.
Паоло Бергантино
да, во-первых, я действительно надеялся на библиотеку python, о которой я не знал: P, а затем, как заметил Бен, просто магические числа не проверяют все изображение.
Суджой
@Sujoy, проверка всего изображения практически невозможна, если у вас уже нет его копии, потому что компьютер не может определить разницу между правильным цветным пикселем и искаженным набором единиц и нулей, если все элементы управления (магические числа) верны.
DevinB
@devinb, согласен, я просто получу магические числа и покончим с этим, если кто-то другой не придумает что-нибудь получше, чтобы вызвать рефакторинг :)
Суджой
xcf и psd на самом деле не являются изображениями, это файлы проектов, которые содержат (часто много) изображений ... вы, вероятно, могли бы привести аргументы в пользу svg.
mgalgs 01

Ответы:

11

Часто первая пара символов будет магическим числом для различных форматов файлов. Вы можете проверить это в дополнение к проверке исключений выше.

Брайан Р. Бонди
источник
11
Этого будет недостаточно, если он действительно проверяет «действительные» изображения; например, наличие магического числа не гарантирует, что файл не был усечен.
Бен Бланк,
1
отличный совет, теперь мне просто нужно выяснить, что это за числа. спасибо :)
Sujoy
@ben, ой, я еще не думал об этом. это действительно хороший момент
Суджой
@ Бен, как вы ожидаете, что библиотека сделает вывод, что файл был усечен?
DevinB
6
@ Бен Бланк: Верно, но часто лучше решить проблему на 99%, чем не решать ее вообще.
Брайан Р. Бонди,
208

Я только что нашел встроенный модуль imghdr . Из документации python:

Модуль imghdr определяет тип изображения, содержащегося в файле или потоке байтов.

Вот как это работает:

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

Использование модуля намного лучше, чем повторная реализация аналогичной функции

Надя Алрамли
источник
2
да, imghdr работает для большинства форматов изображений, но не для всех. согласно моей первоначальной проблеме с файлами svg, xcf и psd, ну, они также не обнаружены в imghdr
Суджой,
2
Ваш ответ на самом деле лучше, спасибо. Как кто-то сказал выше ... но зачастую лучше решить проблему на 99%, чем не решать ее вообще ..
RinkyPinku
2
Стоит отметить: imghdr.what(path)возвращается, Noneесли указан pathнераспознанный тип файла изображения. Список распознаваемых в настоящее время типов изображений: rgb , gif , pbm , pgm , ppm , tiff , rast , xbm , jpeg , bmp , png , webp , exr .
patryk.beza 06
1
Быть осторожен! Действительный hdr не означает действительное изображение (например, байты изображения могли быть зашифрованы!)
Филиппо
1
В комментарии @FilippoMazza я могу подтвердить, что плохое изображение, которое было обрезано во время передачи, может пройти этот тест, но сломается, когда PIL попытается его прочитать.
kevinmicke
47

Помимо того , что Брайан предполагая , вы можете использовать PIL это проверить метод , чтобы проверить , если файл разбит.

im.verify ()

Пытается определить, поврежден ли файл, без фактического декодирования данных изображения. Если этот метод обнаруживает какие-либо проблемы, он вызывает соответствующие исключения. Этот метод работает только с вновь открытым изображением; если изображение уже было загружено, результат не определен. Кроме того, если вам нужно загрузить изображение после использования этого метода, вы должны повторно открыть файл изображения. Атрибуты

Надя Алрамли
источник
ну основная проблема в том, что файлы svg, xcf и psd не могут быть открыты с помощью Image.open (), следовательно, нет шансов проверить с помощью im.verify ()
Суджой
16
Боже мой, документация PIL ужасна. Что такое «подходящее исключение»?
Timmmm
Вот ссылка на документацию Pillow для Image.verify () . К сожалению, это не лучше, и похоже, что они просто подняли абзац выше, ничего не добавляя.
Two-Bit Alchemist
Я видел, как проверять повышение SyntaxError для поврежденных файлов png
Карл
есть ли способ проверить "С фактически декодированием данных изображения"?
Trevor Boyd Smith
7

В дополнение к PILпроверке изображения вы также можете добавить проверку расширения имени файла следующим образом:

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

Обратите внимание, что это только проверяет, имеет ли имя файла допустимое расширение изображения, оно фактически не открывает изображение, чтобы увидеть, является ли оно действительным изображением, поэтому вам необходимо использовать дополнительно PILили одну из библиотек, предложенных в других ответах.

tsveti_iko
источник
Что делать, если расширения в файлах неверны? Например, текстовый файл сохраняется с расширением .jpg или наоборот.
hafiz031
1
@ hafiz031 Чтобы получить фактический формат, вы можете сделать, from PIL import Image img = Image.open(filename) print(img.format)а затем проверить его следующим образом:img.format.lower() in ['png', 'jpg', 'jpeg', 'tiff', 'bmp', 'gif']
tsveti_iko
К сожалению, у меня это не сработало. Он по-прежнему идентифицирует поврежденное изображение как изображение JPEG. Наконец, мне удалось обработать этот случай таким образом (я использую OpenCv): stackoverflow.com/a/63421847/6907424
hafiz031
6

Обновить

Я также реализовал следующее решение в моем скрипте Python здесь, на GitHub .

Я также подтвердил, что поврежденные файлы (jpg) часто не являются «битыми» изображениями, т.е. поврежденный файл изображения иногда остается законным файлом изображения, исходное изображение потеряно или изменено, но вы все равно можете загрузить его без ошибок. Но усечение файла всегда вызывает ошибки.

Конец обновления

Вы можете использовать модуль Python Pillow (PIL) с большинством форматов изображений, чтобы проверить, является ли файл действительным и неповрежденным файлом изображения.

В случае, если вы стремитесь обнаруживать также битые изображения, @Nadia Alramli правильно предлагает im.verify()метод, но он не обнаруживает все возможные дефекты изображения , например, im.verifyне обнаруживает усеченные изображения (которые большинство зрителей часто загружают с серой областью).

Pillow также может обнаруживать дефекты такого типа, но вы должны применить манипуляции с изображениями или декодировать / перекодировать изображение или запустить проверку. Напоследок предлагаю использовать этот код:

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

В случае дефектов изображения этот код вызовет исключение. Учтите, что im.verify примерно в 100 раз быстрее, чем обработка изображений (и я думаю, что переворот - одно из самых дешевых преобразований). С помощью этого кода вы собираетесь проверить набор изображений со скоростью около 10 МБ / с со стандартной подушкой или 40 МБ / с с модулем Pillow-SIMD (современный процессор x86_64 2,5 ГГц).

Для других форматов psd , xcf , .. вы можете использовать Imagemagick wrapper Wand , код следующий:

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

Но, судя по моим экспериментам, Wand не обнаруживает усеченные изображения, я думаю, что он загружает недостающие части в виде серой области без запроса.

Я отмечаю, что Imagemagick имеет внешний идентификатор команды, который может выполнить задание, но я не нашел способа вызвать эту функцию программно и не тестировал этот маршрут.

Я предлагаю всегда выполнять предварительную проверку, проверять, чтобы размер файла не был нулевым (или очень маленьким), это очень дешевая идея:

statfile = os.stat(filename)
filesize = statfile.st_size
if filesize == 0:
  #manage here the 'faulty image' case
Фабиано Тарлао
источник
5

В Linux вы можете использовать python-magic ( http://pypi.python.org/pypi/python-magic/0.1 ), который использует libmagic для определения форматов файлов.

AFAIK, libmagic просматривает файл и пытается рассказать вам о нем больше, чем просто формат, например размеры растрового изображения, версию формата и т. Д. Так что вы можете рассматривать это как поверхностный тест на «достоверность».

Для других определений «действительного» вам, возможно, придется написать свои собственные тесты.

fmarc
источник
5

Вы можете использовать привязки Python к libmagic, python-magic, а затем проверить типы mime. Он не скажет вам, повреждены ли файлы или нет, но он сможет определить, какой это тип изображения.

Камиль Кисиэль
источник
3

Что ж, я не знаю, как устроен psd, но я, конечно, знаю, что, по сути, svg не является файлом изображения как таковым, он основан на xml, поэтому, по сути, это простой текстовый файл.

хитрый
источник
ага, ты прав. это xml. однако он содержит некоторые данные изображения, встроенные в него.
Суджой,
3

Один из вариантов - использовать filetype пакет.

Монтаж

python -m pip install filetype

Преимущества

  1. Быстро: выполняет свою работу, загружая первые несколько байтов вашего изображения ( проверьте магическое число )
  2. Поддерживает различные типы пантомимы: изображения, видео, шрифты, аудио, архивы.

Пример решения

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

Дополнительная информация об официальном репо: https://github.com/h2non/filetype.py

Алекс Фортин
источник
1

Будет ли приемлемой проверка расширений файлов или вы пытаетесь подтвердить, что сами данные представляют собой файл изображения?

Если вы можете проверить расширение файла, регулярное выражение или простое сравнение могут удовлетворить требование.

судорога
источник
простой проверки расширения будет недостаточно, так как можно переименовать txt-файл как jpg или что-то в этом роде. Думаю, если я не найду решения, только тогда я буду использовать проверку расширений для xcf и svg
Суджой,
Понятно, я просто надеялся на некоторые разъяснения, прежде чем приступить к разработке решения, которое могло бы лучше соответствовать вашим потребностям. Спасибо!
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
источник
В вашем коде есть проблемы с отступами, и он не будет работать должным образом. Также рассмотрите возможность добавления некоторых объяснений того, почему и как ваш код решает проблему. Ответы только на код не будут столь полезны для будущих читателей, приходящих сюда.
Tomerikoo
Здесь мы использовали метод Agrparser.
rObinradOO