Flasche, um das in der Datenbank gespeicherte Bild zurückzugeben

74

Meine Bilder werden in einer MongoDB gespeichert und ich möchte sie an den Client zurückgeben. Der Code sieht folgendermaßen aus:

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

Es scheint jedoch, dass ich keine Binärdatei direkt in Flask zurückgeben kann. Meine bisherige Idee:

  1. Geben Sie die base64Bildbinärdatei zurück. Das Problem ist, dass IE <8 dies nicht unterstützt.
  2. Erstellen Sie eine temporäre Datei und geben Sie sie mit zurück send_file.

Gibt es bessere Lösungen?

wong2
quelle

Antworten:

127

Erstellen Sie ein Antwortobjekt mit den Daten und legen Sie dann den Inhaltstyp-Header fest. Setzen Sie den Header für die Inhaltsdisposition auf, attachmentwenn der Browser die Datei speichern soll, anstatt sie anzuzeigen.

@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

Relevant: werkzeug.Headers und flask.Response

Sie können ein dateiähnliches Objekt an und die Header-Argumente übergeben, send_filedamit die vollständige Antwort eingerichtet wird. Verwendung io.BytesIOfür Binärdaten:

return send_file(
    io.BytesIO(image_binary),
    mimetype='image/jpeg',
    as_attachment=True,
    attachment_filename='%s.jpg' % pid)
dav1d
quelle
3
Schließt send_file das Dateiobjekt nach dem Senden? Wenn es sich nicht um ein BytesIO handelt, sondern um ein anderes Dateiobjekt, für dessen Schließen ein Aufruf erforderlich ist (), wer ruft es auf?
Baruch
2
Wenn Sie Python 3 und Flask 0.12 verwenden, kann die Bereitstellung einer binären Zeichenfolge ( b'<binary image data>') zu a führen UnicodeError. send_file()kann einfach besser sein.
GergelyPolonkai
1
@ Baruch Use withKlausel?
MrR
43

Ich wollte nur bestätigen, dass der zweite Vorschlag von dav1d richtig ist - ich habe dies getestet (wobei obj.logo ein mongoengine ImageField ist), funktioniert gut für mich:

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()),
                     attachment_filename='logo.png',
                     mimetype='image/png')

Einfacher als das manuelle Erstellen eines Antwortobjekts und das Einstellen seiner Header.

Jaza
quelle
10

Angenommen, ich habe den gespeicherten Bildpfad bei mir. Der folgende Code hilft beim Senden des Bildes.

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

Uploads ist mein Ordnername, in dem mein Bild mit 123.jpg vorhanden ist.

[PS: Der Upload-Ordner sollte sich ab Ihrer Skriptdatei im aktuellen Verzeichnis befinden.]

Ich hoffe es hilft.

Dikshit Kathuria
quelle
4
Was ist, wenn sich das Bild im Speicher befindet?
MrR
2

Folgendes hat für mich (für Python 3.7.3) funktioniert :

import io
import base64
import flask

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 )
Hafizur Rahman
quelle
Wie kann ich diesen Code auf der Serverseite in Javascript dekodieren? Die Zeichenfolge als ASCII codieren, dann die Bytes als Basis 64 dekodieren und als Bild speichern?
QH