Flask返回存储在数据库中的图像

97

我的图像存储在MongoDB中,我想将它们返回给客户端,以下是代码:

@app.route("/images/<int:pid>.jpg")
def getImage(pid):
    # get image binary from MongoDB, which is bson.Binary type
    return image_binary

然而,在 Flask 中好像不能直接返回二进制数?我目前的想法:

  1. 返回图像二进制码的 base64 编码。问题是 IE<8 不支持此方法。
  2. 创建临时文件,然后使用 send_file 返回该文件。

有更好的解决方案吗?


3
可能是如何在Flask响应中返回图像?的重复问题。 - erickrf
4个回答

167

创建一个带有数据的响应对象,然后设置内容类型标头。如果要让浏览器保存文件而不是显示它,请将内容配置标头设置为attachment

@app.route('/images/<int:pid>.jpg')
def get_image(pid):
    image_binary = read_image(pid)
    response = make_response(image_binary)
    response.headers.set('Content-Type', 'image/jpeg')
    response.headers.set(
        'Content-Disposition', 'attachment', filename='%s.jpg' % pid)
    return response

相关文档: werkzeug.Headersflask.Response

你可以传递一个文件对象和头信息给send_file,让它设置完整的响应。对于二进制数据,请使用io.BytesIO:

return send_file(
    io.BytesIO(image_binary),
    mimetype='image/jpeg',
    as_attachment=True,
    download_name='%s.jpg' % pid)

在 Flask 2.0 之前,download_name 被称为 attachment_filename


3
send_file在发送完文件后会关闭文件对象吗?如果它不是BytesIO,而是一些其他需要调用close()的文件对象,谁会调用它? - Baruch
2
使用Python 3和Flask 0.12,提供二进制字符串(b'<binary image data>')可能会导致UnicodeErrorsend_file()可能更好。 - GergelyPolonkai
1
@Baruch 使用 with 子句吗? - MrR
1
尽管涉及到图像的问题,但是这里针对任何文件类型都有content-typeapplication/octet-stream - Alexey Nikonov
使用的导入? - parsecer

55

我只是想确认dav1d的第二个建议是正确的-我测试过了(其中obj.logo是mongoengine的一个ImageField),对我来说运行得很好:

import io

from flask import current_app as app
from flask import send_file

from myproject import Obj

@app.route('/logo.png')
def logo():
    """Serves the logo image."""

    obj = Obj.objects.get(title='Logo')

    return send_file(
        io.BytesIO(obj.logo.read()),
        download_name='logo.png',
        mimetype='image/png'
    )
比手动创建Response对象并设置其标头更容易。 在Flask 2.0之前,“download_name”被称为“attachment_filename”。

14

假设我已经拥有存储的图片路径。下面的代码可以帮助发送图片。

from flask import send_file
@app.route('/get_image')
def get_image():
    filename = 'uploads\\123.jpg'
    return send_file(filename, mimetype='image/jpg')

uploads是我的文件夹名称,其中包含123.jpg图片。

[附注:uploads文件夹应该与您的脚本文件在同一个目录中]

希望这有所帮助。


10
如果图像在内存中,该怎么办? - MrR

6
以下对于我来说可行(适用于Python 3.7.3):
import io
import base64
# import flask
from PIL import Image

def get_encoded_img(image_path):
    img = Image.open(image_path, mode='r')
    img_byte_arr = io.BytesIO()
    img.save(img_byte_arr, format='PNG')
    my_encoded_img = base64.encodebytes(img_byte_arr.getvalue()).decode('ascii')
    return my_encoded_img

...
# your api code
...
img_path = 'assets/test.png'
img = get_encoded_img(img_path)
# prepare the response: data
response_data = {"key1": value1, "key2": value2, "image": img}
# return flask.jsonify(response_data )

使用此代码在服务器端,我如何在JavaScript中解码它?将字符串编码为ASCII,然后将字节解码为Base64并将其保存为图像? - Q.H.
1
你尝试过吗:
  1. https://github.com/axios/axios/issues/513
  2. https://stackabuse.com/encoding-and-decoding-base64-strings-in-node-js/???
- Hafizur Rahman
你好,有没有办法更新以反映显示js部分? - boardkeystown
转换可以通过示例图像的形式展示,该图像已被读取并转换为base64格式,然后再转换回原始格式。'use strict'; const fs = require('fs'); let buff = fs.readFileSync('images/inp.png'); let base64data = buff.toString('base64'); console.log(base64data) let buffOut = new Buffer(base64data, 'base64'); fs.writeFileSync('images/out.png', buffOut); console.log('Base64图像数据已转换为文件:out.png'); 现在你可以找出你在@boardkeystown中的部分。 - Hafizur Rahman
但是这不会返回原始二进制,它会返回base64对吧? - étale-cohomology

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接