可参考内容:

Python学习——使用ReportLab生成带表格和图文的PDF - 知乎

【Python 实战】一键生成 PDF 报告,图文并茂,代码全公开_python 生成 pdf 报告模块 - CSDN 博客

4.7. 使用 reportlab 模块 — Python 3 教程 文档

一、ReportLab 简介

ReportLab 是一个 Python 用于生成指定格式、复杂的 PDF 库,自定义程度很高,可以生成文字、图片、表格(复杂表格)、控制页面的各种格式的软件库。

ReportLab 对 PDF 的操作分为了几个层级,从上到下,依次为:

DocTemplates:文档的最外层容器;

PageTemplates:各种页面布局容器;

Frames:页面中放置文本,图像的区块;

Flowables:可排列的文本或者图像元素,包含图片、段落、表格、分隔符等等,但不包含页脚和固定位置的页面图像。

Canvas:接收所有其它层级信息并绘制文档的最底层。

DocTemplate结构示意图

二、字体设置

如果要使用中文字体,需要在 reportlab 里注册,方法如下:

1
2
3
4
5
6
7
8
9
10
11
# 从reportlab.pdfbase模块导入pdfmetrics,用于注册字体
from reportlab.pdfbase import pdfmetrics
# 从reportlab.pdfbase.ttfonts模块导入TTFont类,TTFont用于处理TrueType字体
from reportlab.pdfbase.ttfonts import TTFont

# 定义字体文件的路径(例如使用了“MicrosoftYaHei.ttf”字体文件)
font_path = 'MicrosoftYaHei.ttf' # 字体路径(如果只指定字体名,程序会在当前目录下寻找字体文件)

# 注册字体,将字体文件与字体名称关联
# 'hei' 是你给该字体指定的名称,font_path 是字体文件的路径
pdfmetrics.registerFont(TTFont('hei', font_path)) # 注册名为'hei'的字体,并关联对应的TrueType字体文件

在某些地方需要使用字体的时候,只需要把字体设置为 hei 即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
def draw_text(self, text: str):
# 获取普通样式
ct = self.style['Normal']
ct.fontName = 'hei'
ct.fontSize = 12
ct.leading = 1.5 * ct.fontSize # 行间距
ct.wordWrap = 'CJK' # 设置自动换行
ct.alignment = 0 # 左对齐
ct.firstLineIndent = 0 # 第一行开头空格
# ct.leading = 25
# 将 \n 替换为 <br/> 标签
text = text.replace('\n', '<br/>')
return Paragraph(text, ct)

[!TIP]

和 matplotlab 联动的时候(用 matplotlab 绘制各种图表),需要按照 matplotlab 的字体设置方式进行设置:

1
2
3
4
from matplotlib import font_manager
## 使用指定路径加载自定义字体
# _font_path是字体文件的路径,FontProperties类用来创建一个字体属性对象
custom_font = font_manager.FontProperties(fname=_font_path)

对于各种统计图,如直方图、饼图、折线图等,建议在绘制函数的参数指定字体,如对于饼图里的字体问题,建议使用 textprops 参数,而不是 rcParams 参数。title中也指定 fontproperties 参数

三、Paragraph 的使用

创建 Paragraph 实例

Paragraph 类是 ReportLab 中用于创建和渲染文本的核心类之一。它位于 reportlab.platypus 模块中,主要用于处理段落文本内容,并支持样式、对齐、自动换行等功能。

[!TIP]

建议涉及文本的内容,都转换为 Paragraph 进行使用,方便对于文字的样式进行各种个性化设置。

创建一个 Paragraph 实例:

1
2
3
4
5
Paragraph(
text, # 段落的文本字符串。支持内嵌的简单HTML标签(如<b>、<i>等),用于格式化文本。
style, # 定义该段落的样式设置,例如字体、字号、行间距、对齐方式、颜色等。
bulletText=None # 可选参数,用于在段落前显示项目符号或编号。如果不需要项目符号,保持默认值 None。
)

text 为段落文本,style为段落样式,bulletText

对于文档中的各个标题,可以使用不同样式的 Paragraph 作为不同等级的标题:

一级标题:

