39

Tôi đang sử dụng bình cho ứng dụng của mình. Tôi muốn gửi một hình ảnh (được tạo động bởi PIL) cho khách hàng mà không lưu trên đĩa.Làm thế nào để gửi hình ảnh được tạo bởi PIL tới trình duyệt?

Bất kỳ ý tưởng nào về cách thực hiện việc này?

+1

Bình dường như không có hỗ trợ vững chắc để phát trực tuyến dữ liệu nhị phân mà bạn có thể không tạo ra bằng trình tạo Python. Có thể bạn sẽ phải đệm hình ảnh trong bộ nhớ và gửi đi. – millimoose

Trả lời

16

Trước tiên, bạn có thể lưu hình ảnh vào một tempfile và loại bỏ các tập tin địa phương (nếu có):

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) 

Thứ hai, thiết lập các tập tin tạm thời để phản ứng (theo 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 
+0

Không hoạt động nữa: 'LoạiError: đối tượng 'tệp' không thể gọi được là – letmaik

+0

@neo - Cảm ơn, đã cập nhật tới send_file –

+0

Tệp động được tạo ở đây là gì? – user1953366

7

Tôi cũng đang gặp khó khăn trong cùng một tình huống. Cuối cùng, tôi đã tìm thấy giải pháp của nó bằng cách sử dụng một ứng dụng WSGI, một đối tượng được chấp nhận cho "make_response" làm đối số của nó.

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) 

Vui lòng thay thế các hoạt động "mở hình ảnh" bằng các hoạt động PIL thích hợp.

+0

Điều này hoạt động đẹp :) – cybertoast

7

Nó chỉ ra rằng bình cung cấp một giải pháp (RTM để bản thân mình!):

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

Dưới đây là một phiên bản mà không cần file tạm và các loại tương tự (xem 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') 

Để sử dụng trong mã của bạn chỉ cần thực hiện

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

Đây là một câu trả lời vượt trội hơn nhiều so với câu trả lời được chấp nhận. – jrs

+0

Có nghĩa là bạn phải có thể giữ toàn bộ hình ảnh trong bộ nhớ cùng một lúc, phải không? Có thể là một vấn đề với hình ảnh lớn hoặc các loại tải xuống khác. – Eli

+0

@Eli cho những trường hợp đó có vẻ hợp lý hơn khi sử dụng tệp tạm thời. Dù sao, các tệp được tạo động rất lớn không phổ biến. – erickrf

Các vấn đề liên quan