如何在CherryPy中返回HTTP响应的图像

9 投票
4 回答
9924 浏览
提问于 2025-04-16 00:06

我有一段代码可以生成一个Cairo的ImageSurface,我这样把它暴露出来:

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

但是这样不行(浏览器报告说图片有错误)。

我测试过surface.write_to_png('test.png')是可以工作的,但我不太确定该把数据放到哪里才能返回。我在想是不是应该放到某个像文件一样的对象里?根据pycairo的文档get_data()会返回一个缓冲区。我现在也试过:

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

另外,创建并在内存中保存这个图片(就像我现在尝试的那样)和把它写到磁盘上作为临时文件然后从那里提供,哪个更好呢?我只需要这张图片一次,之后就可以丢掉了。

4 个回答

0

试试这个“内存中的文件”方法

return StringIO.StringIO(surface.get_data())
2

你遇到问题是因为你不理解 surface.get_data() 的工作原理。你想要返回的文件类型是 image/png,但是 surface.get_data() 返回的是普通的位图图像(并不是带有头信息的 Windows 位图文件 .BMP),它只是从“虚拟屏幕”(表面)中提取的普通图像数据。

就像这样:

0000010000
0000101000
0001000100
0010000010
0001000100
0000101000
0000010000
18

添加这些导入:

from cherrypy.lib import file_generator
import StringIO

然后这样做:

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)

另外,如果你要提供一个独立的文件(也就是说,它不是网页的一部分),并且你不想让它在浏览器中显示,而是希望它作为一个文件保存到磁盘上,那么你还需要添加一个额外的头部信息:

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

另外,创建并在内存中保存这个图像(就像我现在尝试做的那样)是否更好,还是把它写入磁盘作为临时文件,然后从那里提供?我只需要这个图像一次,之后就可以丢弃了。

如果你唯一想做的就是把这个文件提供给浏览器,那么在服务器上创建这个文件并没有必要。相反,要记住,访问硬盘会带来性能上的损失。

撰写回答