How to send images in a jinja html template? - python

So I've got a setup of flask + jinja and I'm trying to display an image in an html file being rendered by jinja.
In Python I'm converting it into base64 and then sending it to the template. I'm then using an image tag to display the image.
<img src="data:image/jpeg;base64,{{ myimage }}">
I've confirmed that the Python encoding is correct, it displays as it should when I simply write an html file with the base64 embedded into it. Where it seems to fail is from the template modifying the output a little bit. In particular:
<img src=3D"data:;base64,/9j/4QAYR
...
baW4WqWj/2Q=3D=3D"/>
Jinja seems to be screwing around by adding the text 3D in a couple places where it looks like it shouldn't be. I haven't specified anything differently, and when I printed out myimage just as text, it came up the way I expected it to, starting with /9j and ending with /2Q==
I'm not sure if there's something with the way I'm interpreting it in Jijna or what, but it just doesn't load. I see the image src tag in the email source, but there's just nothing where I expect the image to be loaded.

Markup the variable myimage as safe:
<img src="data:image/jpeg;base64,{{ myimage | safe }}">
Simple single file app (uses requests library):
from flask import Flask, render_template_string
import base64
import requests
app = Flask(__name__)
global _base64_encoded_image
#app.route('/')
def index():
_html_template = '''
<p><img src="data:image/jpeg;base64,{{ myimage | safe }}"><p>
<p><img src="data:image/jpeg;base64,{{ myimage | e }}"><p>
<p><img src="data:image/jpeg;base64,{{ myimage }}"><p>
'''
global _base64_encoded_image
return render_template_string(_html_template, myimage=_base64_encoded_image)
#app.before_first_request
def before_first_request():
global _base64_encoded_image
_url = "http://via.placeholder.com/200?text=Flask/Jinja2"
_r = requests.get(_url)
_base64_encoded_image = base64.b64encode(_r.content)
print _base64_encoded_image
if __name__ == '__main__':
app.run()

This looks like a URL encoding problem as = is a character used in that base64 alphabet and its URL encoding is %3D. Try doing a urllib.quote on the base64 data before rendering it with Jinja.

Related

How to inject a variable into <img src='VARIABLE'>

