How can I display PIL image to html with render_template flask? - html

I tried to display my edited image with PIL package, when I tried to make it to display on the html <img src=''></img> it doesn't appear anything, but I see the file name on inspect elements was <img src="<_io.BytesIO object at 0x000001EDA8F76E00>">. How do I make the edited image display properly?
app.py
#app.route("/api/games/shipper/image/", methods=["GET"])
def games_shipper():
... # My stuff up here
image_io = BytesIO()
img.save(image_io, "PNG")
image_io.seek(0)
return render_template('image.html', image_data=image_io)
image.html
... // My stuff up here
<body>
<center>
<image src="{{ image_data }}"></image>
</center>
</body>

You can read the data from the buffer with the getvalue() function and then convert it. The base64 encoded data can then be passed to the src parameter as a data url.
from base64 import b64encode
#app.route("/api/games/shipper/image/", methods=["GET"])
def games_shipper():
... # My stuff up here
image_io = BytesIO()
img.save(image_io, 'PNG')
dataurl = 'data:image/png;base64,' + b64encode(image_io.getvalue()).decode('ascii')
return render_template('image.html', image_data=dataurl)
If you pass the image as a dataurl, there is no way to shrink the string. However, there is the possibility of serving the file as pure image data. You can use send_file in another endpoint for this. You serve the page (template) in one endpoint and the image file in a second.
from flask import send_file
#app.route('/')
def index():
return render_template('index.html')
#app.route('/image')
def game_shipper():
# ...
image_io = io.BytesIO()
img.save(image_io, format='PNG')
image_io.seek(0)
return send_file(
image_io,
as_attachment=False,
mimetype='image/png'
)
<body>
<center>
<img src="{{ url_for('game_shipper') }}" />
</center>
</body>

You'll need to encode your image in Base64 to display it in the img tag directly, see e.g. How to display Base64 images in HTML
The traditional way to display images in Flask templates is to save the image in Flask's static folder and link to it in your template like so
<body>
<center>
<image src="/static/{{image_name}}.png"></image>
</center>
</body>

Related

Image not showing up in the browser

Here's what Im trying to do.. The images I save on the database are going to the correct path. But they don't show up in the site.
#blogs.route("/post/new", methods=['GET', 'POST'])
def new_post():
if ('user' in session and session['user'] == params["username"]):
form = PostForm()
if form.validate_on_submit():
pic = save_picture(request.files['pic'])
post = Post(title=form.title.data,
content=form.content.data, img=pic)
db.session.add(post)
db.session.commit()
flash('Your post has been created!', 'success')
image_file = url_for('static', filename = 'profile_pics/' + pic)
return render_template('post.html',image_file=image_file)
return render_template('create_post.html', title='New Post',
form=form)
return "please login to the dashboard first. Dont try to enter without logging in!"
The HTML side
<img src="{{image_file}}" alt="error">
Found a fix!!
I figured out that one can use the set keyword from python as a variable to store the post.img in it and then refer it inside the source.
{% set img_name = 'profile_pics/' + post.img %}
<img src="{{url_for('static', filename = img_name)}}" alt="error">
This would be the route function:
image_file = url_for('static', filename='profile_pics/' + post.img)
return render_template('template.html', image_file=image_file)
and this is what it looks like in the template:
<img src="{{ image_file }}">
The issue is probably that You are not really able to have nested variables inside html especially because jinja probably interpreted that as a literal string

How to send a string from python to HTML element using Flask

How to send a sting text data from a python script to a specific HTML element. So that I can display it to users clearly and in a certain place using Flask Python library.
python script
#app.route('/services', methods=['POST', 'GET'])
def upload_image():
if 'file' not in request.files:
flash('No file part')
return redirect(request.url)
file = request.files['file']
if file.filename == '':
flash('No image selected for uploading')
return redirect(request.url)
if file and allowed_file(file.filename):
filename = secure_filename(file.filename)
full_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
file.save(full_path)
# print('upload_image filename: ' + filename)
flash('Image successfully uploaded and displayed')
get_image(file.filename)
get_image_path()
data = 'render some text sting here'
print(data)
return render_template('services.html', filename=filename, dataToRender=data)
else:
flash('Allowed image types are -> png, jpg, jpeg, gif')
return redirect(request.url)
HTML
<form method="post" action="{{ url_for('upload_image') }}" enctype="multipart/form-data">
<label for="img" style="margin-bottom: 40px;font-size: 30px">choose image:</label>
<input type="file" onchange="preview(event)" autocomplete="off" required name="file"><br>
<img class="card-img-top" src="img/inttion.jpg" id="imgg" alt="Card image cap">
<p>
<input type="submit" value="Submit">
<h3>Your Recognition Result IS</h3>
<input type="text" name="result">
<h1>here is the result {{ dataToRender }}</h1>
</p>
</form>
To do what you are asking, you will have to make use of flask's ability to integrate with a templating engine (flask uses Jinja2 by default). This would look something like this:
In your main file with your routes in it, you will have to define a route on which you want to render a template
from flask import render_template
#app.route('/')
def index():
data = someFunction()
return render_template('index.html', dataToRender=data)
In another file called templates/index.html you will have to define the template and this is where you can dictate where the information that you provided will show up.
<!DOCTYPE html>
<title>Hello from Flask</title>
<h1>Hello {{ dataToRender }}!</h1>
I hope this helps. Flask also has some great documentation on the subject that can be found here

