0

I have an endpoint which downloads an image from an URL, stores it in the project directory and returns the image on the web page. But I don't want the image to be stored in my project directory. is there a way? if not, is there a way to remove the image after the method is executed?

@app.route('/get_image', methods=['GET'])
def get_image():

    r = requests.get("Certain URL")
    file = open("sample.png", "wb")
    file.write(r.content)
    file.close()
    
    return send_file("sample.png", mimetype='image/gif')
Arad
  • 116
  • 9
  • One approach is to store the images in their own folder, and have a process that periodically cleans out the folder. Alternatively, Flask's `send_file` will accept a file object, so you could use an `io.BytesIO` object to store the contents and pass that to `send_file`. The object will get cleaned up by Python. – Tim Roberts Jun 16 '21 at 18:29
  • this problem was many times on Stackoverflow - for different files. – furas Jun 16 '21 at 20:48
  • you shouldn't send `.png` as `'image/gif'` but as `'image/png'` – furas Jun 16 '21 at 20:53

2 Answers2

2

As @TimRoberts said in comment you would have to use io.BytesIO to create file-like object in memory, write in this file and later read from this file.

    r = requests.get("https://placekitten.com/640/360")

    file_like_object = io.BytesIO()
    file_like_object.write(r.content)
    file_like_object.seek(0)  # move to the beginning of file 

    return send_file(file_like_object, mimetype='image/png')

or shorter

    r = requests.get("https://placekitten.com/640/360")

    file_like_object = io.BytesIO(r.content)

    return send_file(file_like_object, mimetype='image/png')

And this can be usefull if you want to generate files instead of getting from server - ie. plot with matplotlib, image with pillow, audio from some TextToSpeech API, etc.

You could find many examples on Stackoverflow.


But if you don't want to edit file then there is even simpler method.

Using requests.get(..., stream=True) you may get r.raw which is file-like object.

    r = requests.get("https://placekitten.com/640/360", stream=True)

    file_like_object = r.raw

    return send_file(file_like_object, mimetype='image/png')

Minimal working code with both versions, and with real URL so everyone can copy and run it:

EDIT: I added example which resize image without saving on disk.

from flask import Flask, render_template_string, send_file
import requests
import io
from PIL import Image

app = Flask(__name__)

@app.route('/')
def index():
    return render_template_string('''
<img src="/get_image">get_image<br/>
<img src="/get_image_bytesio">get_image_bytesio<br/>
<img src="/get_image_bytesio_smaller">get_image_bytesio_smaller<br/>
''')

@app.route('/get_image')
def get_image():
    r = requests.get("https://placekitten.com/640/360", stream=True)  # it needs `stream=True`
    
    file_like_object = r.raw
    
    return send_file(file_like_object, mimetype='image/png')

@app.route('/get_image_bytesio')
def get_image_bytesio():
    r = requests.get("https://placebear.com/640/360")
    
    #file_like_object = io.BytesIO()
    #file_like_object.write(r.content)
    #file_like_object.seek(0)  # move to the beginning of file after writing

    file_like_object = io.BytesIO(r.content)

    return send_file(file_like_object, mimetype='image/png')

@app.route('/get_image_bytesio_smaller')
def get_image_bytesio_smaller():
    r = requests.get("https://placebear.com/640/360")
    
    file_like_object = io.BytesIO(r.content)

    # edit image without saving on disk    
    img = Image.open(file_like_object)
    img = img.resize((320, 180))

    # `seek()` has to be after `resize()` because it may use `lazy loading`
    
    file_like_object.seek(0)  # move to the beginning of file after reading
    img.save(file_like_object, 'PNG')
    
    file_like_object.seek(0)  # move to the beginning of file after writing
    
    return send_file(file_like_object, mimetype='image/png')

if __name__ == '__main__':
    #app.debug = True 
    app.run() 
furas
  • 134,197
  • 12
  • 106
  • 148
-1

As far as I know, you can't send something without having it on your system. You can pass on the reference/link, but you can't make the server that's hosting it send it for you.

So your best bet is to delete it.

import os
if os.path.exists("theimage.img"):
  os.remove("theimage.img")
else:
  print("The file does not exist")

Now, you could do this as a separate view: create a Delete method view, send the request with the filename from a hidden form on your page. But that could get really messy (i.e. the timing on that might workout that you're deleting the file before you're done sending it).

I think you maybe want to store the images in a specific folder, and delete all of the images in that folder on a certain interval.

Here is a question/answer on how to implement an app scheduler. But that may even be more than you need. What you're looking to schedule is a fairly simple task.

Cron is a system process that can schedule tasks for you. It's pretty straightforward.

Crontab is the python friendly version.

CVerica
  • 327
  • 1
  • 10