How to show images from s3? - python

I'm finishing an application by django that generates pdf certificates
it was working great before I pull it into heroke and set up S3 amazom to host static files.
I have an html with the certificate template, and by HTML2PDF I render it to pdf. But it's not showing the background by css, it works just in the tag
Weird that if we opent the image url in s3 amazom it's shown perfectly
here the template css part
<meta charset="utf-8" />
{% load static %}
<style type="text/css">
#page {
size: 1122.52px 1587.4px ;
/*size: A4 landscape;*/
margin: 0cm;
background-image: url({{bg_front}});
height: 1588;
}
</style>
My view:
class ViewPDF(View):
def get(self, request, *args, **kwargs):
data = {}
pdf = True
if kwargs['pk']:
try:
participant = Participant.objects.get(pk=kwargs['pk'])
print(participant.cpf)
if participant.name:
certificate = Certificate.objects.get(pk=participant.certificate.pk)
pathBack = str(certificate.template.template_back.url)
pathFront = str(certificate.template.template_front.url)
print(pathFront)
#
# CONFIGURA OS BACKGROUNDS E TEXTO
#
data['bg_front'] = pathFront
data['bg_back'] = pathBack
setting = certificate.template.settings
start_date = datetime.strftime(certificate.start_date,'%d/%m/%Y')
end_date = datetime.strftime(certificate.start_date,'%d/%m/%Y')
data['text_front'] = setting.replace('<<nome>>',participant.name).replace('<<cpf>>',str(participant.cpf)).replace('<<ch>>',str(certificate.ch)).replace('<<instituicao>>',str(certificate.institution)).replace('<<DataInicio>>',start_date).replace('<<DataFim>>',end_date)
data['cpf'] = participant.cpf
pdf = render_to_pdf('app_certificates/body_front_pdf.html', data)
return HttpResponse(pdf, content_type='application/pdf')
except TypeError as e:
return HttpResponse(e)

Related

Django Reportlab generates empty pdf

I'm using reportlab to create a pdf. I am using Reportlab Paragraphs. The problem is everytime i download it, it generates an empty txt.
I tested it without django and it works without a problem. If i'm using canvas it works but it doesn't suit what i need.
views.py
from django.http import HttpResponse
from django.shortcuts import render
from reportlab.lib.enums import TA_JUSTIFY
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.pagesizes import letter
def genereaza_pdf(request):
if request.method == 'POST':
response = HttpResponse(content_type='application/pdf')
response['Content-Disposition'] = 'attachment; filename="example.pdf"'
doc = SimpleDocTemplate("example.pdf", pagesize=letter, rightMargin=70, leftMargin=70, topMargin=70,
bottomMargin=60)
report = []
styles = getSampleStyleSheet()
styles.add(ParagraphStyle(name="Times", fontName='Times-Roman', fontSize=15, alignment=TA_JUSTIFY))
p_text = "<u>ANEXA 1</u>"
report.append(Paragraph(p_text, styles["Times"]))
report.append(Spacer(1, 5))
doc.build(report)
return response
return render(request, 'pdf_test.html')
pdf_test.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Download pdf</title>
</head>
<body>
<form method="POST">
{% csrf_token %}
<button type="submit">Download</button>
</form>
</body>
</html>
What seems to be the problem?
You have to write the file to stream. Try this:
from io import BytesIO
def genereaza_pdf(request):
if request.method == 'POST':
response = HttpResponse(content_type='application/pdf')
response['Content-Disposition'] = 'attachment; filename="example.pdf"'
buff = BytesIO()
doc = SimpleDocTemplate(buff, pagesize=letter, rightMargin=70, leftMargin=70, topMargin=70,
bottomMargin=60)
report = []
styles = getSampleStyleSheet()
styles.add(ParagraphStyle(name="Times", fontName='Times-Roman', fontSize=15, alignment=TA_JUSTIFY))
p_text = "<u>ANEXA 1</u>"
report.append(Paragraph(p_text, styles["Times"]))
report.append(Spacer(1, 5))
doc.build(report)
response.write(buff.getvalue())
buff.close()
return response
return render(request, 'pdf_test.html')
The function was generating two files, one in Downloads as default but it was an empty txt and one in the project's directory. I've made the changes.
def genereaza_pdf(request):
if request.method == 'POST':
response = HttpResponse(content_type='application/pdf')
response['Content-Disposition'] = 'attachment; filename="example.pdf"'
doc = SimpleDocTemplate(response, pagesize=letter, rightMargin=70, leftMargin=70, topMargin=70,
bottomMargin=60)
report = []
styles = getSampleStyleSheet()
styles.add(ParagraphStyle(name="Times", fontName='Times-Roman', fontSize=15, alignment=TA_JUSTIFY))
p_text = "<u>ANEXA 1</u>"
report.append(Paragraph(p_text, styles["Times"]))
report.append(Spacer(1, 5))
doc.build(report)
return response
return render(request, 'pdf_test.html')