1
2
3
4
5
6
7
8
9
10
11
12
def draw_1_title(self, title1: str):
# 拿到标题样式
ct = self.style['Heading1']
# 单独设置样式相关属性
ct.fontName = 'hei' # 字体名
ct.fontSize = 20 # 字体大小
ct.leading = 1.5 * ct.fontSize # 行间距
ct.spaceBefore = 4 # 一级标题前的距离
ct.spaceAfter = 4 # 一级标题后的距离
ct.textColor = colors.black # 字体颜色
ct.alignment = 1 # 居中
return Paragraph(title1, ct)

对于其他级别的标题,可以根据需求设置字体、字体大小、行间距以及段前段后距离。

Paragraph 样式

Paragraphs 的默认样式,一般用得到的也就那么多了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
class ParagraphStyle(PropertySet):
defaults = {
'fontName': _baseFontName, # 设置段落的字体名称,默认为基本字体
'fontSize': 10, # 字体大小,默认为 10
'leading': 12, # 行间距,默认为 12
'leftIndent': 0, # 左缩进,默认为 0
'rightIndent': 0, # 右缩进,默认为 0
'firstLineIndent': 0, # 第一行缩进,默认为 0
'alignment': TA_LEFT, # 对齐方式,默认为左对齐(TA_LEFT)
'spaceBefore': 0, # 段落前的间距,默认为 0
'spaceAfter': 0, # 段落后的间距,默认为 0
'bulletFontName': _baseFontName, # 项符号的字体名称,默认为基本字体
'bulletFontSize': 10, # 项符号字体的大小,默认为 10
'bulletIndent': 0, # 项符号的缩进,默认为 0
# 'bulletColor': black, # 项符号的颜色,默认为黑色(此项被注释)
'textColor': black, # 文本颜色,默认为黑色
'backColor': None, # 背景颜色,默认为 None(无背景颜色)
'wordWrap': None, # 自动换行设置,默认为 None(不做特殊处理)
# CJK(中文)使用中文换行,LTR(从左到右)和 RTL(从右到左)使用常规的方向
# 如果可用的话,支持 pyfribi2
'borderWidth': 0, # 边框宽度,默认为 0(没有边框)
'borderPadding': 0, # 边框内边距,默认为 0
'borderColor': None, # 边框颜色,默认为 None(无边框颜色)
'borderRadius': None, # 边框圆角半径,默认为 None(无圆角)
'allowWidows': 1, # 是否允许孤行,默认为 1(允许孤行)
'allowOrphans': 0, # 是否允许遗孤行,默认为 0(不允许遗孤行)
'textTransform': None, # 字符转换(如大写、小写),默认为 None
# 支持的值:uppercase(大写),lowercase(小写),capitalize(首字母大写)等
'endDots': None, # 最后一行左/右对齐段落的点缀(如省略号),默认为 None
# 可为字符串或对象,包含文本、字体、大小、颜色等设置
'splitLongWords': 1, # 是否允许拆分长单词,默认为 1(允许拆分)
'underlineWidth': _baseUnderlineWidth, # 下划线的宽度,默认为基准宽度
'bulletAnchor': 'start', # 项符号的锚定位置,默认为 'start'(开始位置)
# 可选值:start, middle, end 或数字
'justifyLastLine': 0, # 是否允许对最后一行进行对齐,默认为 0(不进行对齐)
'justifyBreaks': 0, # 是否在 <br/> 标签处进行对齐,默认为 0(不对齐)
'spaceShrinkage': _spaceShrinkage, # 是否允许根据百分比收缩空间以适应行宽,默认为默认设置
'strikeWidth': _baseStrikeWidth, # 删除线的宽度,默认为基准宽度
'underlineOffset': _baseUnderlineOffset, # 下划线的偏移量,默认为基准偏移值
'underlineGap': _baseUnderlineGap, # 双下划线/三下划线的间距,默认为基准值
'strikeOffset': _baseStrikeOffset, # 删除线的偏移量,默认为基准偏移值
'strikeGap': _baseStrikeGap, # 删除线间距,默认为基准值
'linkUnderline': _platypus_link_underline, # 超链接的下划线设置,默认为默认设置
'underlineColor': None, # 下划线颜色,默认为 None(无颜色)
'strikeColor': None, # 删除线颜色,默认为 None(无颜色)
'hyphenationLang': _hyphenationLang, # 自动连字符语言,默认为默认语言设置
# 'hyphenationMinWordLength': _hyphenationMinWordLength, # 连字符最小词长度(被注释)
'embeddedHyphenation': _embeddedHyphenation, # 是否启用内嵌连字符,默认为默认设置
'uriWasteReduce': _uriWasteReduce, # 是否减少 URI 字符串浪费,默认为默认设置
}

