Django中使用Reportlab生成PDF

August 21, 2014 | 07:53 python Django

在Django的官方文档中,提到使用Reportlab的方法。尽管不算复杂,但在实际使用过程中还是遇到了种种问题,在此也稍微记录一下。

安装

Reportlab的安装很方便,跟许多python库一样,$ sudo pip install reportlab即可。之后Reportlab的包会被自动安装到python的site-packages下,留意这个位置,之后我们需要往里面添加字体文件。

使用

正如官方文档介绍的那样,我们可以用下面的方式来制作第一个PDF:

from reportlab.pdfgen import canvas
from django.http import HttpResponse

def gen_pdf(request):
    response = HttpResponse(content_type='application/pdf')
    response['Content-Disposition'] = 'attachment; filename="somefilename.pdf"'
    c = canvas.Canvas(response)
    c.drawString(100, 100, "Hello world.")
    c.showPage()
    c.save()
    return response

定义好方法后,我们可以为它定义一条url来访问,就可以下载到生成的PDF了。

中文

这里所说的中文,是泛指Unicode字符。因为你如果直接按照上面所说的方法,是不能生成中文的PDF的。要么是程序出错,要么是打印出来空白字符。原因不复杂,无外乎两个:编码不支持、字体不支持。我们一条条解决。

先说编码,python3.x的一个显著的特性就是源码默认为utf-8编码,而在python2.x下,我们则要显式地为其设置编码格式,在文件开头加上:# -*- coding: utf-8 -*-,这样便可以直接使用中文字符,如:

c.drawString(0, 0, '你好')

但需要注意的是,在为PDF设置文件头时,如果我们需要输出中文名称的PDF,如我们使用模型实例的属性,如user.name之类,还需要将编码转换,变成utf-8格式:

filename = user.name.encode('utf8')
response['Content-Disposition'] = 'attachment; filename="' + filename + '.pdf"'

接下来说说字体,Reportlab中,我们可以使用setFont()方法设置字体字号,如c.setFont("Helvetica", 14)。不过其中却不含中文字体,我们需要手动添加。添加的过程如下:

  1. 找到Reportlab的安装目录,打开目录下的fonts文件夹;
  2. 将你所用到的ttf字体文件复制到该目录下;
  3. 在方法中注册并调用该字体,以黑体(SimHei)为例:

    from reportlab.pdfbase import pdfmetrics
    from reportlab.pdfbase import pdfmetrics
    from reportlab.pdfbase.ttfonts import TTFont
    
    def gen_pdf(request): 
      pdfmetrics.registerFont(TTFont('SimHei','SimHei.ttf')) 
      for facename in ['SimHei']: 
        addMapping(facename, 0, 0, facename) #normal 
        addMapping(facename, 0, 1, facename) #italic
        addMapping(facename, 1, 0, facename) #bold
        addMapping(facename, 1, 1, facename) #italic and bold
    
  4. 当然,只为一种字体设置,不一定要用列表循环。

这样,我们就可以通过Reportlab来输出含有中文字符的PDF了。

语法

关于Reportlab的语法,目前也没有仔细研究,粗看上去与HTML5中canvas的语法有些区别。同样是先设置好画笔的状态(线条、填充、字体等),不过HTML5中的canvas有个光标点的概念,得先moveTo(x0, y0),才能lineTo(x1, y1)画线。而在这里是直接一步做完:c.line(x0, y0, x1, y1)。再详细的API,这里就先不提了,如果之后有什么心得会再记录下来的。可以查看官方的PDF文档。(吐槽一句,这PDF其实做得挺一般的,选择文本时经常会选到整个页面)

成果

最后,贴两张为最近ERP项目制作的名片吧,大概制作的初稿,尽量就别吐槽了~

中文名片

英文名片

Creative Commons BY-NC-ND 3.0