Display JSON data from a python file into HTML

I currently have an HTML file and a python file. The python file uses YELP's API and returns JSON data. How do I display that data onto my webpage through HTML? Is there a function like document.getElementById("id").innerHTML = JSONDATA from JavaScript?
Please let me know if you need any more details; this is my first time posting and first time using an API/making a website. I understand the JSON data is not going to look nice but I will put it into a dictionary and sort it later, basically right now I am just wondering how to display data from a Python file into a HTML file. Also, feel free to link any helpful tutorials.
Found the following Node.js code as it was suggested to use Javascript instead, where in this would I put my tokens/secrets? And then how would I call it in my html file... Thank you.
/* require the modules needed */
var oauthSignature = require('oauth-signature');
var n = require('nonce')();
var request = require('request');
var qs = require('querystring');
var _ = require('lodash');
/* Function for yelp call
* ------------------------
* set_parameters: object with params to search
* callback: callback(error, response, body)
*/
var request_yelp = function(set_parameters, callback) {
/* The type of request */
var httpMethod = 'GET';
/* The url we are using for the request */
var url = 'http://api.yelp.com/v2/search';
/* We can setup default parameters here */
var default_parameters = {
location: 'San+Francisco',
sort: '2'
};
/* We set the require parameters here */
var required_parameters = {
oauth_consumer_key : process.env.oauth_consumer_key,
oauth_token : process.env.oauth_token,
oauth_nonce : n(),
oauth_timestamp : n().toString().substr(0,10),
oauth_signature_method : 'HMAC-SHA1',
oauth_version : '1.0'
};
/* We combine all the parameters in order of importance */
var parameters = _.assign(default_parameters, set_parameters, required_parameters);
/* We set our secrets here */
var consumerSecret = process.env.consumerSecret;
var tokenSecret = process.env.tokenSecret;
/* Then we call Yelp's Oauth 1.0a server, and it returns a signature */
/* Note: This signature is only good for 300 seconds after the oauth_timestamp */
var signature = oauthSignature.generate(httpMethod, url, parameters, consumerSecret, tokenSecret, { encodeSignature: false});
/* We add the signature to the list of paramters */
parameters.oauth_signature = signature;
/* Then we turn the paramters object, to a query string */
var paramURL = qs.stringify(parameters);
/* Add the query string to the url */
var apiURL = url+'?'+paramURL;
/* Then we use request to send make the API Request */
request(apiURL, function(error, response, body){
return callback(error, response, body);
});
};
I had a similar situation. I had to show the IAM users of AWS account in a HTML page. I used AWS boto3 Python client to grab all IAM users and write a JSON file. Then from HTML file I read that JSON file and showed all users in a table.
Here is the Python code IAM.PY:
import boto3
import os
import subprocess
import json
iam_client = boto3.client('iam')
def list_user_cli():
list_cmd = "aws iam list-users"
output = subprocess.check_output(list_cmd, shell = True)
output = str(output.decode('ascii'))
return output
def write_json_file(filename, data):
try:
with open(filename, "w") as f:
f.writelines(data)
print(filename + " has been created.")
except Exception as e:
print(str(e))
if __name__ == "__main__":
filename = "iam.json"
data = list_user_cli()
write_json_file(filename, data)
Here is the HTML file IAM.HTML:
<!DOCTYPE html>
<html>
<head>
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<title>IAM User List</title>
<style type="text/css">
body{
margin: 20px;
}
</style>
</head>
<body>
<div class="container">
<table class="table table-responsive table-hover table-bordered">
<thead>
<tr>
<th>User ID</th>
<th>User Name</th>
<th>Path</th>
<th>Create Date</th>
<th>Arn</th>
</tr>
</thead>
<tbody id="iam_tbody">
</tbody>
</table>
</div>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.0/jquery.min.js"></script>
<script type="text/javascript">
$(document).ready(function(){
$.ajax({
method: "GET",
url: "http://localhost/iam/iam.json",
}).done(function(response){
user_list = response.Users;
for(i = 0; i<user_list.length; i++){
tr = "<tr>";
tr += "<td>";
tr += user_list[i]["UserId"];
tr += "</td>";
tr += "<td>";
tr += user_list[i]["UserName"];
tr += "</td>";
tr += "<td>";
tr += user_list[i]["Path"];
tr += "</td>";
tr += "<td>";
tr += user_list[i]["CreateDate"];
tr += "</td>";
tr += "<td>";
tr += user_list[i]["Arn"];
tr += "</td>";
tr += "<tr>";
$("#iam_tbody").append(tr);
}
});
});
</script>
</body>
</html>
Output
You can use Jquery Ajax to call your API, include Jquery in your html file.
$.ajax({
method: "GET",
url: "api_url",
}).done(function( response ) {
$('#divId').append(response);
});
In Your Html File
<div id="divId"></div>
Jquery Ajax Documentation