四、Tables 的使用

创建 Table 实例

reportlab 的表格功能十分强大,可以生成各种各样的表格,甚至是嵌套表格。Tables 的一般用法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
Table(
data, # 必须参数,表格数据,是一个二维列表(每个内层列表代表一行,行中的每个元素为单元格内容)
colWidths=None, # 列宽设置,可以是一个数值列表,指定每列的宽度。如果为 None,自动计算宽度
rowHeights=None, # 行高设置,可以是一个数值列表,指定每行的高度。如果为 None,自动计算高度
style=None, # 表格样式,默认为 None,通过 TableStyle 类定义表格样式(例如字体、边框、对齐方式等)
splitByRow=1, # 是否按行拆分跨页显示的表格。如果为 1,表示允许按行拆分;如果为 0,表示不拆分
repeatRows=0, # 设置要在每页顶部重复显示的行数。如果为 0,则不重复任何行
repeatCols=0, # 设置要在每页左侧重复显示的列数。如果为 0,则不重复任何列
rowSplitRange=None, # 指定行拆分的范围,通常用来控制表格拆分的行为。默认为 None,表示不进行行拆分
spaceBefore=None, # 表格前的空白间距,默认为 None,表示使用默认的间距
spaceAfter=None, # 表格后的空白间距,默认为 None,表示使用默认的间距
cornerRadii=None # 设置表格四周圆角半径。可以是单一的数值,或者四个不同角的数值列表。如果为 None,表示没有圆角
)

[!NOTE]

  1. 这里的 data 如果二维列表中的某一行,还是列表,这个时候 reportlab 会把它解析为一个嵌套列表(可以理解为合并单元格的效果)。

  2. 如果 data 的不同行的个数不同,reportlab 会自动识别列数最少的列把它作为每一列的个数,如对于 [ [1], [1, 2, 3] ],reportlab 会识别为两行一列的表格,也就是两行 1。

  3. splitByRow 在使用的时候,如果某一行的高度超过了一页,就会报错,需要额外调整。

创建 Table 实例方法的简单样例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def draw_table(data):

style = TableStyle(
[
('FONTNAME', (0, 0), (-1, -1), 'hei'), # 全表字体
('VALIGN', (0, 0), (-1, -1), 'MIDDLE'), # 所有表格上下居中对齐
('TEXTCOLOR', (0, 0), (-1, -1), colors.black), # 设置表格内文字颜色
('ALIGN', (0, 0), (-1, -1), 'CENTER'), # 所有行水平居中
]
)

# 列宽度,指定四列
col_width = [100, 100, 100, 100]

style.add('SPAN', (0, 0), (1, 0)) # 合并第一行的前两列单元格
style.add('SPAN', (2, 0), (3, 0)) # 合并第一行的后两列单元格

return Table(args, colWidths=col_width, style=style, splitByRow=True)

TableStyle 样式

表格样式 TableStyle 主要分为 3 类,分别为:单元格式命令、行命令、合并命令。

表格样式的创建例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
LIST_STYLE = TableStyle(
[
# 在表格的第一行(索引0)上方绘制一条宽度为2点、绿色的线,
# 坐标范围:(0,0) 到 (-1,0) 表示第一行所有列。
('LINEABOVE', (0, 0), (-1, 0), 2, colors.green),

# 从第二行(索引1)开始直到最后一行(-1),在每一行的上方绘制一条宽度为0.25点、黑色的线,
# 坐标范围:(0,1) 到 (-1,-1) 表示除第一行之外所有行的上方线条。
('LINEABOVE', (0, 1), (-1, -1), 0.25, colors.black),

# 在表格的最后一行(-1)的下方绘制一条宽度为2点、绿色的线,
# 坐标范围:(0,-1) 到 (-1,-1) 表示最后一行所有列的下方边线。
('LINEBELOW', (0, -1), (-1, -1), 2, colors.green),

# 将从第二行的第二列(索引1,1)到最后一行的所有单元格内容右对齐,
# 坐标范围:(1,1) 到 (-1,-1) 表示除第一列和第一行外所有区域。
('ALIGN', (1, 1), (-1, -1), 'RIGHT')
]
)

