web-dev-qa-db-fra.com

Python PIL "IOError: fichier image tronqué" avec de grandes images

Je pense que ce problème n'est pas lié à Zope. Je vais néanmoins expliquer ce que j'essaie de faire:

J'utilise une PUT_factory dans Zope pour télécharger des images vers la ZODB par FTP. L'image téléchargée est enregistrée en tant qu'image Zope dans un objet conteneur nouvellement créé. Cela fonctionne bien, mais je veux redimensionner l'image si elle dépasse une certaine taille (largeur et hauteur). J'utilise donc la fonction de vignette de PIL pour les redimensionner, c'est-à-dire à 200x200. Cela fonctionne bien tant que les images téléchargées sont relativement petites. Je n'ai pas vérifié la limite exacte, mais 976x1296px est toujours correct.

Avec de plus grandes images, j'obtiens:

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

J'ai testé beaucoup de jpegs de mon appareil photo. Je ne pense pas qu'ils soient tous tronqués.

Voici mon code:

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)

Comme j'utilise une PUT_factory, je n'ai pas d'objet fichier, j'utilise soit les données brutes de l'usine, soit un objet Image créé précédemment (Zope).

J'ai entendu dire que PIL traite les données d'image différemment lorsqu'une certaine taille est dépassée, mais je ne sais pas comment ajuster mon code. Ou est-ce lié au chargement paresseux de PIL?

51
Rastaf

Je suis un peu en retard pour répondre ici, mais j'ai rencontré un problème similaire et je voulais partager ma solution. Tout d'abord, voici une trace de pile assez typique pour ce problème:

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)

Si nous regardons autour de la ligne 220 (dans votre cas, la ligne 201 - vous utilisez peut-être une version légèrement différente), nous voyons que PIL lit des blocs du fichier et qu'il s'attend à ce que les blocs soient d'une certaine taille. Il s'avère que vous pouvez demander à PIL d'être tolérant avec les fichiers tronqués (il manque un fichier du bloc) en modifiant un paramètre.

Quelque part avant votre bloc de code, ajoutez simplement ce qui suit:

from PIL import ImageFile
ImageFile.LOAD_TRUNCATED_IMAGES = True

... et tu devrais être bon.

EDIT: Il semble que cela aide la version de PIL fournie avec Pillow ("pip install pillow"), mais peut ne pas fonctionner pour les installations par défaut de PIL

127
abhillman

La meilleure chose est que vous pouvez:

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)

Aussi stupide que cela puisse paraître - cela fonctionnera comme un miracle. Si votre image manque de données, elle sera remplie de gris (vérifiez le bas de votre image).

Remarque: l'utilisation du cas de chameau dans Python est déconseillé et n'est utilisé que dans les noms de classe.

12
Ctrl-C

Ce n'est peut-être pas un problème PIL. Il peut être lié à votre paramètre de serveur HTTP. Les serveurs HTTP imposent une limite à la taille du corps d'entité qui sera accepté.

Par exemple, dans Apache FCGI, l'option FcgidMaxRequestLen détermine la taille maximale du fichier qui peut être téléchargé.

Vérifiez cela pour votre serveur - il peut s'agir de celui qui limite la taille de téléchargement.

2
feroze

J'ai dû changer la version tds en 7.2 pour éviter que cela ne se produise. Fonctionne également avec tds version 8.0, mais j'ai eu d'autres problèmes avec 8.0.

0
stuartz