Web2py: Serve images from action call or web service call - python

I am using Web2Py, user images are dynamical and have to be loaded from a different system in the same server therefore they cannot be moved to be contained in the web2py application directory. So I cannot have a relative path to the images. Symbolink links are not an option.
I was thinking the solution could be to serve JPG images from an action call or web service, this way the application can access the local file and return it programatically without having to move a single image. For example a view has the following code:
<li class="file ext_jpg">
<figure class="image_container">
<img src="controller_name/action_serving_images/unique_id_genereted_for_this_image.jpg" alt="">
</figure>
</li>
having the Action:
def action_serving_images(image_id)
#obtain image based on it's unique generated id
return image
Or for the service case:
<li class="file ext_jpg">
<figure class="image_container">
<img src="controller_name/service_serving_images/jpg/image/unique_id_genereted_for_this_image.jpg" alt="">
</figure>
</li>
having the Service:
def service_serving_images():
return service()
#service.jpg
def image(image_id):
#obtain image based on it's unique generated id
return image
Is any of these options possible?
How can I fetch the image and return it as a byte stream with the proper content-type so the browser can render it properly?
Do i need to create a special decorator for JPG in the case of the Service? How?

This is easier than that.
First you create an action like this:
def serve_image():
id = request.args(0)
filename = get_image_filename_from(id)
stream = open(filename,'rb')
return response.stream(stream, attachment=True, filename=filename)
Then in your views you do:
<img src="{{=URL('serve_image',args='1234')}}" />
where 1234 is the id of the image you want.

Related

Form image data, how to handle image?

So I send a Form to my Flask App and wish to receive the Form image data input and pass it to another function.
Example of form:
<form action="https://example.com/api/accept_form" method="POST" enctype="multipart/form-data">
<label for="fileupload"><input type="file" name="fileupload" value="fileupload" id="fileupload" accept="image/*">
Select a file to upload</label>
<br><button id="submit">Post to Instagram</button>
</form>
On the flask app:
def image_function(image):
#DO SOMETHING WITH THE IMAGE
#main.route("/api/accept_form", methods=["POST"])
def manipulate_image():
image = request.form["fileupload"]
image_function(image)
I can see how the image data looks using the print command:
request.files["fileupload"] = <FileStorage: '666650673.jpg' ('image/jpeg')>
request.files["fileupload"].read() = b'\xff\xd8\xff\xe0\x00\x10JFIF\x00\x01\x01\x00\x00H\x00H\x00\x00\xff\xe1\x00 and so on ...'
How do I pass the image to another function in the Flask App as if it was the original .jpg submitted, called from the Flask Apps current directory using "./666650673.jpg"?
References:
https://linuxhint.com/python-string-decode-method/
https://stackoverflow.com/a/2324133/14843373
https://github.com/williballenthin/python-evtx/issues/43
My mistake, as #teddybearsuicide pointed out was that I was passing a file handle and not a file pointer.
Maybe there is a better way but I just saved it locally on the EC2 based on this
Solution
request.files["image"].save("./imageToSave.jpg")
And called it as you would any file in your directory.
image = "./imageToSave.jpg"
I would prefer not to have had to save it so if anyone knows how to pass the file handle directly to achieve the same effect that would be great.

Images Don't Display After Making Layered Webpage

I am using python, html, jinja, java script ect. to build a webapp on a raspberry pi powered device. So far when I put images on my webpages everything works fine. However when I create a "layered" webpage that is using a variable to differentiate between user profile files, it breaks my local image references which wont load and instead display their tag. Using online images for the image source works perfectly fine however.
Not Working Code(Python):
#app.route('/adminPortal/<user_id>', methods=['GET', 'POST'])
def adminPortal(user_id):
print('Admin Portal')
...
Working Code(Python):
#app.route('/adminPortal', methods=['GET', 'POST'])
def adminPortal():
print('Admin Portal')
Unchanged HTML:
<img src="{{ 'static/oldLady.jpg' }}" alt="Profile Pic Of User" height=200px> <span style="display:inline-block; width: 50px;"></span>
<img src="{{'static/' + avatar + '.png'}}" alt="Picture of Avatar" height=200px> <br>
<img src="https://api.time.com/wp-content/uploads/2021/06/Pills.jpg" alt="Picture of Avatar" height=200px> <br>
<img src="{{'static/Amy.png?' + time}}" width="240" usemap="#amymap" class="unselectclass">
So far I have not been able to find any success how I reference the photos, and I don't know how to create the same webpage infrastructure in any other manner than the "layered" system I have set up.
The URL static/oldLady.jpg means "relative to the directory with the current page". If you are rendering /adminPortal, then it means /static/oldLady.jpg. If you are rendering /adminPortal/joe, then it means /adminPortal/static/oldLady.jpg.
The solution is to use absolute URLs: /static/oldLady.jpg.

Cant display images from GridFS, PyMongo