TableStyle 用户方法

添加样式到 TableStyle

向一个 TableStyle 实例加入一个样式设置:

1
TableStyle.add(commandSequence)

例子:

1
LIST_STYLE.add('BACKGROUND', (0,0), (-1,0), colors.Color(0,0.7,0.7))

获取样式命令

获取 TableStyle 所有定义的样式命令:

1
cmds = LIST_STYLE.getCommands()

TableStyle 单元格式命令

使用 TableStyle 之前,需要注意坐标参数:

这个坐标参数代表的含义是从第一个坐标参数开始,到第二个坐标参数结束。

如上面的 LIST_STYLE.add('BACKGROUND', (0,0), (-1,0), colors.Color(0,0.7,0.7)),指的就是从 (0, 0) 位置开始,到 (-1, 0) 位置结束,每个位置参数的第一位代表列、第二位代表行,先列后行。这里第二位都是 0,则表示都是第一行;第一位从 0 到 -1,则表示所有的列。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
FONT - 设置字体,同时可指定字体名称、字号和行距。
# 例:
('FONT', (0, 0), (-1, -1), 'Helvetica') # 设置全表的字体为 Helvetica


FONTNAME (或 FACE) - 只设置字体名称。
# 例:
('FONTNAME', (0, 0), (-1, -1), 'Helvetica') # 全表字体设置为 Helvetica


FONTSIZE (或 SIZE) - 设置字体大小(单位为点)。
# 注意:单独设置字号时,行距(leading)可能会与预期不同步。
# 例:
('FONTSIZE', (0, 0), (-1, -1), 10) # 设置字体大小为 10


LEADING - 设置行距(单位为点)。
# 例:
('LEADING', (0, 0), (-1, -1), 14) # 设置全表行间距为 14


TEXTCOLOR - 设置文本颜色,可以使用颜色名称或 (R, G, B) 元组。
# 例:
('TEXTCOLOR', (0, 0), (-1, -1), colors.red) # 设置字体颜色为红色


ALIGNMENT (或 ALIGN) - 设置文本的对齐方式,可选值包括 LEFT、RIGHT、CENTRE(或 CENTER)和 DECIMAL。
# 例:
('ALIGN', (0, 0), (-1, -1), 'CENTER') # 设置全表字体居中对齐


LEFTPADDING - 设置单元格左内边距,默认值为6
# 例:
('LEFTPADDING', (0, 0), (-1, -1), 10) # 设置所有单元格的左内边距为 10 点


RIGHTPADDING - 设置单元格右内边距,默认值为6
# 例:
('RIGHTPADDING', (0, 0), (-1, -1), 10) # 设置所有单元格的右内边距为 10 点


BOTTOMPADDING - 设置单元格底部内边距,默认值为3
# 例:
('RIGHTPADDING', (0, 0), (-1, -1), 10) # 设置所有单元格的右内边距为 10 点


TOPPADDING - 设置单元格顶部内边距,默认值为3
# 例:
('BOTTOMPADDING', (0, 0), (-1, -1), 5) # 设置所有单元格的底部内边距为 5 点


BACKGROUND - 设置单元格背景色,可以是颜色对象、颜色名称或数值元组/列表。
# 也可传入一个包含三项的列表/元组描述渐变填充,格式为:
# [DIRECTION, startColor, endColor],
# 其中 DIRECTION 可为 VERTICAL 或 HORIZONTAL。
# 例:
# 设置单元格的背景颜色为蓝色
('BACKGROUND', (0, 0), (-1, -1), colors.blue)
# 设置从白色到蓝色的垂直渐变背景
('BACKGROUND', (0, 0), (-1, -1), ['VERTICAL', colors.white, colors.blue])


ROWBACKGROUNDS - 接受一个颜色列表,用于循环设置每行的背景色。
# 例:
# 设置表格行的背景颜色,交替使用浅灰色和白色
('ROWBACKGROUNDS', [colors.lightgrey, colors.white])


COLBACKGROUNDS - 接受一个颜色列表,用于循环设置每列的背景色。
# 例:
# 设置表格列的背景颜色,交替使用浅蓝色和白色
('COLBACKGROUNDS', [colors.lightblue, colors.white])


