Django - Pisa generated pdf doesn't have spaces - django

I'm using Django and my code to render the PDF is really typical:
t = loader.get_template('back/templates/content/receipt.html')
c = RequestContext(request, {
'pagesize': 'A4',
'invoice': invoice,
'plan': plan,
})
html = t.render(c)
result = StringIO.StringIO()
pdf = pisa.pisaDocument(StringIO.StringIO(html.encode("UTF-8")), result)
if not pdf.err:
return HttpResponse(result.getvalue(), mimetype="application/pdf")
And the receipt.html is nothing unusual:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Squizzal Receipt</title>
<style type="text/css">
#page {
size: {{pagesize}};
margin: 1cm;
word-spacing 1cm;
#frame footer {
-pdf-frame-content: footerContent;
bottom: 0cm;
margin-left: 9cm;
margin-right: 9cm;
height: 1cm;
}
}
</style>
</head>
<body>
<h1>Your Receipt</h1>
<<SNIP>>
but none of the spaces in the pdf are rendered. All the words are right next to each other. I've tried normal spaces and "&nbsp" and the result is the same. For example the above would appear as "YourReceipt" in the pdf.
When I try using the command line version of pisa, it generates the pdf just fine with spaces between the words.
Any thoughts?

I had this same issue and didn't want to force the PDF to be downloaded from the browser. This turned out to be a platform specific issue: Google Chrome's native PDF viewer plugin fails to render spaces in certain documents on certain Linux distros when Microsoft TrueType fonts are not installed. See http://www.google.com/support/forum/p/Chrome/thread?tid=7169b114e8ea33c7&hl=en for details.
I fixed this by simply running the following commands in bash (adjust for your distro; this was on Ubuntu):
$ sudo apt-get install msttcorefonts
(Accept the EULA during the install process)
$ fc-cache -fv
After restarting Chrome (important!), the native PDF viewer correctly displayed the PDF with spaces.

Ok thanks to akonsu the problem seems to be how Django's HttpResponse is being treated (either on the server side or on the browser side).
Instead of
return HttpResponse(result.getvalue(), mimetype="application/pdf")
Use:
resp = HttpResponse(result.getvalue(), mimetype="application/pdf")
resp['Content-Disposition'] = 'attachment; filename=receipt.pdf'
return resp
This at least produces a result without spaces. Still no idea why the first way wasn't working.

Related

How to stream the videos stored on google cloud storage bucket?

I have stored videos on google cloud storage browser. I want to play these videos on my frontend. For that I need the video URL. But the problem is, whenever I navigate to that URL, the file gets downloaded.
What do I need to do to get the streaming video URL of my stored object?
I accomplished this using video.js.
<html>
<head>
<link href="https://unpkg.com/video.js/dist/video-js.css" rel="stylesheet">
<style>
.video-js {
width: 600px;
height: 600px;
}
</style>
</head>
<body>
<video-js controls data-setup="{}">
<source src="https://storage.cloud.google.com/bucketName/folderName/recordingName.flv" type="video/flv">
</video-js>
<script src="https://unpkg.com/video.js/dist/video.min.js"></script>
<script src="https://unpkg.com/videojs-flash/dist/videojs-flash.min.js"></script>
</body>
</html>
Cloud Storage does support streaming transfers using gcloud. You can also do do streaming transfers on the backend of your application using the third party Boto python lib.
But since you want this solution to be implemented with a fronted I'm guessing you are actually looking for a media player.
So, you will need to:
1.- Generate a SignedUrl of the object (your video):
using gcloud command:
gsutil signurl -d 10m Desktop/private-key.json gs://example-bucket/cat.jpeg
using python lib:
from google.cloud import storage
import datetime
def generate_download_signed_url_v4(bucket_name, blob_name):
"""
Generates a signed URL for downloading a blob.
Note that this method requires a service account key file. You can not use
this if you are using Application Default Credentials from Google Compute
Engine or from the Google Cloud SDK.
"""
storage_client = storage.Client.from_service_account_json('key.json')
bucket = storage_client.get_bucket(bucket_name)
blob = bucket.blob(blob_name)
url = blob.generate_signed_url(
# This URL is valid for 15 minutes
expiration=datetime.timedelta(minutes=15),
# Allow GET requests using this URL.
method='GET'
)
print('Generated GET signed URL:')
print(url)
print('You can use this URL with any user agent, for example:')
print('curl \'{}\''.format(url))
return url
generate_download_signed_url_v4("example-id", "example.mp4")
2.- Initialize an HMTL5 media player with that url:
<!DOCTYPE html>
<html>
<body>
<video width="320" height="240" controls>
<source src="video-signedurl.mp4" type="video/mp4">
Your browser does not support the video tag.
</video>
</body>
</html>

