Return an image taken from an URL without storing the image file

Question:

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')
Asked By: Arad

||

Answers:

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.

Answered By: CVerica

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">
<img src="/get_image_bytesio">
<img src="/get_image_bytesio_smaller">
''')

@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
    
    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()
    file_like_object.write(r.content)
    file_like_object.seek(0)  # move to the beginning of file after writing

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

    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() 
Answered By: furas
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.