如何在python中使用reportlab,rtl和bidi创建包含波斯语(波斯语)文本的PDF

r.a*_*.aj 6 pdf reportlab persian python-3.x farsi

我一直在尝试从可以是英语、波斯语、数字或它们的组合的内容创建 PDF 文件。

波斯语文本存在一些问题,例如:“??? ?? ??? ??????? ???”

?- 文字必须从右到左书写

2-单词中不同位置的字符之间存在差异(意味着字符会根据周围的字符改变形状)

3- 因为句子是从右到左阅读的,所以普通的 textwrap 不能正常工作。

r.a*_*.aj 7

我使用 reportlab 来创建 PDf,但不幸的是,reportlab 不支持阿拉伯语和波斯语字母表,所以我使用了 Vahid Mardani 的“rtl”库和 Meir Kriheli 的“pybidi”库来使文本在 PDF 结果中看起来正确。

首先我们需要在reportlab中添加一个支持波斯语的字体:

  1. 在 Ubuntu 14.04 中:

    copy Bahij-Nazanin-Regular.ttf into
    /usr/local/lib/python3.4/dist-packages/reportlab/fonts folder
    
    Run Code Online (Sandbox Code Playgroud)
  2. 将字体和样式添加到 reportlab:

    from reportlab.lib.enums import TA_RIGHT
    from reportlab.pdfbase import pdfmetrics
    from reportlab.pdfbase.ttfonts import TTFont
    pdfmetrics.registerFont(TTFont('Persian', 'Bahij-Nazanin-Regular.ttf'))
    styles = getSampleStyleSheet()
    styles.add(ParagraphStyle(name='Right', alignment=TA_RIGHT, fontName='Persian', fontSize=10))
    
    Run Code Online (Sandbox Code Playgroud)

在下一步中,我们需要将波斯文本 Letters 重塑为正确的形状,并使每个单词的方向从右到左:

    from bidi.algorithm import get_display
    from rtl import reshaper
    import textwrap

    def get_farsi_text(text):
        if reshaper.has_arabic_letters(text):
          words = text.split()
          reshaped_words = []
          for word in words:
            if reshaper.has_arabic_letters(word):
              # for reshaping and concating words
              reshaped_text = reshaper.reshape(word)
              # for right to left    
              bidi_text = get_display(reshaped_text)
              reshaped_words.append(bidi_text)
            else:
              reshaped_words.append(word)
          reshaped_words.reverse()
         return ' '.join(reshaped_words)
        return text
Run Code Online (Sandbox Code Playgroud)

对于添加项目符号或包装文本,我们可以使用以下功能:

    def get_farsi_bulleted_text(text, wrap_length=None):
       farsi_text = get_farsi_text(text)
       if wrap_length:
           line_list = textwrap.wrap(farsi_text, wrap_length)
           line_list.reverse()
           line_list[0] = '{} •'.format(line_list[0])
           farsi_text = '<br/>'.join(line_list)
           return '<font>%s</font>' % farsi_text
       return '<font>%s &#x02022;</font>' % farsi_text
Run Code Online (Sandbox Code Playgroud)

为了测试我们可以编写的代码:

    from reportlab.lib.pagesizes import letter
    from reportlab.platypus import SimpleDocTemplate, Paragraph
    from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle

    doc = SimpleDocTemplate("farsi_wrap.pdf", pagesize=letter,    rightMargin=72, leftMargin=72, topMargin=72,
                    bottomMargin=18)
    Story = []

    text = '???? ???? ??????? ???? ???? ???? ???????? ???????? ???? ???? ????? ??? ??? ???? ??? ?? ???????? ????? ?? ???' \
   '?? ????? ??????? ?? ???? ???? ????? ????? ?? ?? ????? ?????? ??????? ???? ????????. ??? ?? ??? ?? ??????? ????' \
   ' ???? ???? ???????? ?? ????????? ?? ????? ????? ?? ?? ?? ???? ?? ????????? ?????? ????? ??? ? ??? ?? ????? ??' \
   ' ????? ????. ????? ?? ?????? ?? ??? ?????? ?? ???? ???????? ??????? ?? ????????? ??????? ????. ??????? ?????? iOS ' \
   '??? ??????? ????? ?? ??????? ?? ???????? ? ???????????? ????? ????? ??? ??????. ???????? ????? ?? ?????? ????? ???' \
   '? ?? ?????? ?? ??? ????? ??????? ????. ?? ??? ??? ???? ??????? ????? ???? ???? ?? ???? ??? ??? ?? ?? ??? ????? ??' \
   ' ?????????.'
    tw = get_farsi_bulleted_text(text, wrap_length=120)
    p = Paragraph(tw, styles['Right'])
    Story.append(p)
    doc.build(Story)
Run Code Online (Sandbox Code Playgroud)


r.a*_*.aj 5

在使用 Reportlab 工作一段时间后,我们在组织和格式化它时遇到了一些问题。这花了很多时间,而且有点复杂。所以我们决定使用 pdfkit 和 jinja2。这样我们就可以在 html 和 CSS 中格式化和组织,而且我们也不需要重新格式化波斯文本。

首先我们可以设计一个像下面这样的html模板文件:

    <!DOCTYPE html>
        <html>
        <head lang="fa-IR">
            <meta charset="UTF-8">
            <title></title>
        </头>
        <身体>
            <p dir="rtl">???????</p>
            <ul dir="rtl">
                {% 体验经验 %}
                <li><a href="{{ Experience.url }}">{{ Experience.title }}</a></li>
                {% 结束为 %}
            </ul>
        </正文>
        </html>

然后我们使用 jinja2 库将我们的数据渲染到模板中,然后使用 pdfkit 从渲染结果创建一个 pdf:

    from jinja2 import Template
    from pdfkit import pdfkit

    sample_data = [{'url': 'http://www.google.com/', 'title': '????'},
                   {'url': 'http://www.yahoo.com/fa/', 'title': '????'},
                   {'url': 'http://www.amazon.com/', 'title': '??????'}]

    with open('template.html', 'r') as template_file:
        template_str = template_file.read()
        template = Template(template_str)
        resume_str = template.render({'experiences': sample_data})

        options = {'encoding': "UTF-8", 'quiet': ''}
        bytes_array = pdfkit.PDFKit(resume_str, 'string', options=options).to_pdf()
        with open('result.pdf', 'wb') as output:
            output.write(bytes_array)
Run Code Online (Sandbox Code Playgroud)