Como verificar se um arquivo é um arquivo de imagem válido?

105

Atualmente, estou usando PIL.

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

No entanto, embora isso cubra suficientemente a maioria dos casos, alguns arquivos de imagem como xcf, svg e psd não estão sendo detectados. Os arquivos Psd lançam uma exceção OverflowError.

Existe alguma maneira de incluí-los também?

Sujoy
fonte
21
Não é uma prática particularmente comum fechar duplicatas em diferentes idiomas. Se você não conseguir encontrar nenhuma outra pergunta sobre Python, deixe-o em aberto, pois pode haver soluções específicas para Python que as pessoas queiram postar e que não chegaram à pergunta que você postou.
Paolo Bergantino
sim, antes de mais nada, eu estava realmente esperando por uma lib python que eu não conhecia: P e então, como Ben apontou, apenas os números mágicos não validam a imagem inteira.
Sujoy
@Sujoy, validar uma imagem inteira é quase impossível, a menos que você já tenha uma cópia dela, porque o computador não pode dizer a diferença entre um pixel de cor correta e um conjunto truncado de 1s e 0s, contanto que todo o controle (números mágicos) estão corretos.
DevinB de
@devinb, concordou, vou apenas pegar os números mágicos e terminar com eles, a menos que alguém apareça com algo melhor para chamar um
refator
xcf e psd não são realmente imagens, eles são arquivos de projeto que contêm (freqüentemente muitas) imagens ... você provavelmente poderia fazer um caso para svg embora.
mgalgs 01 de

Respostas:

11

Muitas vezes, os primeiros caracteres serão um número mágico para vários formatos de arquivo. Você pode verificar isso além da verificação de exceção acima.

Brian R. Bondy
fonte
10
Isso não será suficiente se ele realmente estiver testando imagens "válidas"; a presença de um número mágico não garante que o arquivo não tenha sido truncado, por exemplo.
Ben Blank
1
excelente conselho, agora só preciso descobrir quais são esses números. obrigado :)
Sujoy
@ben, ai não pensei nisso ainda. isso é um bom ponto de fato
Sujoy
@Ben, como você esperaria que uma biblioteca inferisse que um arquivo foi truncado?
DevinB de
6
@Ben Blank: Verdade, mas resolver um problema a 99% do caminho geralmente é melhor do que não resolvê-lo.
Brian R. Bondy de
205

Acabei de encontrar o módulo imghdr integrado . Da documentação do python:

O módulo imghdr determina o tipo de imagem contida em um arquivo ou fluxo de bytes.

É assim que funciona:

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

Usar um módulo é muito melhor do que reimplementar uma funcionalidade semelhante

Nadia Alramli
fonte
2
sim, imghdr funciona para a maioria dos formatos de imagem, mas não para todos. de acordo com meu problema original com arquivos svg, xcf e psd, esses também não foram detectados no imghdr
Sujoy
2
Sua resposta é realmente melhor, obrigado. Como alguém disse acima ... mas resolver um problema 99% do caminho geralmente é melhor do que não resolvê-lo.
RinkyPinku
2
Vale a pena observar: imghdr.what(path)retorna Nonese o pathtipo de arquivo de imagem fornecido não for reconhecido. Lista de tipos atualmente reconhecidos imagem: rgb , gif , PBM , PGM , ppm , tiff , rast , XBM , jpeg , bmp , png , WebP , EXR .
patryk.beza
1
Seja cuidadoso! Um hdr válido não significa uma imagem válida (por exemplo, os bytes da imagem podem ter sido embaralhados!)
Filippo Mazza
1
Pelo comentário de @FilippoMazza, posso confirmar que uma imagem ruim que foi cortada durante a transferência pode passar neste teste, mas irá quebrar quando o PIL tentar lê-la.
kevinmicke
47

Além do que Brian está sugerindo, você pode usar o método de verificação do PIL para verificar se o arquivo está corrompido.

im.verify ()

Tenta determinar se o arquivo está quebrado, sem realmente decodificar os dados da imagem. Se esse método encontrar algum problema, ele levantará exceções adequadas. Este método só funciona em uma imagem recém-aberta; se a imagem já foi carregada, o resultado é indefinido. Além disso, se você precisar carregar a imagem após usar esse método, deverá reabrir o arquivo de imagem. Atributos

Nadia Alramli
fonte
bem, o principal problema é que os arquivos svg, xcf e psd não podem ser abertos com Image.open (), portanto, não há chance de verificar com im.verify ()
Sujoy
16
Meu Deus, a documentação do PIL é terrível. O que é exatamente uma "exceção adequada"?
Timmmm
Aqui está o link para a documentação do Pillow para Image.verify () . Infelizmente, não é melhor e parece que eles simplesmente levantaram o parágrafo acima sem adicionar nada.
Two-Bit Alchemist
Eu vi verificar o aumento de SyntaxError para arquivos PNG corrompidos
Carl
existe uma maneira de verificar "COM realmente decodificando os dados da imagem"?
Trevor Boyd Smith
7

Além da PILverificação de imagem, você também pode adicionar verificação de extensão de nome de arquivo como esta:

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

Observe que isso só verifica se o nome do arquivo tem uma extensão de imagem válida, não abre realmente a imagem para ver se é uma imagem válida, por isso você precisa usar adicionalmente PILou uma das bibliotecas sugeridas nas outras respostas.