Image won't load on python-based webserver

I've built a simple web server that gets a request and send a response. So when the server gets an invalid request, like "localhost/not-a-page", the server will send a response with the content of the HTML file "404.html" the webpage should display an image. So far, so good.
But when the 404 page loads up, the page can't find the image. The HTML part is correct and works offline. I've tried to move the image to serval locations, relative to the Python script, relative to the HTML. But it just can't find it. Hi I'm trying to make the server as low-level as I can, I want to learn how servers work. So I'm not using any server-related libraries. I'm using only the socket library of Python.
I'll appreciate any help to resolve this problem without using other libraries,
EDIT
Here is the relevant Python part :
import socket
import threading
import os
default_error_page = """\
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<title>Error response</title>
</head>
<body>
<center>
<h1>Response</h1>
<p>Error code: %(code)d</p>
<p>Message: %(status)s.</p>
</center>
</body>
</html>
"""
default_header_status = "HTTP/1.1 %(code)d %(status)s\r\n"
default_header_content_type = "Content-Type: text/html; charset=utf-8\r\n\r\n"
buffer_size = 1024
def get_page(code):
    page = default_error_page
    if code == 200:
        pass
    else:
        file = open(os.path.dirname(__file__) + "/www/not-found.html", 'r')
        page = file.read()
    return page
class BaseServer:
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server_name = ""
    host_name = ""
    host_port = 8000 # default port
    is_shutdown = False
    def __init__(self, name):
        self.server_name = name
    def start_server(self):
        thread = threading.Thread(target=self.run_server(), name=self.server_name)
        thread.start()
    def run_server(self):
        self.server_socket.bind((self.host_name, self.host_port)) # bind to host
        self.server_socket.listen()
        while not self.is_shutdown:
            conn, addr = self.server_socket.accept()
            self.handle_request(conn, addr)
    def handle_request(self, connection, address):
        print(str(address[0]) + " Connected! (port " + str(address[1]) + ")")
        result = self.parse_request(connection.recv(buffer_size))
        if result == 0:
            page = self.parse_response(200)
        else:
            page = self.parse_response(404)
        connection.sendall(bytes(page))
    def parse_request(self, data):
        if len(data) == 0:
            return
        strings = str(bytes(data).decode('utf-8')).split('\r\n')
        command, path, version = strings[0].split()
        print("command - " + command)
        print("path - " + path)
        print("version - " + version)
        status = 1
        if path == "/":
            status = 0
        return status
    def parse_response(self, code):
        status = "ERROR"
        if code == 200:
            status = "OK"
        elif code == 404:
            status = "NOT FOUND"
        base_header = (default_header_status % {'code': code, 'status': status})
        base_content_type = default_header_content_type
        # page = (default_error_page % {'code': code, 'status': status})
        page = str(get_page(code))
        return_string = str(base_header + base_content_type + page).encode('utf-8')
        print(return_string)
        return return_string
def main():
    server = BaseServer("Home Server")
    server.start_server()
if __name__ == "__main__":
    main()
