2010-06-17 5 views
7

Ho codice che genera un Cairo ImageSurface, e che è stato esposto in questo modo:Come restituire un'immagine in una risposta HTTP con CherryPy

def preview(...): 
    surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, width, height) 
    ... 
    cherrypy.response.headers['Content-Type'] = "image/png" 
    return surface.get_data() 
preview.exposed = True 

Questo non funziona (i browser segnalare che l'immagine contiene errori).

Ho provato che surface.write_to_png('test.png') funziona, ma non sono sicuro su cosa riversare i dati per restituirli. Sto indovinando un oggetto simile a un file? Secondo the pycairo documentation, get_data() restituisce un buffer. Ho anche provato ora:

tempf = os.tmpfile() 
surface.write_to_png(tempf) 
return tempf 

Inoltre, è meglio per creare e mantenere questa immagine nella memoria (come sto cercando di fare) o scrivere su disco come file temporaneo e servire da lì ? Ho solo bisogno dell'immagine una volta, quindi può essere scartata.

+0

E a proposito di 'write_to_png_stream'? http://cairographics.org/documentation/cairomm/reference/classCairo_1_1Surface.html#b3eca5bc13abe27f470fdf08134269bb –

+0

pycairo non sembra esporre questo metodo ... http://cairographics.org/documentation/pycairo/2/reference/surfaces. html # class-imagesurface-surface – colinmarc

risposta

15

aggiungere queste importazioni:

from cherrypy.lib import file_generator 
import StringIO 

e poi andare in questo modo:

def index(self): 
    surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, width, height) 
    cherrypy.response.headers['Content-Type'] = "image/png" 

    buffer = StringIO.StringIO() 
    surface.write_to_png(buffer) 
    buffer.seek(0) 

    return file_generator(buffer) 

Additionaly, se siete serve file autonomo (cioè non fa parte di una pagina web) e non vuoi che venga reso nel browser ma piuttosto trattato come un file per salvare su un disco, allora avete bisogno di un altro colpo di testa:

cherrypy.response.headers['Content-Disposition'] = 'attachment; filename="file.png"' 

Inoltre, è meglio per creare e mantenere questa immagine nella memoria (come sto cercando di fare ) o scrivere su disco come un file temp e servirlo da lì? Io ho solo bisogno diimmagine, quindi può essere scartato .

Se l'unica cosa che si vuole fare è pubblicare questo file su un browser non c'è motivo di crearlo su un disco sul server. Al contrario, ricorda che l'accesso all'hard disk comporta una penalizzazione delle prestazioni.

+0

Funziona alla grande! Per la taglia, potresti spiegarmi perché? – colinmarc

+0

Ottima risposta, zifot - Penso che la chiave stia usando "write_to_png" che converte i dati grezzi in formato PNG. Il solo uso di surface.get_data() non funzionerà perché non è memorizzato internamente come dati PNG (è ARGB_32). –

+0

@Marc Novakowski - Grazie. Hai ragione, ImageSurface conserva i dati in memoria in uno dei formati descritti qui: http://cairographics.org/manual/cairo-image-surface.html#cairo-format-t. Il formato del file di output è una storia diversa. – zifot

0

Hai provato return str(surface.get_data())?

+0

appena provato, non ha funzionato. – colinmarc

0

Prova questo per 'file nella memoria' approccio

return StringIO.StringIO(surface.get_data()) 
+0

Ancora senza fortuna ... – colinmarc

1

Si sta fallendo a causa di non capire il funzionamento di surface.get_data(). Si sta tentando di tornare mime-type image/png ma surface.get_data() rendimenti immagine bitmap semplice (non è un file di BMP Widnows bitmap con l'intestazione), che è semplice discarica immagine da "schermo virtuale" (di superficie)

Come questo:

 
0000010000 
0000101000 
0001000100 
0010000010 
0001000100 
0000101000 
0000010000