How to send image generated by PIL to browser?

Question:

I’m using flask for my application. I’d like to send an image (dynamically generated by PIL) to client without saving on disk.

Any idea how to do this ?

Asked By: user795243

||

Answers:

First, you can save the image to a tempfile and remove the local file (if you have one):

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)

Second, set the temp file to the response (as per this stackoverflow 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
Answered By: Adam Morris

I was also struggling in the same situation. Finally, I have found its solution using a WSGI application, which is an acceptable object for “make_response” as its 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)

Please replace “opening image” operations with appropriate PIL operations.

Answered By: cocoatomo

It turns out that flask provides a solution (rtm to myself!):

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

Here’s a version without any temp files and the like (see 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')

To use in your code simply do

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

Mr. Mr. did an excellent job indeed. I had to use BytesIO() instead of 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')
Answered By: Dan Erez
        return send_file(fileName, mimetype='image/png')
Answered By: Gank