Как вернуть изображение в HTTP-ответе с помощью CherryPy


У меня есть код, который генерирует Каир 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 7

4 ответа:

Добавьте следующие импортные операции:

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"'

Также, лучше ли создавать и удерживать этот образ в памяти (как я пытаюсь делать) или записать его на диск в качестве темпа подать и подать его оттуда? Я только нужен образ один раз, тогда это может быть отброшенный.

Если единственное, что вы хотите сделать, это передать этот файл браузеру, нет никаких причин создавать его на диске на сервере. Совсем наоборот-помните, что доступ к жесткому диску приводит к снижению производительности.

Вы терпите неудачу из-за непонимания работы surface.get_data(). Вы пытаетесь вернуть mime-тип image/png, но surface.get_data() возвращает простое растровое изображение (не является растровым файлом Windows .BMP с заголовком) который это обычный дамп изображения с "виртуального экрана" (surface)

Вот так:

0000010000
0000101000
0001000100
0010000010
0001000100
0000101000
0000010000

Вы пробовали return str(surface.get_data())?

Попробуйте это для подхода "файл в памяти"

return StringIO.StringIO(surface.get_data())