2010-06-17 10 views
7

tengo código que genera un ImageSurface El Cairo, y exponerlo así:Cómo devolver una imagen en una respuesta 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 

Esto no funciona (navegadores informar que la imagen tiene errores)

He probado que surface.write_to_png('test.png') obras, pero no estoy seguro de lo que para volcar los datos en devolverlo. Estoy adivinando algún objeto parecido a un archivo? De acuerdo con the pycairo documentation, get_data() devuelve un buffer. También he intentado ahora:

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

Además, es mejor crear y mantener esta imagen en la memoria (como yo estoy tratando de hacer) o escribir en el disco como un archivo temporal y se sirve a partir de ahí ? Solo necesito la imagen una vez, luego puede descartarse.

+0

¿Qué tal 'write_to_png_stream'? No parece http://cairographics.org/documentation/cairomm/reference/classCairo_1_1Surface.html#b3eca5bc13abe27f470fdf08134269bb –

+0

PyCairo para exponer ese método ... http://cairographics.org/documentation/pycairo/2/reference/surfaces. html # class-imagesurface-surface – colinmarc

Respuesta

15

Añadir estas importaciones:

from cherrypy.lib import file_generator 
import StringIO 

y luego ir así:

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) 

Adicionalmente, si estás que sirve un archivo independiente (es decir, no forma parte de una página web) y no desea que se muestre en el navegador sino que se lo trate como un archivo en guardar en un disco, entonces necesita una más cabecera:

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

Además, es mejor crear y mantener esta imagen en la memoria (como que estoy tratando de hacer ) o escribirlo en el disco como un archivo temp y lo sirve desde allí? Solo necesita la imagen una vez, luego puede ser descartada.

Si lo único que desea hacer es publicar este archivo en un navegador, no hay razón para crearlo en un disco en el servidor. Todo lo contrario: recuerde que acceder al disco duro implica una penalización en el rendimiento.

+0

¡Funciona muy bien! Por la recompensa, ¿podrías explicarme por qué? – colinmarc

+0

Excelente respuesta, zifot: creo que la clave está usando "write_to_png", que convierte los datos sin procesar a formato PNG. El solo uso de surface.get_data() no funcionará porque no está almacenado internamente como datos PNG (es ARGB_32). –

+0

@Marc Novakowski - Gracias. Tiene razón, ImageSurface guarda los datos en la memoria en uno de los formatos descritos aquí: http://cairographics.org/manual/cairo-image-surface.html#cairo-format-t. El formato del archivo de salida es una historia diferente. – zifot

0

Ha intentado return str(surface.get_data())?

+0

acaba de probar, no funcionó. – colinmarc

0

Prueba esto para 'archivo en la memoria' enfoque

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

Todavía no hubo suerte ... – colinmarc

1

Usted está fallando, porque de no comprender el funcionamiento de surface.get_data(). Usted está tratando de volver tipo MIME image/pngsurface.get_data() pero vuelve imagen de mapa de bits normal (no es un archivo .BMP Widnows memoria de imagen con cabecera), que es evidente volcado imagen de "pantalla virtual" (superficie)

De esta manera:

 
0000010000 
0000101000 
0001000100 
0010000010 
0001000100 
0000101000 
0000010000 
Cuestiones relacionadas