tsveti_iko
fonte
E se as extensões estiverem incorretas nos arquivos? Por exemplo, um arquivo de texto é salvo com extensão .jpg ou vice-versa.
hafiz031
1
@ hafiz031 Para obter o formato real, você pode fazer from PIL import Image img = Image.open(filename) print(img.format)e verificar desta forma:img.format.lower() in ['png', 'jpg', 'jpeg', 'tiff', 'bmp', 'gif']
tsveti_iko
Infelizmente, isso não funcionou para mim. Ainda está identificando uma imagem corrompida como uma imagem JPEG. Por fim, consegui lidar com este caso desta forma (estou usando OpenCv): stackoverflow.com/a/63421847/6907424
hafiz031
6

Atualizar

Também implementei a seguinte solução em meu script Python aqui no GitHub .

Também verifiquei que os arquivos danificados (jpg) freqüentemente não são imagens 'quebradas', ou seja, um arquivo de imagem danificado às vezes permanece um arquivo de imagem legítimo, a imagem original foi perdida ou alterada, mas você ainda consegue carregá-la sem erros. Porém, o truncamento de arquivos sempre causa erros.

Fim da atualização

Você pode usar o módulo Python Pillow (PIL), com a maioria dos formatos de imagem, para verificar se um arquivo é válido e intacto.

Caso pretenda detectar também imagens quebradas, @Nadia Alramli sugere corretamente o im.verify()método, mas este não detecta todos os possíveis defeitos da imagem , por exemplo, im.verifynão detecta imagens truncadas (que a maioria dos visualizadores costuma carregar com uma área acinzentada).

O Pillow também é capaz de detectar esses tipos de defeitos, mas você deve aplicar a manipulação da imagem ou a decodificação / recodificação da imagem ou para acionar a verificação. Finalmente, sugiro usar este código:

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

Em caso de defeitos na imagem, este código irá gerar uma exceção. Por favor, considere que im.verify é cerca de 100 vezes mais rápido do que realizar a manipulação de imagens (e eu acho que flip é uma das transformações mais baratas). Com este código você vai verificar um conjunto de imagens a cerca de 10 MBytes / seg com Pillow padrão ou 40 MBytes / seg com módulo Pillow-SIMD (moderno CPU 2.5Ghz x86_64).

Para os outros formatos psd , xcf , .. você pode usar Imagemagick wrapper Wand , o código é o seguinte:

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

Mas, a partir de meus experimentos, o Wand não detecta imagens truncadas, acho que carrega partes que faltam como área cinza sem avisar.

Eu vermelho que Imagemagick tem uma identificação de comando externa que poderia fazer o trabalho, mas não encontrei uma maneira de invocar essa função programaticamente e não testei esta rota.

Sugiro sempre fazer uma verificação preliminar, verificar se o tamanho do arquivo não é zero (ou muito pequeno), é uma ideia muito barata :

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

No Linux, você pode usar python-magic ( http://pypi.python.org/pypi/python-magic/0.1 ) que usa libmagic para identificar formatos de arquivo.

AFAIK, libmagic examina o arquivo e tenta lhe dizer mais sobre ele do que apenas o formato, como dimensões do bitmap, versão do formato, etc. Portanto, você pode ver isso como um teste superficial de "validade".

Para outras definições de "válido", você pode ter que escrever seus próprios testes.

fmarc
fonte
5

Você pode usar as ligações Python para libmagic, python-magic e então verificar os tipos MIME. Isso não dirá se os arquivos estão corrompidos ou intactos, mas deve ser capaz de determinar que tipo de imagem é.

Kamil Kisiel
fonte
3

Bem, eu não sei sobre o interior do psd, mas eu, claro, sei que, na verdade, o svg não é um arquivo de imagem em si, - é baseado em xml, então é, essencialmente, um arquivo de texto simples.

brilhante
fonte
aha, você está certo. é xml. no entanto, ele contém alguns dados de imagem embutidos nele.
Sujoy
2

Uma opção é usar o filetype pacote.

Instalação

python -m pip install filetype

Vantagens

  1. Rápido: funciona carregando os primeiros bytes de sua imagem ( verifique o número mágico )
  2. Suporta diferentes tipos de mime: imagens, vídeos, fontes, áudio, arquivos.

Exemplo de solução

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

Informações adicionais sobre o repo oficial: https://github.com/h2non/filetype.py

Alex Fortin
fonte
1

Verificar as extensões de arquivo seria aceitável ou você está tentando confirmar se os próprios dados representam um arquivo de imagem?

Se você puder verificar a extensão do arquivo, uma expressão regular ou uma comparação simples pode satisfazer o requisito.

porco-do-mato
fonte
simplesmente verificar a extensão não será suficiente, pois é possível renomear um arquivo txt como jpg ou algo assim. Acho que, se não conseguir encontrar uma solução, só então usarei a verificação de extensão para xcf e svg
Sujoy
Compreensível, eu estava apenas esperando por alguns esclarecimentos antes de começar a conceber uma solução que possa atender melhor às suas necessidades. Obrigado!
doomspork de
-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
fonte
Seu código tem alguns problemas de indentação e não funcionará corretamente. Além disso, considere adicionar algumas explicações sobre por que e como seu código resolve o problema. As respostas apenas em código não são tão úteis para futuros leitores que vêm aqui.
Tomerikoo
Aqui, usamos o método Agrparser.
rObinradOO