How to return an image in an HTTP response with CherryPy

colinmarc picture colinmarc · Jun 17, 2010 · Viewed 9k times · Source

I have code which generates a Cairo ImageSurface, and I expose it like so:

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

This doesn't work (browsers report that the image has errors).

I've tested that surface.write_to_png('test.png') works, but I'm not sure what to dump the data into to return it. I'm guessing some file-like object? According to the pycairo documentation, get_data() returns a buffer. I've also now tried:

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

Also, is it better to create and hold this image in memory (like I'm trying to do) or write it to disk as a temp file and serve it from there? I only need the image once, then it can be discarded.

Answer

zifot picture zifot · Jun 20, 2010

Add these imports:

from cherrypy.lib import file_generator
import StringIO

and then go like this:

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, if you're serving standalone file (i.e. it's not a part of a web page) and you don't want it to be rendered into browser but rather treated as a file to save on a disk then you need one more header:

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

Also, is it better to create and hold this image in memory (like I'm trying to do) or write it to disk as a temp file and serve it from there? I only need the image once, then it can be discarded.

If the only thing you want to do is to serve this file to a browser there is no reason to create it on a disk on the server. Quite the contrary - remember that accessing hard disk brings performance penalty.