If I place one of the dictionary values(i.e "https://....) directly into <img src, the image will render properly. Using the variable 'musician'(which contains "https://...) will yield an empty properly formatted frame with a broken image logo.
musician_dict = {
'g': 'https://media.stubhubstatic.com/stubhub-catalog/d_defaultLogo.jpg/t_f-fs-0fv,q_auto:low,f_auto,c_fill,$w_280_mul_3,$h_180_mul_3/performer/404807/gvwionkcazusra2wbkuu',
'p': 'https://cdn.britannica.com/18/161418-050-811E4CBE/McCoy-Tyner.jpg?w=400&h=300&c=crop'
}
# The website starts with a main page
#app.route("/")
def piano_or_guitar_game():
musician = random.choice(list(musician_dict.values()))
return "<h1>pIANO player or gUITAR player(q to quit)</h1>" \
"<img src=musician width=500>"
You're sending it back as a string literal. With Flask, you'd usually do something like:
return render_template("index.html", picture=musician)
and then in your templates folder, you would have:
<img src={{picture}} width=500>
See Flask's blog tutorial.

Linebreak of a yaml not displaying at an html file

I am having a ymal file and a html file where some of the content in the ymal file is loaded into the html file (see below). I would like to add linebreaks to the string in the ymal file such that it is shown in separate lines when the html file is loaded. I am using flask and jupyter to load the html file.
The html file is loaded correctly but whatever i try it seems that I cannot get the string to break where I want it to.
Does anyone can help me to add linebreaks in the yaml files such that they are shown in the html file?
Thank you.
python code:
import oyaml as yaml
from flask import Flask
from flask import render_template
app = Flask(__name__)
app.config['JSON_SORT_KEYS'] = False
#app.route('/')
def index():
website_data = yaml.load(open('_config.yaml'))
return render_template('home.html', data=website_data)
if __name__ == '__main__':
app.run()
My yaml code:
profile:
first_name: |
I would like to have a break here.\n
And then I would also to have a break here\\
But it does not work whatever I try</br>.
My html code:
<!DOCTYPE html>
<html>
<body>
<h1>My homepage</h1>
<p>{{ data.profile.first_name }} </p>
<p>This is a test website again</p>
</body>
</html>

Replacing text from string with an image using flask

I have written a piece of code that matches if the string has anything of the pattern text.someExtension, In my case, it would be fileName.png in the string, converts it into an img tag and displays on the HTML file using python and flask. Let us take the example string:
"What is the output of this program? e.png"
the code matches e.png and it then replaces e.png by
"<br><img src="{{url_for('static', filename='pics/e.png')}}" /><br>"
The image e.png is put in the folder pics inside the static folder.
If this string is pushed into a flask variable even by adding Markup() to it it isn't rendering the image but showing the following output.
output on html page
why is it so? Any way to make it display the image e.png?
my code is:
import re
from flask import Flask, Markup, render_template
app = Flask(__name__)
def rep(x):
text = re.findall(r'\w+[.]\w+', x)
for i in text:
b ="<img src=\"{{ url_for('static',filename='pics/"+i+"')}}\">"
x=x.replace(i,b)
return x
#app.route('/')
def home():
a = "What is the output of this program? e.png"
a = rep(a)
return render_template('new.html',var=Markup(a))
if __name__ == '__main__':
app.run(debug=True, host='localhost', port=8032)
And the HTML file is,
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{{var}}
</body>
</html>
The problem is that the value you're passing to your template is a string and even though the string you're inserting is formatted with the {{ brackets, flask doesn't interpret those. Notice if you look at the html being served, it actually contains the string 'url_for'...
You're also not even importing the url_for function from flask, so that wouldn't have worked anyway.
The solution:
import re
from flask import Flask, url_for, Markup, render_template
app = Flask(__name__)
def rep(x):
text = re.findall(r'\w+[.]\w+', x)
for i in text:
b ="<img src='" + url_for('static', filename='pics/'+i) + "'>"
x=x.replace(i,b)
return x
#app.route('/')
def home():
a = "What is the output of this program? e.png"
a = rep(a)
return render_template('new.html', var=Markup(a))
#app.route('/static/<path:path>')
def static_file(path):
return send_from_directory('static', path)
if __name__ == '__main__':
app.run(debug=True, host='localhost', port=8032)
The html file can remain unchanged. This solution
separately tells the flask server to listen and serve the static files under the /static page.
Creates the html with the image url by string concatenation, instead of trying to use template rendering.

Python Flask to change text in a HTML file

I'm trying to create a simple program which will replace {{ test }} with 'Hello world' by following a tutorial, however I am stumped and when I open the HTML file - as {{ test }} is shown on the page instead of 'Hello World' which is what should be appearing.
Any help would be appreciated because I am very unsure on what to do to fix this, thanks.
I am unsure if I have even linked the two files, as to my knowledge it was never specified in the video and I have only just noticed that there is no link between the two files.
Python Code:
from flask import Flask, render_template
app = Flask(__name__)
#app.route('/')
def homepage():
return render_template('index.html', test='hello world')
if __name__ == '__main__':
homepage()
else:
print('Please run this file as main, not as module.')
HTML Code:
<!DOCTYPE HTML>
<html>
<head>
</head>
<body>
<p> {{ test }} </p>
</body>
</html>
Flask is a webserver. You are not meant to call the functions with app.route. Replace the last part with:
if __name__ == '__main__':
app.run()
and then visit http://127.0.0.1:5000/ in your browser. The template file is not meant to change.
If for some reason you don't want to run a server but you just want to create HTML files, then use Jinja2, the template engine behind Flask.

Embedding an html page inside Flask

Ok, I have managed to create a flask page that shows a bokeh image -- now I have to somehow put that into a template
https://gist.github.com/cloudformdesign/a0c5f2e8558ea3b60f0a
What I would like is to create a webpage with a few text boxes where the user can type the data they want to graph and it will be graphed below the text boxes. The user can select new data they want graphed and the graph will update.
I am very bad at coding in html, so I am very bad in creating templates. How would I do something like this?
I created my own example, thanks to #elyase
https://github.com/bokeh/bokeh/tree/master/examples/embed/simple
This is a very simple example of embedding bokeh pages in an html page. The example giving by #elyase was helpful, but didn't actually work with python3 (I could not import or install pyaudio). It was also overly complicated for what I was trying to ask. The gist above gives a very simple answer with only two files, all in the same directory. Thanks a ton!
Basically you need to create a view which will serve as static image, and you get the image url from that route.
I haven't got your included library so I'm going to use matplotlib and numpy to simulate what you are trying to attempt. This isn't a FULL solution for you (it's in the simplest working way using 2 views and 1 simple template), but you should be able to understand all the ESSENTIAL techniques which let you finish off your page.
I have a few comments and guidelines, and I think the code itself is pretty much self explanatory.
OK, here is the view main.py:
from flask import Flask, render_template, request, send_file
import matplotlib.pyplot as plt
import numpy as np
from StringIO import StringIO
app = Flask(__name__)
#app.route('/plot/')
def plot():
try:
# try to get the query string like ?width=xxx&height=xxx
height = int(request.args.get('height'))
width = int(request.args.get('width'))
except ValueError:
# if height, width not available, set a default value
height, width = 100, 100
# I randomly generate the plot which just based on H x W
# you should be able to generate yours from your library
to_draw = np.random.randint(0, 255, (height, width))
img = plt.imshow(to_draw)
# you can convert the graph to arrays and save to memory
imgIO = StringIO()
img.write_png(imgIO, noscale=True) # save to memory
imgIO.seek(0)
# and send that image as file as static file of url
# like... /plot/?width=100&height=100
return send_file(imgIO, mimetype='image/png')
# this is the main page with the form and user input
#app.route('/', methods=['GET', 'POST'])
def index():
# set the default values
height, width = 100, 100
# handle whenever user make a form POST (click the Plot button)
if request.method == 'POST':
try:
# use this to get the values of user input from the form
height = int(request.form['height'])
width = int(request.form['width'])
except ValueError:
pass
# and pass the context back to the template
# if no form is POST, default values will be sent to template
return render_template('index.html', height=height, width=width)
if __name__ == '__main__':
app.debug = True
app.run()
And the template at templates/index.html:
<html>
<head>
<title>Micro Plot!</title>
</head>
<body>
<h1>Interactive Plot</h1>
<form action="/" name="plot" method="POST">
<p><input type="text" name='height' value="{{ height }}" /></p>
<p><input type="text" name='width' value="{{ width }}" /></p>
<p><input type="submit" value="Plot Now!"></p>
</form>
<img src="{{ url_for('plot', height=height, width=width) }}" />
</body>
</html>
The trick is to set the image src to send a GET request to the url, and then Flask's /plot/ view to render an in-memory image and feed back as static.
Key Notes:
The url_for will then dynamically generate the src as like /plot/?width=xxx&height=xxx.
To get the querystring from the url in the view, use request.args.get('KeyName').
Once your plot is ready, save it in the memory with Python StringIO module and use Flask's send_file to serve as static content.
You should read and learn more about Flask and HTML, you cannot build something really amazing without having a good understanding of how these things work together.
I hope this helps you understand the underlying techniques, and Good Luck!
I ended up creating my own answer with the help of elyase, and the code was pulled into an example folder in the bokeh project. Check it out here:
https://github.com/bokeh/bokeh/tree/master/examples/embed/simple

Categories