Python PIL "IOError: файл изображения усечен" с большими изображениями
Я думаю, что эта проблема не связана с Zope. Тем не менее я объясню, что я пытаюсь сделать:
Я использую PUT_factory в Zope для загрузки изображений на ZODB на FTP. Загруженное изображение сохраняется как изображение Zope внутри вновь созданного объекта контейнера. Это отлично работает, но я хочу изменить размер изображения, если оно превышает определенный размер (ширина и высота). Поэтому я использую функцию миниатюр PIL для изменения их размера, то есть до 200x200. Это прекрасно работает, пока загруженные изображения относительно невелики. Я не проверял точный предел, но 976x1296px все еще в порядке.
С большими снимками я получаю:
Module PIL.Image, line 1559, in thumbnail
Module PIL.ImageFile, line 201, in load
IOError: image file is truncated (nn bytes not processed).
Я проверил много jpegs с моей камеры. Я не думаю, что все они урезаны.
Вот мой код:
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, у меня нет файлового объекта, я использую либо необработанные данные из factory, либо ранее созданного объекта Zope.
Я слышал, что PIL обрабатывает данные изображения по-разному, когда определенный размер превышен, но я не знаю, как настроить свой код. Или это связано с ленивой загрузкой PIL?
Ответы
Ответ 1
Я немного опоздал, чтобы ответить здесь, но у меня возникла аналогичная проблема, и я хотел поделиться своим решением. Во-первых, здесь довольно типичная трассировка стека для этой проблемы:
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
... и вы должны быть хорошими.
EDIT: похоже, что это помогает для версии PIL в комплекте с подушкой ( "подушка для установки подушек" ), но может не работать для стандартных установок PIL
Ответ 2
Лучше всего то, что вы можете:
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 не рекомендуется и используется только в именах классов.
Ответ 3
Это может быть не проблема PIL. Это может быть связано с настройкой вашего HTTP-сервера. HTTP-серверы устанавливают ограничение на размер тела объекта, который будет принят.
Например, в Apache FCGI параметр FcgidMaxRequestLen определяет максимальный размер файла, который можно загрузить.
Проверьте, что для вашего сервера это может быть ограничение размера выгрузки.
Ответ 4
Мне пришлось изменить версию tds на 7.2, чтобы это не происходило. Также работает с tds версии 8.0, однако у меня были некоторые другие проблемы с 8.0.