web-dev-qa-db-fra.com

Comment envoyer une image générée par PIL vers un navigateur?

J'utilise flask pour mon application. Je voudrais envoyer une image (générée dynamiquement par PIL) au client sans enregistrer sur le disque.

Une idée de comment faire ça?

47
user795243

Tout d'abord, vous pouvez enregistrer l'image dans un tempfile et supprimer le fichier local (si vous en avez un):

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)

Ensuite, définissez le fichier temporaire sur la réponse (selon cette question de stackoverflow ):

from flask import send_file

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

Voici une version sans aucun fichier temporaire et similaire (voir ici ):

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

Pour utiliser dans votre code, faites simplement

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

M. M. a effectivement fait un excellent travail. J'ai dû utiliser BytesIO () au lieu de 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')
7
Dan Erez

Je me débattais également dans la même situation. Enfin, j'ai trouvé sa solution en utilisant une application WSGI, qui est un objet acceptable pour "make_response" comme argument.

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)

Veuillez remplacer les opérations "image d'ouverture" par des opérations PIL appropriées.

7
cocoatomo

Il s'avère que flask fournit une solution (rtm pour moi-même!):

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