How to change image path dynamically with Flask

Hi is there a way to dynamically load different images whenever I get into my flask app?
I've got 10 images each is named 'accueil_X' with X is 0,1,2,...
app.py
#app.route('/', methods=("POST", "GET"))
def home():
random = randrange(10)
random_pix = 'accueil_'+str(random)+'.png'
HTML
<img src="{{url_for('static', filename='+{{ random_pix }}+')}}" width=100%, alt="">
Jinja seems to load an image named +{{ random_pix }}+: How can I fix this ? thank you
so you want to load a random image with each refresh of the home page:
#app.route('/', methods=("POST", "GET"))
def home():
random = randrange(10)
random_pix = 'accueil_'+str(random)+'.png'
[..]
# i added this missing line to get code more clear
return render_template('home.html', random_pix=random_pix)
Jinja seems to load an image named +{{ random_pix }}+: How can I fix this ?
it's simple, just remove the {{ }} surrounding the variable random_pix
<img src="{{ url_for('static', filename='\'' + random_pix + '\'') }}" width=100%, alt="">
jinja2 uses {{ .. }} to evaluate any valid expression
refer to this doc
You could do this with a context processor which is the equivelant of Django's "template tag".
This can be used to pass a number of variables to all templates, or pass a function which can then be called in all templates.
First import the required modules, and initialise the app:
from flask import Flask, url_for, render_template
from random import randrange
app = Flask(__name__)
Then define a context processor:
#app.context_processor
def utility_processor():
def random_image():
number = randrange(10)
f = 'accueil_' + str(number) + '.png'
return url_for('static', filename=f)
return dict(rand_im=random_image)
Notice you've passed the random_image function which can then be called in the template as rand_im. Instead of putting the call to url_for in the template, you've done this in Python.
So you could render this with the following in any template:
<img src="{{ rand_im() }}" width="100%" />

Display profile image in nav bar

I am building my own blog site.
I managed to have the users upload their own profile pic and have it displayed beside their post but now i want to have that same image be displayed in the navbar as a profile image but when i do it the same way i did it with the posts it doesnt work and looks like this.
For the posts i made a profile image model and accessed the variable from within the html file but the same method does not work for displaying it in the nav bar.
I am using python and django for backend.
This is my model code for the profile image:
from django.db import models
from django.contrib.auth.models import User
from PIL import Image
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
image = models.ImageField(default="default.jpg", upload_to="profile_pics")
def __str__(self):
return f"{self.user.username} Profile"
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
img = Image.open(self.image.path)
if img.height > 300 or img.width > 300:
output_size = (300, 300)
img.thumbnail(output_size)
img.save(self.image.path)
This is how i reference it in my html file for displaying next to posts:
<img class="rounded-circle article-img" src="{{ post.author.profile.image.url }}" id="img">
When i use any other image(either from a url or a local file) it works perfectly but when I use that variable to call the image it doesn't work
It might be worth mentioning that the navbar and post sections are in different html files. it looks like the nav bar's html file does not have access to that variable?
What am I doing wrong?
Try this:
<img class="rounded-circle article-img" src="{{ request.user.profile.image.url }}" id="img">

How to output just html image tag when I have text and html in django template output?

I am using this to output,
{{ movie.img }}
and I get the output is supposed to be something like,
u'<img src="//upload.wikimedia.org/wikipedia/en/thumb/8/8a/Dark_Knight.jpg/220px-Dark_Knight.jpg" alt="" height="327" width="220" >\nTheatrical release poster'
How do I just output the html image part? I don't want the Theatrical release poster to appear in the output.
Since you are getting that as just text, your best solution would be to write a template filter that would strip content not in the <img> html tag.
If the object were a ImageField (or FileField), you can call on the url attribute only, {{ movie.img.url }}
update
Ok, here's a basic, probably too naive template filter for your use.
from django import template
from django.template.defaultfilters import stringfilter
import re
register = template.Library()
#register.filter(is_safe=True)
#stringfilter
def get_img_tag(value):
result = re.search("<.*?>", value)
if result:
return result.group()
return value
Use:
{{ movie.img|get_img_tag|safe }}