And this is the HTML:
<html>
<head>
<link rel="stylesheet" type="text/css" href="/style/main.css"/>
<style>
*{
padding:0;
margin:0;
}
body{
background-color:#ffe6b3;
}
h1{
margin-top:30px;
background-color:#ffcc66;
font-size:3em;
display:inline-block;
color:#3a0000;
}
p{
margin-top:80px;
font-size:2em;
color:#3a0000;
}
#img404{
background-image:url(../images/404.gif);
width:100%;
height:50%;
background-repeat:no-repeat;
background-position:center 20%;
}
</style>
</head>
<body>
<center>
<div class=top>
<h1>ERROR 404</h1>
</div>
<p>
Sorry, we could not find the page :(
</p>
<div id="img404">
</div>
</center>
</body>
</html>
Sorry if it's not very readable, but I'm on the phone.
Dima.
Don't use relative paths for image like ../images/img.gif. Rather use full url or url relative to the root.
http://localhost/images/img.gif - full url
/images/img.gif - path relative to root url
Figured out my problem.
After I saw the logs, I realized that the browser sends another request, for the image.
And silly me, my code is:
if path ="/":
status = 0
else:
status = 1
So for every request which is not root("/") the server will return 404.
Oops

Flask: how do I serve an svg that's dynamically generated

So I have code that generates an SVG xml:
def get_map(locations):
max_value = max(locations.iteritems(), key=operator.itemgetter(1))[1]
base = "fill:#%s;fill-rule:nonzero;"
f = open("../static/img/usaHigh.svg", "r").read()
soup = BeautifulSoup(f)
for l in locations:
#do stuff.....
return str(soup)
but now I want to serve this svg through flask. To be able to do something like
<img src='sometemp.svg'>
so my flask function would look like:
def serve_content():
return render_template('sometemplate.html', map=get_map())
Is this possible without creating temp files?
EDIT: here's a chunk of the output:
<?xml version='1.0' encoding='utf-8'?>
<!-- (c) ammap.com | SVG map of USA -->
<svg xmlns="http://www.w3.org/2000/svg" xmlns:amcharts="http://amcharts.com/ammap" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1">
<defs>
<style type="text/css">
.land
{
fill: #CCCCCC;
fill-opacity: 1;
stroke:white;
stroke-opacity: 1;
stroke-width:0.5;
}
</style>
<!--{id:"US-AK"},{id:"US-AL"},{id:"US-AR"},{id:"US-AZ"},{id:"US-CA"},{id:"US-CO"},{id:"US-CT"},{id:"US-DC"},{id:"US-DE"},{id:"US-FL"},{id:"US-GA"},{id:"US-HI"},{id:"US-IA"},{id:"US-ID"},{id:"US-IL"},{id:"US-IN"},{id:"US-KS"},{id:"US-KY"},{id:"US-LA"},{id:"US-MA"},{id:"US-MD"},{id:"US-ME"},{id:"US-MI"},{id:"US-MN"},{id:"US-MO"},{id:"US-MS"},{id:"US-MT"},{id:"US-NC"},{id:"US-ND"},{id:"US-NE"},{id:"US-NH"},{id:"US-NJ"},{id:"US-NM"},{id:"US-NV"},{id:"US-NY"},{id:"US-OH"},{id:"US-OK"},{id:"US-OR"},{id:"US-PA"},{id:"US-RI"},{id:"US-SC"},{id:"US-SD"},{id:"US-TN"},{id:"US-TX"},{id:"US-UT"},{id:"US-VA"},{id:"US-VT"},{id:"US-WA"},{id:"US-WI"},{id:"US-WV"},{id:"US-WY"}-->
</defs>
<g>
<path id="US-AK" title="Alaska" class="land" d="M456.18,521.82l-0.1,4.96l-0.1,4.94l-0.1,4.92l-0.1,4.9l-0.1,4.88l-0.1,4.86l-0.1,4.84l-0.1,4.82l-0.1,4.8l-0.1,4.78l-0.1,4.77l-0.09,4.75l-0.1,4.73l-0.09,4.71l-0.09,4.7l-0.09,4.68l-0.09,4.66l-0.09,4.65l-0.09,4.64l-0.09,4.62l-0.09,4.61l-0.09,4.59l-0.09,4.58l-0.09,4.56l-0.09,4.55l-0.09,4.54l-0.09,4.53l-0.09,4.51l-0.09,4.5l-0.09,4.49l-0.09,4.48l-0.09,4.47l1.8,0.66l1.79,0.65l0.57,-1.23l1.93,0.97l1.69,0.85l1.09,-1.06l1.18,-1.14l1.58,-0.07l1.77,-0.09l1.18,-0.06l0,0.98l-0.44,1.63l-
So I'm trying to pipe that back to the page template without first saving it into a file, and then serving it. Is that possible?
EDIT 2:
this is the routing function
#app.route("/map", methods=["GET", "POST"])
def map():
locations = {"US-NY":60,
"US-FL":30,
"US-CA":100}
#return Response(get_map(locations), mimetype='image/svg+xml')
return render_template("map.html", svg=get_map(locations))
This is my template:
<html>
<body>
this is some of the stuff I want, here's a beautiful map
{{ svg }}
</body>
</html>
And this is what my page looks like on Chrome
So it's not actually showing the svg :'(
Your SVG code is being autoescaped. An appropriate solution is to call Markup(), like so:
return render_template("map.html", svg=Markup(get_map(locations)))
You can use StringIO for this :
from flask import send_file
from StringIO import StringIO
def serve_content(content):
svg_io = StringIO()
svg_io.write(content)
svg_io.seek(0)
return send_file(svg_io, mimetype='image/svg+xml')
For those with no need for an actual file, here's how I make an SVG from scratch with a custom color and serve it up with Flask.
import flask
custom_color_global_variable = 'red'
#app.route('/circle-thin-custom-color.svg', methods=('GET', 'HEAD'))
def circle_thin_custom_color):
"""Thin circle with the color set by a global variable."""
return flask.Response(
"""
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 512 512"
><path
fill="{color}"
d="M256 8C119 8 8 119 8 256s111 248 248 248 248-111
248-248S393 8 256 8zm216 248c0 118.7-96.1 216-216 216-118.7
0-216-96.1-216-216 0-118.7 96.1-216 216-216 118.7 0 216 96.1
216 216z"
/></svg>
\n""".format(
color=custom_color_global_variable,
),
mimetype='image/svg+xml'
)

Showing web camera through web interface (Python, CherryPy, OpenCV)

I want to show OpenCV processed image with web interface (made with CherryPy). Code below works fine:
import cherrypy
import cv2
class Picture(object):
def __init__(self):
self.cam = cv2.VideoCapture(0)
#cherrypy.expose
def index(self):
_, image = self.cam.read()
_, data = cv2.imencode('.jpg', image)
cherrypy.response.headers['Content-Type'] = 'image/jpeg'
return data.tostring()
if __name__ == '__main__':
cherrypy.config.update({'server.socket_host': '127.0.0.1', 'server.socket_port': 80, })
cherrypy.quickstart(Picture())
However: I would like to embed the image in html so I can (for example) add another image or other data to the same page.
I have tried the following code:
import cherrypy
import cv2
class Picture(object):
def __init__(self):
self.cam = cv2.VideoCapture(0)
#cherrypy.expose
def index(self):
_, image = self.cam.read()
_, data = cv2.imencode('.jpeg', image)
return """ <html>
<head>
<title>CherryPy static imagl</title>
</head>
<html>
<body>
<img src=" """ + data + """:image/jpeg" />
</body>
</html>"""
if __name__ == '__main__':
cherrypy.config.update({'server.socket_host': '127.0.0.1', 'server.socket_port': 80, })
cherrypy.quickstart(Picture())
But this gives the following error:
<img src=" """ + data + """:image/jpeg" />
TypeError: cannot concatenate 'str' and 'numpy.ndarray' objects
Converting the numpy arry to a string using the following code also does not work (it gives no error but displays only characters):
<img src=" """ + data.tostring() + """:image/jpeg" />
Anyone who can give me some more insight? Thanks in advance!
The following code does the trick :)
import cherrypy
import cv2
import base64
class Picture(object):
def __init__(self):
self.cam = cv2.VideoCapture(0)
#cherrypy.expose
def index(self):
_, image = self.cam.read()
_, data = cv2.imencode('.jpg', image)
jpeg_base64 = base64.b64encode(data.tostring())
return """
<html>
<head>
<meta http-equiv="refresh" content="1" />
<title>Cherrypy webcam</title>
</head>
<html>
<body>
<img src='data:image/jpeg;base64,%s' />
<img src='data:image/jpeg;base64,%s' />
</body>
</html>
""" % (jpeg_base64, jpeg_base64)
if __name__ == '__main__':
cherrypy.config.update({'server.socket_host': '127.0.0.1', 'server.socket_port': 80, })
cherrypy.quickstart(Picture())
This code displays the same picture two times. and the:
<meta http-equiv="refresh" content="1" />
refreshes the code every second.

Categories

Resources