Estoy usando matraz para mi aplicación. Me gustaría enviar una imagen (generada dinámicamente por PIL) al cliente sin guardar en el disco.¿Cómo enviar imágenes generadas por PIL al navegador?
¿Alguna idea de cómo hacer esto?
Estoy usando matraz para mi aplicación. Me gustaría enviar una imagen (generada dinámicamente por PIL) al cliente sin guardar en el disco.¿Cómo enviar imágenes generadas por PIL al navegador?
¿Alguna idea de cómo hacer esto?
En primer lugar, se puede guardar la imagen en un tempfile y eliminar el archivo local (si lo tiene):
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)
En segundo lugar, establecer el archivo temporal de la respuesta (según 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
Ya no funciona: 'TypeError: 'file' object no se puede llamar' – letmaik
@neo - Gracias, actualizado a send_file –
¿Cuál es el archivo creado dinámicamente aquí? – user1953366
También estaba luchando en la misma situación. Finalmente, encontré su solución usando una aplicación WSGI, que es un objeto aceptable para "make_response" como argumento.
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)
Reemplace las operaciones de "apertura de la imagen" con las operaciones de PIL apropiadas.
Esto funciona maravillosamente :) – cybertoast
Resulta que frasco proporciona una solución (RTM a mí mismo!):
from flask import abort, send_file
try:
return send_file(image_file)
except:
abort(404)
Aquí hay una versión sin ningún tipo de archivos temporales y similares (ver 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')
Para usar en su código simplemente haga
@app.route('some/route/')
def serve_img():
img = Image.new('RGB', ...)
return serve_pil_image(img)
Esta es una respuesta muy superior a la respuesta aceptada. – jrs
Significa que tienes que ser capaz de mantener toda la imagen en la memoria de una vez, ¿verdad? Podría ser un problema con imágenes enormes u otros tipos de descargas. – Eli
@Eli para esos casos, parece más sensato usar un archivo temporal. De todos modos, los enormes archivos generados dinámicamente no son comunes. – erickrf
Flask no parece tener un soporte sólido para la transmisión de datos binarios que pueda Generar con un generador de Python. Probablemente tendrá que almacenar la imagen en la memoria y enviarla. – millimoose