VALIGN - 设置单元格中内容的垂直对齐方式,可选值为 TOP、MIDDLE 或默认的 BOTTOM。
# 例:
# 设置所有单元格的内容垂直居中对齐
('VALIGN', (0, 0), (-1, -1), 'MIDDLE')

TableStyle 行命令

行命令可以灵活地控制表格的线条样式。每个命令的作用是指定某些单元格区域的边框或者其他线条的样式。具体命令的格式包括 起始和结束单元格的坐标线条粗细线条颜色

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
GRID - 相当于同时使用 BOX 和 INNERGRID。
它会在表格的每个单元格周围绘制边框,并在表格的所有单元格之间绘制内部网格线。
# 例:
('GRID', (0, 0), (-1, -1), 1, colors.black) # 绘制整个表格的网格线,线条粗细为 1 点,颜色为黑色


BOX - 绘制整个表格的外边框,类似于给整个表格加一个边框线。
# 例:
('BOX', (0, 0), (-1, -1), 2, colors.blue) # 给整个表格添加一个 2 点粗的蓝色边框


OUTLINE - 和 BOX 命令等价,都用于给整个表格加上一个外部轮廓边框。
# 例:
('OUTLINE', (0, 0), (-1, -1), 2, colors.green) # 给整个表格添加一个 2 点粗的绿色外边框


INNERGRID - 绘制表格内部的网格线,但不绘制外部的边框。即,它只在单元格之间绘制分隔线。
# 例:
('INNERGRID', (0, 0), (-1, -1), 0.5, colors.grey) # 绘制所有的网格线,线条粗细为 0.5,颜色为灰色


LINEBELOW - 在指定行的下方绘制一条水平线,也就是下边线
# 例:
('LINEBELOW', (0, 1), (-1, 1), 1, colors.red) # 在第二行(索引为 1)下方绘制 1 点粗的红色线条


LINEABOVE - 在指定行的上方绘制一条水平线,也就是上边线
# 例:
('LINEBEFORE', (1, 0), (1, -1), 0.5, colors.green) # 在第二列(索引为 1)左侧绘制 0.5 点粗的绿色垂直线条


LINEAFTER - 在指定列的右侧绘制一条垂直线,也就是右边线
# 例:
('LINEAFTER', (2, 0), (2, -1), 0.5, colors.yellow) # 在第三列(索引为 2)右侧绘制 0.5 点粗的黄色垂直线条

TableStyle 合并单元格命令

SPAN 命令用于合并单元格,命令如下:

1
SPAN, (sc, sr), (ec, er)

表示从列 scec、从行 srer 的单元格应合并成一个超大单元格,其内容由单元格 (sc, sr) 决定。

[!IMPORTANT]

这里合并时,每行单元格的数量应当一致,不需要的位置用空白代替,不然合并的时候会丢失内容。

如对于二维数组: [ [姓名, 得分], [张三, 李四, 99, 98] ]

这里在合并时,对于第一列内容要先进行扩充,扩充为[‘姓名’, ‘’, ‘得分’, ‘’],需要注意,合并的单元格内容为左侧单元格的内容

合并的命令为:

1
2
('SPAN', (0, 0), (1, 0))	# 合并"姓名"和""
('SPAN', (2, 0), (3, 0)) # 合并"得分"和""

Table 中可能会遇到格式的问题

嵌套表格上下界额外空白间隙

这个问题导致的原因是,嵌套表格同一行的前后某个单元格的高度,超过了内部嵌套单元格的长度,导致出现了额外的空白间隙。

嵌套表格上下界额外空隙问题示例

这个问题也很好解决,有两个解决方案:

  1. 只要表格的内部分割线
  2. 手动计算并指定嵌套表格的高度

对于方案一,是最简单的方案,使用 INNERGRID 命令即可。就是如果这个间隙十分大,看起来会有些怪。代码如下:

1
style.add('INNERGRID', (0, 0), (-1, -1), 1, colors.black)  # 绘制内部网格线

效果如下:

方案一

但是这个方案不完美,因为分割线不连贯。

对于方案二:

这个方案就是逐个表格的每个行高,如果外部的那个单元格大于内部的表格的行高,那么就重新指定一下行高;否则,我们就按照原始的行高来,这里需要指定 Table 的参数。