Python webbrowser not opening browser

I'm trying to familiarize myself with Python with a major concern for web publishing, so I looked around and found the following example. Running 2.7 in PyScripter on Windows 7 didn't bring up the browser as I expected. The code came up in Notepad++ instead, apparently since the html suffix was associated with Notepad. I tried about a dozen different permutations of the code, but the html file still opened in Notepad until I associated that file with Firefox. When I include the print webbrowser._browsers command, I get {'windows-default': [, None], 'c:\program files (x86)\internet explorer\iexplore.exe': [None, ]}
This would imply to me that IE should be the default browser being called, but obviously it is not. Can anyone enlighten me here as I am a Python newbie?
'''A simple program to create an html file froma given string,
and call the default web browser to display the file.'''
contents = '''<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta content="text/html; charset=ISO-8859-1"
http-equiv="content-type">
<title>Hello</title>
</head>
<body>
Hello, World!
</body>
</html>
'''
import webbrowser
def main():
browseLocal(contents)
def strToFile(text, filename):
"""Write a file with the given name and the given text."""
output = open(filename,"w")
output.write(text)
output.close()
def browseLocal(webpageText, filename='C:\\Python27\\Programs\\tempBrowseLocal.html'):
'''Start your webbrowser on a local file containing the text
with given filename.'''
strToFile(webpageText, filename)
print webbrowser._browsers
webbrowser.open(filename)
main()
def browseLocal(webpageText):#take filename out of here
'''Start your webbrowser on a local file containing the text
with given filename.'''
#define filename here.
filename='C:\\Python27\\Programs\\tempBrowseLocal.html'
strToFile(webpageText, filename)
print webbrowser._browsers
webbrowser.open(filename)

R Shiny and p5.js

