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')
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.
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()
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')
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.
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()