如何检查文件是否为有效的图像文件?


105

我目前正在使用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的解决方案,而这些问题并没有解决您发布的问题。
Paolo Bergantino

是的,首先,我真的很希望找到一个我不了解:P的python库,然后如ben所指出的那样,只是魔术数字不能验证整个图像。
Sujoy

@Sujoy,几乎不可能验证整个图像,除非您已经拥有了它的副本,因为只要所有控件,计算机都无法分辨出正确的彩色像素与乱码的1和0之间的区别。 (幻数)是正确的。
DevinB

@devinb,同意,除非有人提出更好的要求重构的方法,否则我将获得不可思议的数字:)
Sujoy

xcf和psd并不是真正的图像,它们是包含(通常是许多)图像的项目文件……不过,您可能会为svg辩护。
mgalgs 2014年

Answers:


11

很多时候,前几个字符对于各种文件格式来说都是一个神奇的数字。除了上面的异常检查之外,您还可以检查此内容。


10
如果他真的在测试“有效”图像,那还不够。例如,幻数的存在并不能保证文件没有被截断。
本·布兰克

1
极好的建议,现在我只需要弄清楚这些数字是多少。谢谢:)
Sujoy

@ben,哎呀,我还没想到。那确实是一个好点
Sujoy

@Ben,您如何期望库来推断文件已被截断?
DevinB

6
@本·布兰克(Ben Blank):是的,但是99%地解决问题通常比根本不解决要好。
布赖恩·邦迪

205

我刚刚找到了内置的imghdr模块。从python文档中:

imghdr模块确定文件或字节流中包含的图像的类型。

它是这样工作的:

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

使用模块比重新实现类似功能要好得多


2
是的,imghdr适用于大多数图像格式,但不是全部。根据我对svg,xcf和psd文件的原始问题,以及在imghdr中也未检测到的问题
Sujoy,2009年

2
谢谢,您的回答实际上更好。就像上面的人说的...但是解决问题的99%的方法通常总比根本解决好。
RinkyPinku 2015年

2
值得注意的是:如果给定的图像文件类型无法识别,则imghdr.what(path)返回。当前识别的图像类型列表rgbgifpbmpgmppmtiffrastxbmjpegbmppngwebpexrNonepath
patryk.beza 2016年

1
小心!有效的hdr并不表示有效的图像(例如,图像字节可能已被加密!)
Filippo Mazza

1
根据@FilippoMazza的评论,我可以确认在传输过程中被切断的不良图像可以通过此测试,但是在PIL尝试读取它时会破裂。
kevinmicke '18

47

除了Brian建议的内容之外,您还可以使用PIL的verify方法检查文件是否损坏。

im.verify()

尝试确定文件是否损坏,而无需实际解码图像数据。如果此方法发现任何问题,它将引发适当的异常。此方法仅适用于新打开的图像。如果图像已经加载,则结果不确定。另外,如果在使用此方法后需要加载图像,则必须重新打开图像文件。属性


好吧,主要问题是无法使用Image.open()打开svg,xcf和psd文件,因此,无法通过im.verify()进行验证
Sujoy

16
我的上帝,PIL文档太糟糕了。什么是“适当的例外”?
Timmmm

这是Image.verify()枕头文档的链接。不幸的是,这并没有更好,而且看起来他们只是在不添加任何内容的情况下抬起了上面的段落。
两位炼金术士

我已经看到了验证为损坏的png文件引发SyntaxError的错误
Carl

有没有办法验证“实际上是在解码图像数据”?
Trevor Boyd Smith,

7

除了PIL图像检查之外,您还可以添加文件扩展名检查,如下所示:

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

请注意,这只会检查文件名是否具有有效的图像扩展名,它实际上不会打开图像以查看它是否为有效图像,这就是为什么您需要额外使用PIL或其他答案中建议的一个库的原因。


如果文件中的扩展名不正确怎么办?例如,文本文件以.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

更新资料

我还在GitHub上的 Python脚本中实现了以下解决方案

我还验证了损坏的文件(jpg)经常不是“损坏”的图像,即,损坏的图片文件有时仍是合法的图片文件,原始图像丢失或更改了,但是您仍然可以正确加载它。但是,文件截断总是导致错误。

结束更新

您可以使用Python 枕头具有大多数图像格式的(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倍(我认为翻页是更便宜的转换之一)。使用此代码,您将使用标准Pillow或大约40 MBytes / sec(使用Pillow-SIMD模块)(现代2.5Ghz x86_64 CPU)验证一组图像,速度约为10 MB /秒。

对于其他格式psdxcf ..,您可以使用Imagemagick包装器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

4

在Linux上,您可以使用python-magic(http://pypi.python.org/pypi/python-magic/0.1),它使用libmagic来识别文件格式。

AFAIK,libmagic会查看文件并尝试向您提供有关格式的更多信息,例如位图尺寸,格式版本等。因此,您可能会将其视为对“有效性”的肤浅测试。

对于“有效”的其他定义,您可能必须编写自己的测试。



3

好吧,我不了解psd的内部信息,但是我可以肯定地知道,事实上,svg本身不是图像文件,而是基于xml的,因此从本质上讲它是一个纯文本文件。


啊哈,你是对的。它是xml。但是,其中包含一些嵌入的图像数据。
Sujoy

2

一种选择是使用filetype软件包。

安装

python -m pip install filetype

优点

  1. 快速:通过加载图片的前几个字节来工作(检查幻数
  2. 支持不同的mime类型:图像,视频,字体,音频,档案。

解决方案示例

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使用扩展名检查
Sujoy,2009年

可以理解的是,我只是希望进行一些澄清,然后再着手设计一种更适合您需要的解决方案。谢谢!
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)

您的代码存在一些缩进问题,无法正常运行。另外,考虑添加有关代码为什么以及如何解决问题的一些说明。仅代码的答案对以后来这里的读者没有太大帮助。
Tomerikoo

这里我们使用了Agrparser方法。
rObinradOO
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.