Reputation: 9385
I want to generate PDF reports in different languages. I've followed different guides that are using TTFont. I've tried in different languages but no one is working.
For example, for Russian, I use:
self.buffer = BytesIO()
self.pdf_data = []
pdfmetrics.registerFont(TTFont('DejaVuSerif', self.font_dir + 'dejavuserif/DejaVuSerif.ttf'))
font_name = "DejaVuSerif"
self.styles = getSampleStyleSheet()
self.styles.add(ParagraphStyle(name = "HeaderTitle", parent = self.styles['Title'], alignment = TA_CENTER, fontName=font_name))
doc = SimpleDocTemplate(self.buffer)
self.pdf_data.append(Paragraph('Операции - Отчет Август 2020 г.', self.styles['HeaderTitle']))
doc.build(self.pdf_data)
pdf = self.buffer.getvalue()
self.buffer.close()
But the output is:
€•‚ƒ„…†† - €‡ˆ‚‡ „‰Š‹Œ‡ 2020 Š.
What I'm doing wrong?
ReportLab version = 3.5.50
UPDATE
I want to point that in locale the file is correct, but when I attach in a response, the problem persists.
return flask.send_from_directory(file_path, filename, mimetype="application/pdf", as_attachment=True, attachment_filename=filename, cache_timeout=0)
Upvotes: 1
Views: 2509
Reputation: 27106
The part of the code you show looks good. In the variable 'pdf' you get back the bytes of the PDF.
One can return the bytes with a flask response like this:
@app.route('/')
def gen_pdf():
pdf_util = PDFUtil()
pdf_bytes = pdf_util.generate()
response = make_response(pdf_bytes)
response.headers.set('Content-Type', 'application/pdf')
return response
Please note that the Content-Type
header needs to be set to: application/pdf
. If you want the browser to download the PDF file instead of displaying it inline, you can add an additional header, e.g:
response.headers.set('Content-Disposition', 'attachment', filename='test.pdf')
So if the font is fine and you these bytes are returned with content-type application/pdf
the correct result will be displayed in a browser.
I have only slightly modified your code, saved it in a python script named pdf_flask_demo.py
to get a self-contained example with flask response part:
from io import BytesIO
from reportlab.lib.enums import TA_CENTER
from reportlab.lib.styles import ParagraphStyle, getSampleStyleSheet
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.platypus import SimpleDocTemplate, Paragraph
from flask import Flask, make_response
app = Flask(__name__)
@app.route('/')
def gen_pdf():
pdf_util = PDFUtil()
pdf_bytes = pdf_util.generate()
response = make_response(pdf_bytes)
response.headers.set('Content-Type', 'application/pdf')
return response
class PDFUtil:
def __init__(self):
self.font_dir = "./"
def generate(self):
self.buffer = BytesIO()
self.pdf_data = []
pdfmetrics.registerFont(TTFont('DejaVuSerif', self.font_dir + 'dejavuserif/DejaVuSerif.ttf'))
font_name = "DejaVuSerif"
self.styles = getSampleStyleSheet()
self.styles.add(
ParagraphStyle(name="HeaderTitle", parent=self.styles['Title'], alignment=TA_CENTER, fontName=font_name))
doc = SimpleDocTemplate(self.buffer)
self.pdf_data.append(Paragraph('Операции - Отчет Август 2020 г.', self.styles['HeaderTitle']))
doc.build(self.pdf_data)
pdf = self.buffer.getvalue()
self.buffer.close()
return pdf
Alternative
One can also save the PDF file in the local file system and return it flask.send_from_directory
. The downloaded PDF on the users browser can then also be displayed correctly when opened in a PDF viewer.
@app.route('/')
def gen_pdf():
pdf_util = PDFUtil()
pdf_bytes = pdf_util.generate()
f = open('/Users/stephan/tmp/mytest.pdf', 'wb')
f.write(pdf_bytes)
f.close()
return flask.send_from_directory('/Users/stephan/tmp/', 'mytest.pdf', mimetype="application/pdf", as_attachment=True,
attachment_filename='mytest.pdf', cache_timeout=0)
Test
On command line I call:
export FLASK_APP=pdf_flask_demo
export FLASK_ENV=development
flask run
And when using http://127.0.0.1:5000
in the browser I get the desired result:
Upvotes: 3