Hi all, im a bit new in Python.
So I have a confused issue for me. I need to store image in database, and after that I have to display each image on client side. Im using Flask for rest request.
So here I have my simpl marckup for submitind
<form action="/upload" method="post" enctype="multipart/form-data">
<label for="image">Select image</label>
<input type="file" name='img' id='image'>
<input type="submit" id='upload_img'>
</form>
and here I get my request and save it to my DB
#app.route("/upload", methods=["POST"])
def upload_image():
# get current image file
img_file = request.files['img']
# get Content Type and File Name of current image
content_type = img_file.content_type
filename = img_file.filename
# save to GridFS my image
# fields <-- recive the id of just saved image
fields = db.FS.put(img_file, content_type=content_type, filename=filename)
# store the filename and _id to another database
# so here we can much morea easaly get image from our GridFS
db.Mongo['images'].insert({"filename": filename, "fields": fields})
return index(images=[])
My simple database model
class db(object):
URI = "mongodb://localhost:27017"
Mongo = None
FS = None
#staticmethod
def initialize():
client = pymongo.MongoClient(db.URI)
db.Mongo= client['gallery']
db.FS = GridFS(Database.DATABASE)
And all saves is successfully.
Retrive my image from DB and try to send it on clietn
#app.route('/get_all_images')
def get_image():
images = db.Mongo['gallery'].find({})
# try to get just a first image _id and fing it at GridFS files
image = db.FS.get(images[0]["fields"])
#send to the client
return index(images=image.read())
Here is markup for display image from the response
<div>
<img src="data:image/png;base64,{{images}}" alt="">
<div>{{images}}</div>
</div>
and finnaly I get something like this enter image description here
the response is look like this:
b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00w\x00\x00\x00\x7f\x08\x06\x00\x00\x00\xd5j]\xe7\x00\x00\x00\x19tEXtSoftware\x00Adobe ImageReadyq\xc9e<\x00\x00\x03"iTXtXML:com.adobe.xmp\x00\x00\x00\x00\x00
The problam is that I cant figute out how to convert this byte format into real image..and display it on a web page directly from database.
I try to make several variants to solve this problam..but in some how my mind is blow up..and I really dont undestand how to work with it.
Thanks for your time :)
IF somebady have any idias or advice how can I show images from database into client side...
I did it! :)
I figured out how to fix this by myself.
Actually the problem was in my response...and in some case on client side too.
Because when I send request from the server, I send the data in byte format,
print(type(image.read()))
<class 'bytes'>
while at the client I suggested the something like binary string
<img src="data:image/png;base64,{{images}}" alt="">
There is my solution code:
import codecs
base64_data = codecs.encode(image.read(), 'base64')
image = base64_data.decode('utf-8')
And on the client I receive the string, which I paste into the img tag...and taddaaaa I got image from my database.
Thanks all who try to help me or figure out how to fix my issue.
I'm not sure that is the best practice, but it works.
P.S. sorry for my English :P

How to Serve a Video (blob) with Google App Angine

I'm trying just for learning how to serve a video with the blobstore without it takes all the screen the video, for example
here I imported Video as video_model
class ViewVideo(webapp.Reque...,blobstore_handlers.BlobstoreDownloadHandler):
def get(self):
video_id = self.request.get('video_id')
video_instance = None
if video_id:
video_instance = video_model().get_video_content(video_id)
self.response.headers['Content-Type'] = 'video/mp4'
self.send_blob(video_instance.content.key())
class Video(db.Model):
content = blobstore.BlobReferenceProperty()
title = db.StringProperty()
def get_video(self,video_id):
return Video.get_by_id(video_id)
def get_video_content(self,content):
query_str = "SELECT * FROM Video WHERE content =:content"
return db.GqlQuery(query_str,content=content).get()
Where the video_id came from a url given, but as you see I put it directly in send_blob() function and this one when I tested it takes all the screen just to see the video, I was wondering how can I serve the video from my application without happening this, I was thinking embedded HTML but I can't figure it out how the source will be
Any help will be grateful
If it lacks of content to answer the question I will edit it
Without HTML5, it's a tricky mess. With HTML5, it becomes easy & elegant. Serve to the user's browser, as part of whatever page you're serving, the following HTML (5) snippet:
<video width="320" height="240" controls>
<source src="/getmp4?video_id=whatever" type="video/mp4">
Your browser does not support the video tag: please upgrade it!
</video>
and use that ViewVideo handler to serve only the /getmp4 URL, not the URL that your user directly gets via their browser.
The 320, 240, and the choice to show controls, are all optional, of course -- as even more is the use of whatever for the video id!-)

Refreshing images on a page without refreshing the whole page with Django

I'm making an application that receives images.
I'm making it in a pretty hacky way, where this is the HTML:
<body onload="javascript:setTimeout('location.reload(true);', 1000);" >
<div class="container">
<img class="img0" src="{{ uno }}"/>
<img class="img1" src="{{ dos }}"/>
<img class="img2" src="{{ tres }}"/>
</div>
</body>
And this is in views.py:
def main(request):
x = get_newest_pics()
uno = x[-1]
dos = x[-2]
tres = x[-3]
context = { 'uno' : uno, 'dos' : dos, 'tres' : tres }
return render(request, 'index.html', context)
I'm sure there's a better way to go about this, but I'm very new to Django and I don't know how. At this point, the page is just flickering every second showing the same images, when really I just want it to refresh whenever there is a new image. Is there a way to consistently call get_newest_pics() and refresh just the images, rather than the whole page? Or even just a way to make the page stop flickering?
The way to do this is to implement ajax on your front end, and then request for new images at an interval, once a new image is found, update the container where you are showing your images and add the new (available) image.
Have a look at the django-dajaxice library to help you with the "wiring" of your front end to django correctly.
The way you have written your code, all three images are sent at once to your page, and your javascript snippet is in effect just refreshing the page very quickly, which is why you see the flickering effect.
You could do a "hack" and create a separate view for each image in django, then call each view on an interval using javascript - it would have the same end result but really inefficient in terms of code.

Categories