I am using R Shiny to develop a web page and also include my own R code.
I am using p5.js(https://p5js.org/) to display a game in the web page.
As in the official web page says I have an HTML and the p5 javascript code together with the javascript library. If I run the HTML, that is, clicking right and pressing chrome to display I get the started example (https://p5js.org/get-started/) with no incidence.
Here it is the HTML code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<!--<meta name="viewport" content="width=device-width, initial-scale=1">-->
<script language="javascript" type="text/javascript" src="libraries/p5.js"> </script>
<script language="javascript" type="text/javascript" src="sketch.js"></script>
<!-- this line removes any default padding and style. you might only need one of these values set. -->
<style> body {padding: 0; margin: 0;} </style>
</head>
<body>
</body>
</html>
When I do the same in Shiny, running the code from R-Studio I do not get anything from it. I have stored the javascript files in the www folder as it is supposed to be and I currently know that my HTML called the javascript since I set an alert in the p5 javascript file, but outside the setup and draw methods. The problem is that, even though the alert is loaded, seems like the setup and draw methods are not called and, obviously, as a consequence, they do not load the canvas. I know that they are not called because I have a called to an alert in the setup method that works running the HTML file directly but not if I run the same file from R-Studio.
Here it is the p5 javascript code:
alert("GOOD1");
function setup() {
alert("GOOD2");
createCanvas(640, 480);
}
function draw() {
if (mouseIsPressed) {fill(0);}
else {fill(255);}
ellipse(mouseX, mouseY, 80, 80);
}
I load the HTML page in Shiny using the next line of code
... ,tabItem(tabName = "tabProcessing", htmlOutput("processingMasterThesis") ...
Attach to the tag "processingMasterThesis" I have the corresponding URL to the HTML file in the server.R, as it is supposed to be so the problem is not here.
Why may be the cause of this? It works if I call the HTML file directly to be load in the browser but not if I do it from R-Studio, why?
I have solved the problem. The p5 java script code will be:
// =====================
// "app/sketch.js"
// =====================
var myCanvas;
function setup() {
var idCanvas = 'divCanvas';
myCanvas = createCanvas(300, 300);
myCanvas.parent(idCanvas);
}
function draw() {
if (mouseIsPressed) {
fill(0);
} else {
fill(255);
}
ellipse(mouseX, mouseY, 80, 80);
}
The library you need to run the example can be found at https://p5js.org/
In this javascript file I have created an id that reference a html div element so that is the place where I will set my canvas. Once this is done, the rest of the javascript code will code perfectly. The point is to reference that the parent of the canvas is that div as you can see in the code.
After this you just have to create either in shiny or pure html code something like this:
# THE UI (File ui.R)
library(shiny)
library(shinydashboard)
library(rmarkdown)
shinyUI(
fluidRow(
# THE UI
tags$html(
tags$body(
singleton(tags$head(tags$script(src = "master_thesis/app/libraries/p5.js")))
,singleton(tags$head(tags$script(src = "master_thesis/app/sketch.js")))
,singleton(tags$div(id = 'divCanvas', style = 'width:auto; height:auto'))
))
)
)
The code that I show below is in shiny. The first "head" line include the library p5.js and the second "head" line just say "hey this is my p5 script file" and "divCanvas will be the div that I will print on".
You may have issues with the references to the javascript file. I think is worthy to note that you must create a www folder in your root shiny application. In this folder, you must put your javascript files. For example, as you can see in my code the two javascript files that I am using follow the next path:
ShinyApplication/www/app/libraries/p5.js
ShinyApplication/www/app/sketch.js
Hope this can help!

Pisa arabic rendering issue using xhtml2pdf and reportlab

Arabic goes wrong displayed on output pdf with the following code:
template = get_template(template_src)
context = Context(context_dict)
html = template.render(context)
result = StringIO.StringIO()
pdf = pisa.pisaDocument(StringIO.StringIO(
html.encode(pdf_encoding)), result, encoding=pdf_encoding) # pdf_encoding = 'utf-8'
and in the template I set charset and fonts:
<meta http-equiv="content-type" content="text/html; charset=utf-8">
#font-face {
font-family: AmiriRegular;
src: url(/usr/share/fonts/opentype/fonts-hosny-amiri/amiri-regular.ttf);
}
body { font-family: AmiriRegular; }
the output:
The Arabic text in snapshot is supposed to be:
ياسر حسن
I think one solution is to pass those arabic text manually and reshape them using these two libraries:
import arabic_reshaper
from bidi.algorithm import get_display
reshaped_text = arabic_reshaper.reshape('your desired text in arabic')
bidi_text = get_display(reshaped_text)

Trouble with urllib calls in Python. Getting server error

I am trying to download an XML file from the Eurostat website but I am having trouble using urllib in Python to do it. Somehow when I use my regular Chrome browser it's able to make the HTTP request and the website will generate an XML file, but when I try to do the same thing in python I get a server error. This is the code I am using:
import urllib
from xml.etree import ElementTree as ET
response = urllib.urlopen("http://ec.europa.eu/eurostat/SDMX/diss-web/rest/data/lfsq_egais/Q.T.Y_GE15.EMP..NL")
result = response.read()
print result
I have tried using urllib.urlretrieve too and that didn't work either. Any reason why this might be happening? The HTML I get back is as follows:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Draft//EN">
<HTML>
<HEAD>
<TITLE>Error 500--Internal Server Error</TITLE>
<META NAME="GENERATOR" CONTENT="WebLogic Server">
</HEAD>
<BODY bgcolor="white">
<FONT FACE=Helvetica><BR CLEAR=all>
<TABLE border=0 cellspacing=5><TR><TD><BR CLEAR=all>
<FONT FACE="Helvetica" COLOR="black" SIZE="3"><H2>Error 500--Internal Server Error</H2>
</FONT></TD></TR>
</TABLE>
<TABLE border=0 width=100% cellpadding=10><TR><TD VALIGN=top WIDTH=100% BGCOLOR=white><FONT FACE="Courier New"><FONT FACE="Helvetica" SIZE="3"><H3>From RFC 2068 <i>Hypertext Transfer Protocol -- HTTP/1.1</i>:</H3>
</FONT><FONT FACE="Helvetica" SIZE="3"><H4>10.5.1 500 Internal Server Error</H4>
</FONT><P><FONT FACE="Courier New">The server encountered an unexpected condition which prevented it from fulfilling the request.</FONT></P>
</FONT></TD></TR>
</TABLE>
</BODY>
</HTML>
This question is a few months old now, but better late than never:
The Eurostat REST API you are talking is supposed to respond with XML content, which urllib is not expecting/allowing by default. The solution is to add a header Accept: application/xml to the request.
This will do the trick in Python 2.7 (using urllib2 by the way):
import urllib2
req = urllib2.Request("http://ec.europa.eu/eurostat/SDMX/diss-web/rest/data/"
"lfsq_egais/Q.T.Y_GE15.EMP..NL")
req.add_header("Accept", "application/xml")
response = urllib2.urlopen(req)
print response.read()
See urllib2 docs for more info and examples.