2012-10-20 13 views
22

Penso che questo problema non sia legato a Zope. Ciò nonostante, spiegherò cosa sto cercando di fare:Python PIL "IOError: file immagine troncato" con immagini grandi

Sto usando un PUT_factory in Zope per caricare le immagini su ZODB per FTP. L'immagine caricata viene salvata come immagine Zope all'interno di un oggetto contenitore appena creato. Funziona bene, ma voglio ridimensionare l'immagine se supera una certa dimensione (larghezza e altezza). Quindi sto usando la funzione di anteprima di PIL per ridimensionarli, cioè fino a 200x200. Funziona bene finché le immagini caricate sono relativamente piccole. Non ho controllato il limite esatto, ma 976x1296px è ancora ok.

Con le immagini più grandi ottengo:

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

Ho provato un sacco di immagini JPEG della mia macchina fotografica. Non penso che siano tutti troncati.

Ecco il mio codice:

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) 

Come sto usando un PUT_factory, non ho un oggetto file, sto utilizzando i dati grezzi dalla fabbrica o di un creato in precedenza (Zope) Oggetto immagine.

Ho sentito dire che il PIL gestisce i dati delle immagini in modo diverso quando viene superata una certa dimensione, ma non so come regolare il mio codice. O è collegato al caricamento pigro del PIL?

+0

Hai mai risolto questo problema? –

+0

no, non ho :( – Rastaf

risposta

54

Sono un po 'in ritardo per rispondere qui, ma mi sono imbattuto in un problema simile e volevo condividere la mia soluzione. In primo luogo, ecco una abbastanza tipico traccia dello stack per questo problema:

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) 

Se ci guardiamo intorno la linea 220 (nel tuo caso la linea 201, forse si esegue una versione leggermente diversa), vediamo che PIL sta leggendo in blocchi del file e che si aspetta che i blocchi abbiano una certa dimensione. Si scopre che è possibile chiedere a PIL di tollerare i file che vengono troncati (manca qualche file dal blocco) modificando un'impostazione.

Da qualche parte prima del blocco di codice, è sufficiente aggiungere il seguente:

from PIL import ImageFile 
ImageFile.LOAD_TRUNCATED_IMAGES = True 

... e si dovrebbe essere buono.

EDIT: Sembra che questo aiuta per la versione del PIL in bundle con cuscino ("PIP installare cuscino"), ma non può funzionare per le installazioni di default di PIL

+2

solo per curiosità, questo influenzerà in qualche modo l'immagine analizzata? PIL tacerà sulle immagini troncate, ma l'immagine andrà bene? Mi piacerebbe risolvere il mio problema ma non vorrei ottenere immagini danneggiate. –

+0

Pawel, l'immagine sarà completata a grandezza naturale con il colore grigio. –

+2

Questo funziona, ma lascia una barra bianca sgradevole nella parte inferiore della mia immagine. Come posso ritagliare dinamicamente questa barra bianca? –

2

Questo potrebbe non essere un problema PIL. Potrebbe essere correlato alle impostazioni del server HTTP. I server HTTP pongono un limite alle dimensioni del corpo dell'entità che saranno accettate.

Ad esempio, in FCGI Apache, l'opzione FcgidMaxRequestLen determina la dimensione massima del file che può essere caricato.

Controlla che per il tuo server - potrebbe essere quello che limita le dimensioni del caricamento.

+0

Buon punto, ma non è sicuramente un problema HTTP Nella prima parte della mia condizione accedo ai dati di un oggetto Zope. Non c'è nessuna richiesta HTTP coinvolta ei dati sono ok – Rastaf

+0

Feroze ha ragione - è causato dal taglio dei dati su qualche punto della catena del flusso di dati: una causa frequente non è l'output di scarico quando si esegue il piping (tramite "|" in una shell) di un comando per l'input dell'altro. nessun errore diretto) ma vengono prodotti i dati tagliati Se si ha una media di 255 byte tagliati (incontro previsto di \ n), allora molto probabilmente è la causa. Può anche avere una media diversa, a seconda del tipo di file e della regolarità dei byte del contenuto (= ispezionarlo comunque;]). –

10

La cosa migliore è che è possibile:

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) 

Per quanto stupido come sembra - che funzionerà come un miracolo. Se la tua immagine ha dei dati mancanti, sarà riempita di grigio (controlla la parte inferiore dell'immagine).

Nota: l'utilizzo del caso cammello in Python è sconsigliato e viene utilizzato solo nei nomi di classe.

+0

Non riesco a verificare se funziona, il problema è scomparso miracolosamente. Ma grazie comunque :) Ho usato case miste qui (i nomi delle classi sono in maiuscolo), ma non è proprio un incoraggiamento o sia ... – Rastaf

0

ho dovuto cambiare la versione TDS a 7,2 a impedire che ciò accada. Funziona anche con la versione 8.0 di tds, tuttavia ho avuto altri problemi con 8.0.

Problemi correlati