如何将 PIL 生成的图像发送到浏览器?

Posted

技术标签:

【中文标题】如何将 PIL 生成的图像发送到浏览器?【英文标题】:How to send image generated by PIL to browser? 【发布时间】:2011-12-14 04:55:46 【问题描述】:

我正在为我的应用程序使用烧瓶。我想将图像(由 PIL 动态生成)发送到客户端而不保存在磁盘上。

知道怎么做吗?

【问题讨论】:

Flask 似乎没有对流式二进制数据的可靠支持,而您无法使用 Python 生成器生成这些数据。您可能必须在内存中缓冲图像并发送它。 【参考方案1】:

这是一个没有任何临时文件等的版本(请参阅here):

def serve_pil_image(pil_img):
    img_io = StringIO()
    pil_img.save(img_io, 'JPEG', quality=70)
    img_io.seek(0)
    return send_file(img_io, mimetype='image/jpeg')

要在您的代码中使用,只需这样做

@app.route('some/route/')
def serve_img():
    img = Image.new('RGB', ...)
    return serve_pil_image(img)

【讨论】:

意味着你必须能够一次将整个图像保存在内存中,对吧?可能是大图像或其他类型下载的问题。 如何将其插入到我返回的模板中? Python3 需要使用 ByteIO:fadeit.dk/blog/post/python3-flask-pil-in-memory-image 我现在如何在img 标签的src 属性中引用文件 对于那些询问如何在img 标记的src 属性中引用文件的人,只需使用将提供图像@app.route('/docs/<filename>') 的端点,然后在html 中使用`src= "/docs/some_img.jpg"【参考方案2】:

先生。先生确实做得很好。我不得不使用 BytesIO() 而不是 StringIO()。

def serve_pil_image(pil_img):
    img_io = BytesIO()
    pil_img.save(img_io, 'JPEG', quality=70)
    img_io.seek(0)
    return send_file(img_io, mimetype='image/jpeg')

【讨论】:

我遇到了一个问题,即 BytesIO 不是字符串,send_file 需要一个字符串作为路径。如何从 BytesIO 对象中获取路径? 我认为字节作为 8 位对象出现,可以解释为字符串。无论如何 - 我不确定为什么它不适合你,试试 StringIO() 吧? 它实际上工作正常,我只是没有在我的 html 中正确引用它。现在使用url_for(),它工作正常。 我有这样的设置,但是当我在 docker 中运行我的应用程序时,我得到RuntimeError: Attempted implicit sequence conversion but the response object is in direct passthrough mode. 任何想法在哪里设置它?【参考方案3】:

首先,您可以将图像保存到tempfile 并删除本地文件(如果有的话):

from tempfile import NamedTemporaryFile
from shutil import copyfileobj
from os import remove

tempFileObj = NamedTemporaryFile(mode='w+b',suffix='jpg')
pilImage = open('/tmp/myfile.jpg','rb')
copyfileobj(pilImage,tempFileObj)
pilImage.close()
remove('/tmp/myfile.jpg')
tempFileObj.seek(0,0)

其次,将临时文件设置为响应(根据this *** question):

from flask import send_file

@app.route('/path')
def view_method():
    response = send_file(tempFileObj, as_attachment=True, attachment_filename='myfile.jpg')
    return response

【讨论】:

不再工作:TypeError: 'file' object is not callable 这里动态创建的文件是什么? @user1953366 - 在这个例子中,正在创建的文件是 myfile.jpg,但我会认真检查下面的 mr-mr 的答案,因为它不需要创建临时文件更有效. 临时文件也写入磁盘?这是如何被接受的响应?【参考方案4】:

原来flask提供了一个解决方案(rtm给我自己!):

from flask import abort, send_file
try:
    return send_file(image_file)
except:
    abort(404)

【讨论】:

【参考方案5】:

我也在同样的情况下苦苦挣扎。最后,我找到了使用 WSGI 应用程序的解决方案,它是“make_response”作为其参数的可接受对象。

from Flask import make_response

@app.route('/some/url/to/photo')
def local_photo():
    print('executing local_photo...')
    with open('test.jpg', 'rb') as image_file:
        def wsgi_app(environ, start_response):
            start_response('200 OK', [('Content-type', 'image/jpeg')])
            return image_file.read()
        return make_response(wsgi_app)

请将“打开图像”操作替换为适当的 PIL 操作。

【讨论】:

【参考方案6】:
        return send_file(fileName, mimetype='image/png')

【讨论】:

以上是关于如何将 PIL 生成的图像发送到浏览器?的主要内容,如果未能解决你的问题,请参考以下文章

如何在屏幕上显示 PIL 图像?

如何在 Python 中使用 PIL 将图像合成到另一个图像上?

如何使用 PIL 将 PNG 图像写入字符串?

通过套接字发送pil图像而不保存python

如何将服务器生成的音频 wav 文件发送到客户端浏览器? [关闭]

如何使用 Postman 将图像发送到烧瓶服务器