首页 > 解决方案 > ReportLab PDF Python 3 字体问题

问题描述

我想生成不同语言的 PDF 报告。我遵循了使用 TTFont 的不同指南。我尝试过使用不同的语言,但没有人在工作。

例如,对于俄语,我使用:

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()

但输出是:

€•‚ƒ„…†† - €‡‚‚‡ „‰Š‹Œ‡ 2020 Š。

我做错了什么?

报告实验室版本 = 3.5.50

更新

我想指出,在语言环境中文件是正确的,但是当我附加响应时,问题仍然存在。

return flask.send_from_directory(file_path, filename, mimetype="application/pdf", as_attachment=True, attachment_filename=filename, cache_timeout=0)

标签: python-3.xreportlab

解决方案


您显示的代码部分看起来不错。在变量“pdf”中,您可以取回 PDF 的字节。

可以使用如下所示的烧瓶响应返回字节:

@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

请注意,Content-Type标题需要设置为:application/pdf. 如果您希望浏览器下载 PDF 文件而不是内联显示,您可以添加额外的标题,例如:

response.headers.set('Content-Disposition', 'attachment', filename='test.pdf')

因此,如果字体很好,并且这些字节与内容类型一起返回,application/pdf则正确的结果将显示在浏览器中。

我只是稍微修改了您的代码,将其保存在一个名为的 python 脚本中pdf_flask_demo.py,以获得一个带有烧瓶响应部分的自包含示例:

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

选择

也可以将PDF文件保存在本地文件系统中并返回flask.send_from_directory。当在 PDF 查看器中打开时,用户浏览器上下载的 PDF 也可以正确显示。

@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)

测试

在命令行我调用:

export FLASK_APP=pdf_flask_demo
export FLASK_ENV=development 
flask run

在浏览器中使用http://127.0.0.1:5000时,我得到了想要的结果:

测试运行


推荐阅读