PIL处理大图片出现"IOError: image file truncated"错误

105

我认为这个问题与Zope无关。但是我会解释一下我的尝试:

我在Zope中使用PUT_factory将图片通过FTP上传到ZODB。上传的图像被保存为Zope Image,并放置在新创建的容器对象内部。这很好用,但是如果图像超过一定大小(宽度和高度),我想调整图像的大小。因此,我使用PIL的缩略图函数将它们调整为200x200。只要上传的图像相对较小,这就可以正常工作。我没有检查确切的限制,但是976x1296像素仍然可以。

对于更大的图片,我遇到了:

Module PIL.Image, line 1559, in thumbnail
Module PIL.ImageFile, line 201, in load
IOError: image file is truncated (nn bytes not processed).

我测试了很多从相机中获取的JPEG格式的图片,我不认为它们全部都被截断了。

以下是我的代码:

if img and img.meta_type == 'Image':
  pilImg = PIL.Image.open( StringIO(str(img.data)) )
elif imgData:
  pilImg = PIL.Image.open( StringIO(imgData) )

pilImg.thumbnail((width, height), PIL.Image.ANTIALIAS)

因为我使用了PUT_factory,所以我没有一个文件对象,我使用来自工厂的原始数据或之前创建的(Zope)图像对象。

我听说当图像大小超过一定尺寸时,PIL会以不同的方式处理图像数据,但我不知道如何调整我的代码。还是与PIL的延迟加载有关?

7个回答

255

我回复有点晚,但我遇到了类似的问题,我想分享我的解决方案。首先,这是一个相当典型的堆栈跟踪:

Traceback (most recent call last):
  ...
  File ..., line 2064, in ...
    im.thumbnail(DEFAULT_THUMBNAIL_SIZE, Image.ANTIALIAS)
  File "/Library/Python/2.7/site-packages/PIL/Image.py", line 1572, in thumbnail
    self.load()
  File "/Library/Python/2.7/site-packages/PIL/ImageFile.py", line 220, in load
    raise IOError("image file is truncated (%d bytes not processed)" % len(b))
IOError: image file is truncated (57 bytes not processed)

如果我们在你的代码中查找第220行左右(在你的情况下可能是第201行 - 也许你正在运行稍微不同的版本),我们可以看到PIL正在以文件块的形式读入文件,并且它期望这些块的大小都是一定的。事实证明,你可以通过改变设置要求PIL能够容忍已截断的文件(缺少文件块)。

在你的代码块之前的某个地方,只需添加以下内容即可:

from PIL import ImageFile
ImageFile.LOAD_TRUNCATED_IMAGES = True

...然后你应该没问题了。

编辑:看起来这对于与Pillow捆绑在一起的PIL版本(“pip install pillow”)有帮助,但可能不适用于默认安装的PIL。


13
出于好奇,这会以某种方式影响解析后的图像吗?PIL不会对被截断的图像发出警告,但是图像会没事吗?我想解决我的问题,但不想得到损坏的图像。 - Pawel Miech
5
Pawel,该图像将使用灰色完成至全尺寸。 - Ctrl-C
3
这可以解决问题,但是在我的图片底部留下了一个难看的白色条。我该如何动态地裁剪掉这个白色条呢? - Daniel Lee
3
我有点震惊这个旧解决方案仍然需要且在PIL/Pillow中默认未被考虑。无论如何,谢谢!对此表示赞赏(实际上我不得不使用imageio来获得类似的错误,导致我发布了这篇文章,因为Pillow只报告了在JpegImageFilefloat之间的无效操作)。 - hyit
在使用 Pytorch 的 torch.utils.data.DataLoader 对图像数据集进行训练时,我来到这里 - 这个解决方案有效。 - Alex Punnen
显示剩余2条评论

16

以下是我所做的:

  • /usr/lib/python3/dist-packages/PIL/ImageFile.py中第40行的LOAD_TRUNCATED_IMAGES = False修改为LOAD_TRUNCATED_IMAGES = True

需要具备管理员权限才能编辑该文件。 我在运行一些使用PIL库的pytorch时遇到了这个错误。

只有在遇到此错误而不直接使用PIL时才执行此修复操作。

否则请执行其他操作。

from PIL import ImageFile
ImageFile.LOAD_TRUNCATED_IMAGES = True

13

最棒的事情是,你可以:

if img and img.meta_type == 'Image':
    pilImg = PIL.Image.open( StringIO(str(img.data)) )
elif imgData:
    pilImg = PIL.Image.open( StringIO(imgData) )

try:
    pilImg.load()
except IOError:
    pass # You can always log it to logger

pilImg.thumbnail((width, height), PIL.Image.ANTIALIAS)

虽然看起来很蠢,但它会像魔法一样运作。如果您的图像缺少数据,它将使用灰色填充(请检查图像底部)。

注意:在Python中不鼓励使用驼峰命名法,仅在类名中使用。


我无法验证它是否有效,问题奇迹般地消失了。但还是谢谢你 :) 我在这里使用了混合大小写(类名大写),但这也不是鼓励的做法... - Georg Pfolz

5
这可能不是PIL的问题。这可能与您的HTTP服务器设置有关。HTTP服务器对将被接受的实体正文大小设置了限制。
例如,在Apache FCGI中,选项FcgidMaxRequestLen确定可以上传的文件的最大大小。
检查一下您的服务器 - 可能就是限制上传大小的那个。

好的观点,但这绝对不是HTTP问题。在我的条件的第一部分中,我访问了一个Zope对象的数据。没有涉及到HTTP请求,数据也正常。 - Georg Pfolz
1
Feroze是正确的-它是由于在数据流链中的某个点修剪数据造成的。一个常见的原因是当将一个命令的输出通过 shell 中的“|”管道传递到另一个命令的输入时,没有刷新输出。它看起来似乎可以工作(没有直接错误),但是会产生修剪过的数据。如果您已经平均修剪了255字节(预计遇到\n),那么很可能是这个原因。它也可能有不同的平均值,取决于文件类型和它的内容字节的规则性(=无论如何都要进行检查;])。 - Ctrl-C

3
我曾经也遇到过相同的问题。然而,在我的情况下,设置 ImageFile.LOAD_TRUNCATED_IMAGES = True 不太适用,而且我已经检查过所有的图像文件都是完整的,只是比较大。
我使用 cv2 读取图像,然后将其转换为 PIL.Image 来解决这个问题。
img = cv2.imread(imgfile, cv2.IMREAD_GRAYSCALE)
img = Image.fromarray(img)

1

当图像部分损坏时,会引发OSError。

我使用以下代码来检查并保存错误的图像列表。

try:
    img = Image.open(file_path)
    img.load()

    ## do the work with the loaded image

except OSError as error:
    print(f"{error} ({file_path})")
    
    with open("./error_file_list.txt", "a") as error_log:
        log.write(str(file_path))

0

我不得不将TDS版本更改为7.2以防止这种情况发生。同时,使用TDS版本8.0也可以,但是我遇到了其他一些问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接