五、BaseDocTemplate 的使用

BaseDocTemplate 定义

BaseDocTemplateReportLab 库中的一个类,用于处理多个页面模板(PageTemplate)。它提供了一个 build 方法来处理页面内容并生成 PDF 文档。BaseDocTemplate 允许你创建自定义布局,它为页面的布局提供了基本机制,并且允许通过 Flowables 来管理、组织文档内容,并最终输出 PDF 文件。

BaseDocTemplate 的定义如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
BaseDocTemplate(
self,
filename, # 必需的参数,指定生成的 PDF 文件的路径和名称。
pagesize=defaultPageSize, # 页面大小。可以设置为 `letter`、`A4` 等常见大小。
pageTemplates=[], # 页面模板列表,默认空。可指定多个页面模板,每个模板定义了一个页面的布局。
showBoundary=0, # 控制是否显示页面边界框,0 表示不显示,1 表示显示。
leftMargin=inch, # 页面左边距,默认为 `inch`(1 英寸)。用于控制页面内容的左侧空白区域。
rightMargin=inch, # 页面右边距,默认为 `inch`(1 英寸)。用于控制页面内容的右侧空白区域。
topMargin=inch, # 页面顶部边距,默认为 `inch`(1 英寸)。用于控制页面内容的上方空白区域。
bottomMargin=inch, # 页面底部边距,默认为 `inch`(1 英寸)。用于控制页面内容的下方空白区域。
allowSplitting=1, # 是否允许内容跨页,1 允许,0 禁止。如果页面内容过多,将自动分割到下一页。
title=None, # 设置 PDF 文档的标题,默认为 `None`。可以指定一个字符串作为文档标题。
author=None, # 设置 PDF 文档的作者,默认为 `None`。可以指定一个字符串作为文档作者。
_pageBreakQuick=1, # 控制页面换行的速度。1 表示快速换页,0 表示正常。
encrypt=None # 用于设置加密保护的选项,默认为 `None`。保护 PDF 文档,使其不可复制或打印等。
)

这里的 filename 参数同样可以是一个字符串,表示接收生成的 PDF 文档的文件名;或者它可以是一个具有 write 方法的对象,例如 BytesIO、文件或套接字。

BaseDocTemplate 用户方法

添加列表到 BaseDocTemplate 中

将一个或多个(列表)PageTemplates 加入到 BaseDocTemplate 中。

用法:

1
BaseDocTemplate.addPageTemplates(self, pageTemplates)

构建 PDF 文档

当文档实例的内容正确设置时,build 方法将以 flowables 列表的形式接收文档内容,并逐一处理这些 flowables。实际上,这使得 BaseDocTemplate 实例依次调用其 handle_XXX 方法来处理不同的事件。

用法:

1
BaseDocTemplate.build(self, flowables, filename=None, canvasmaker=canvas.Canvas)

通常构建 PDF 文件时会和 Python 的 IO 一起使用,以下是一个简单的案例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def generate_pdf(content, graphs):  
"""
生成 PDF 并且返回 PDF 的字节流
@param content: PDF 的内容
@param graphs: PDF 绘制类
@return: PDF 字节流
"""
buffer = io.BytesIO()
doc = BaseDocTemplate(buffer, leftMargin=inch / 10, rightMargin=inch / 10)

template = PageTemplate(
id="test", frames=frame_footer, onPage=graphs.header, onPageEnd=graphs.footer
)

doc.addPageTemplates([template])

doc.build(content)
return buffer.getvalue()

六、其他常用类

Image 图片类

Image 类用法比较简单,用来读取本地的图片文件,同时可以指定高度和宽度:

Image 的用法:

1
Image(filename, width=None, height=None)

这里有时候 filename 可能不是一个文件路径,可能会是一个加密的 base64_string,使用起来也很简单,只要把 base64_string 解密,然后使用 Python 的 IO 进行读取即可。

Spacer 空白间隔区类

空白间隔区 Spacer 可以用来在文档中插入一定的空白间隔,用法如下:

1
Spacer(width, height)

PageBreak 换页符类

PageBreak 类用来在一个页面中插入一个“换页符”,让下面的内容到下一页去,用法如下:

1
PageBreak()