使用Python中的reportlab库生成PDF文件
1 安装
pip install reportlab
2 应用场景
官网案例
3 PLATYPUS
Platypus是“Page Layout and Typography Using Scripts”,是使用脚本的页面布局和印刷术的缩写,这是一个高层次页面布局库,它可以让你通过编程创造复杂的文档,并且毫不费力。
Platypus设计的目的是尽可能地将高层布局设计与文档内容分离,比如,段落使用段落格式构造,页面使用页面模板,这样做是有好处的,在仅仅修改几行代码的情况下,包含数百个页面的数百个文档就能够被构造成不同的风格。

3.1 start demo
import reportlab
from reportlab.platypus import SimpleDocTemplate, Paragraph
from reportlab.lib.styles import getSampleStyleSheet
# 调用模板,创建指定名称的PDF文档
doc = SimpleDocTemplate("start_demo.pdf")
# 获得模板表格
styles = getSampleStyleSheet()
# 指定模板
style = styles['Normal']
# 初始化内容
story =[]
# 将段落添加到内容中
story.append(Paragraph("this is a demo pdf!",style))
# 将内容输出到PDF中
doc.build(story)
在Python文件的同目录下,生成一个文件名为”start_demo.pdf“的文件:
doc = SimpleDocTemplate("start_demo.pdf") 调用了 BaseDocTemplate模板
BaseDocTemplate 基本思想很简单。
1) 该文档有一个与之相关的数据列表,这些数据应该来自流动性。我们会特殊类,如PageBreak、FrameBreak,用于执行强制页面结束等操作。
2) 文档有一个或多个页面模板。
3) 每个页面模板都有一个或多个框架。
4) document类提供了处理故事事件的基本方法,以及将故事流放入框架的一些合理方法。
5) 文档实例可以覆盖基本处理程序例程。
这个类的大多数方法不是由用户直接调用的,但在一些高级用法中,它们可能需要通过子类化来重写。
异常:必须调用doctemplate.build(…)才能获得最合理的用途,因为它使用页面模板生成文档。
每个文档模板在初始化时将恰好一个文档构建到filename参数指定的文件中。
初始化的可能关键字参数:
-pageTemplates:模板列表。必须是非空的。指定给模板的名称用于引用它们,因此使用的两个模板不应具有相同的名称。例如,在奇数页和偶数页上,您可能需要一个标题页模板、一个章节首页模板、一章首页模板和两个章节内部模板。如果省略了此参数,则在生成文档之前,应使用addPageTemplates方法至少提供一个pageTemplate。
-pageSize:reportlab/lib/pagesizes.pu中的2元组或大小常量。由SimpleDocTemplate子类使用,该子类不接受的列表
pageTemplates,但为您制作一个;使用pageTemplates时忽略。
-showBoundary:如果设置,则在框架边界周围绘制一个框。
-左边距:
-右侧边距:
-顶部边距:
-底部边距:以点为单位的边距大小(默认为1英寸)。这些页边距可能会被pageTemplates覆盖。它们主要是SimpleDocumentTemplate子类感兴趣的。
-allowSpliting:如果设置了流动性(如段落),则可以在框架或页面之间进行拆分(默认值:1)
-title:文档的内部标题(不会自动显示在任何页面上)
-author:文档的内部作者(不会自动显示在任何页面上)
初始化参数:
'pagesize':defaultPageSize,
'pageTemplates':[],
'showBoundary':0,
'leftMargin':inch,
'rightMargin':inch,
'topMargin':inch,
'bottomMargin':inch,
'allowSplitting':1,
'title':None,
'author':None,
'subject':None,
'creator':None,
'producer':None,
'keywords':[],
'invariant':None,
'pageCompression':None,
'_pageBreakQuick':1,
'rotation':0,
'_debug':0,
'encrypt': None,
'cropMarks': None,
'enforceColorSpace': None,
'displayDocTitle': None,
'lang': None,
'initialFontName': None,
'initialFontSize': None,
'initialLeading': None,
'cropBox': None,
'artBox': None,
'trimBox': None,
'bleedBox': None,
'keepTogetherClass': KeepTogether,
'hideToolbar': None,
'hideMenubar': None,
'hideWindowUI': None,
'fitWindow': None,
'centerWindow': None,
'nonFullScreenPageMode': None,
'direction': None,
'viewArea': None,
'viewClip': None,
'printArea': None,
'printClip': None,
'printScaling': None,
'duplex': None,
4 段落
段落是一种重要的Flowables,它可以格式化任意的文本。
段落中主要包括两种信息:文本和格式。Paragraph(text, style)
from reportlab.lib.styles import ParagraphStyle
4.1 ParagraphStyle 参数
class ParagraphStyle(PropertySet):
defaults = {
'fontName':_baseFontName,
'fontSize':10,
'leading':12,
'leftIndent':0,
'rightIndent':0,
'firstLineIndent':0,
'alignment':TA_LEFT,
'spaceBefore':0,
'spaceAfter':0,
'bulletFontName':_baseFontName,
'bulletFontSize':10,
'bulletIndent':0,
#'bulletColor':black,
'textColor': black,
'backColor':None,
'wordWrap':None, #None means do nothing special
#CJK use Chinese Line breaking
#LTR RTL use left to right / right to left
#with support from pyfribi2 if available
'borderWidth': 0,
'borderPadding': 0,
'borderColor': None,
'borderRadius': None,
'allowWidows': 1,
'allowOrphans': 0,
'textTransform':None, #uppercase lowercase (captitalize not yet) or None or absent
'endDots':None, #dots on the last line of left/right justified paras
#string or object with text and optional fontName, fontSize, textColor & backColor
#dy
'splitLongWords':1, #make best efforts to split long words
'underlineWidth': _baseUnderlineWidth, #underline width default
'bulletAnchor': 'start', #where the bullet is anchored ie start, middle, end or numeric
'justifyLastLine': 0, #n allow justification on the last line for more than n words 0 means don't bother
'justifyBreaks': 0, #justify lines broken with <br/>
'spaceShrinkage': _spaceShrinkage, #allow shrinkage of percentage of space to fit on line
'strikeWidth': _baseStrikeWidth, #stroke width default
'underlineOffset': _baseUnderlineOffset, #fraction of fontsize to offset underlines
'underlineGap': _baseUnderlineGap, #gap for double/triple underline
'strikeOffset': _baseStrikeOffset, #fraction of fontsize to offset strikethrough
'strikeGap': _baseStrikeGap, #gap for double/triple strike
'linkUnderline': _platypus_link_underline,
'underlineColor': None,
'strikeColor': None,
'hyphenationLang': _hyphenationLang,
#'hyphenationMinWordLength': _hyphenationMinWordLength,
'embeddedHyphenation': _embeddedHyphenation,
'uriWasteReduce': _uriWasteReduce,
}
几个重要的参数说明:
ParagraphStyle是段落的默认格式,也就是在调用Paragraph(text, style)语句时,如果不传入style参数,默认的段落格式。
还有其他方式获得ReportLab提供的段落格式:
from reportlab.lib.styles import getSampleStyleSheet
stylesheet=getSampleStyleSheet()
normalStyle = stylesheet['Normal']
这里获得系统提供的Normal格式,其实Normal格式与ParagraphStyle是一模一样的,除了Normal格式,还可以获得其他的格式:
def getSampleStyleSheet():
"""Returns a stylesheet object"""
stylesheet = StyleSheet1()
stylesheet.add(ParagraphStyle(name='Normal',
fontName=_baseFontName,
fontSize=10,
leading=12)
)
stylesheet.add(ParagraphStyle(name='BodyText',
parent=stylesheet['Normal'],
spaceBefore=6)
)
stylesheet.add(ParagraphStyle(name='Italic',
parent=stylesheet['BodyText'],
fontName = _baseFontNameI)
)
stylesheet.add(ParagraphStyle(name='Heading1',
parent=stylesheet['Normal'],
fontName = _baseFontNameB,
fontSize=18,
leading=22,
spaceAfter=6),
alias='h1')
stylesheet.add(ParagraphStyle(name='Title',
parent=stylesheet['Normal'],
fontName = _baseFontNameB,
fontSize=18,
leading=22,
alignment=TA_CENTER,
spaceAfter=6),
alias='title')
stylesheet.add(ParagraphStyle(name='Heading2',
parent=stylesheet['Normal'],
fontName = _baseFontNameB,
fontSize=14,
leading=18,
spaceBefore=12,
spaceAfter=6),
alias='h2')
stylesheet.add(ParagraphStyle(name='Heading3',
parent=stylesheet['Normal'],
fontName = _baseFontNameBI,
fontSize=12,
leading=14,
spaceBefore=12,
spaceAfter=6),
alias='h3')
stylesheet.add(ParagraphStyle(name='Heading4',
parent=stylesheet['Normal'],
fontName = _baseFontNameBI,
fontSize=10,
leading=12,
spaceBefore=10,
spaceAfter=4),
alias='h4')
stylesheet.add(ParagraphStyle(name='Heading5',
parent=stylesheet['Normal'],
fontName = _baseFontNameB,
fontSize=9,
leading=10.8,
spaceBefore=8,
spaceAfter=4),
alias='h5')
stylesheet.add(ParagraphStyle(name='Heading6',
parent=stylesheet['Normal'],
fontName = _baseFontNameB,
fontSize=7,
leading=8.4,
spaceBefore=6,
spaceAfter=2),
alias='h6')
stylesheet.add(ParagraphStyle(name='Bullet',
parent=stylesheet['Normal'],
firstLineIndent=0,
spaceBefore=3),
alias='bu')
stylesheet.add(ParagraphStyle(name='Definition',
parent=stylesheet['Normal'],
firstLineIndent=0,
leftIndent=36,
bulletIndent=0,
spaceBefore=6,
bulletFontName=_baseFontNameBI),
alias='df')
stylesheet.add(ParagraphStyle(name='Code',
parent=stylesheet['Normal'],
fontName='Courier',
fontSize=8,
leading=8.8,
firstLineIndent=0,
leftIndent=36,
hyphenationLang=''))
stylesheet.add(ListStyle(name='UnorderedList',
parent=None,
leftIndent=18,
rightIndent=0,
bulletAlign='left',
bulletType='1',
bulletColor=black,
bulletFontName='Helvetica',
bulletFontSize=12,
bulletOffsetY=0,
bulletDedent='auto',
bulletDir='ltr',
bulletFormat=None,
#start='circle square blackstar sparkle disc diamond'.split(),
start=None,
),
alias='ul')
stylesheet.add(ListStyle(name='OrderedList',
parent=None,
leftIndent=18,
rightIndent=0,
bulletAlign='left',
bulletType='1',
bulletColor=black,
bulletFontName='Helvetica',
bulletFontSize=12,
bulletOffsetY=0,
bulletDedent='auto',
bulletDir='ltr',
bulletFormat=None,
#start='1 a A i I'.split(),
start=None,
),
alias='ol')
return stylesheet
假如想要获得Title格式,我们只需要按照如下格式调用即可:
from reportlab.lib.styles import getSampleStyleSheet
stylesheet=getSampleStyleSheet()
titleStyle = stylesheet['Title']
从Title的源代码可知:Title的效果是:字体18号;行间距22;对齐方式:居中;段落后间距:6。
5 表格
表格是Flowable的派生类,是一种简单文本表格机制。表格可以保存所有能被转换为字符串或Flowerable是所有事物。
如果我们不提供行高,它们可以根据数据自动计算出行高。
如果需要,它们可以跨页分割,你可以指定跨页分割后,需要重复的行数。
表格风格和表格数据是分离的,因此你可以声明一系列的风格,然后将它们用于一大堆报告。
表格使用如下代码进行创建:
Table(data, colWidths=None, rowHeights=None, style=None, splitByRow=1,
repeatRows=0, repeatCols=0, rowSplitRange=None, spaceBefore=None,
spaceAfter=None)
几个关键参数:
from reportlab.platypus import SimpleDocTemplate, Table
from reportlab.lib.styles import getSampleStyleSheet
# 调用模板,创建指定名称的PDF文档
doc = SimpleDocTemplate("my_pdf_01.pdf")
# 获得模板表格
styles = getSampleStyleSheet()
# 指定模板
style = styles['Normal']
# 初始化内容
story =[]
# 初始化表格内容
data= [['00', '01', '02', '03', '04'],
['10', '11', '12', '13', '14'],
['20', '21', '22', '23', '24'],
['30', '31', '32', '33', '34']]
# 根据内容创建表格
t = Table(data)
# 将表格添加到内容中
story.append(t)
# 将内容输出到PDF中
doc.build(story)
5.1 表格格式
指定表格格式有两种方式,一种是在调用创建表格接口时,传入style参数,一种是在创建完表格后,调用如下接口:
Table.setStyle(tblStyle)
5.1.1 直接传入style参数
from reportlab.platypus import SimpleDocTemplate, Table
from reportlab.lib import colors
from reportlab.lib.styles import getSampleStyleSheet
# 调用模板,创建指定名称的PDF文档,输入参数为路径文件名
doc = SimpleDocTemplate("../datas/wws_tables.pdf")
# 获得模板表格
styles = getSampleStyleSheet()
# 指定模板
style = styles['Normal']
# 初始化内容
story = []
# 初始化表格内容
data = [['00', '01', '02', '03', '04'],
['10', '11', '12', '13', '14'],
['20', '21', '22', '23', '24'],
['30', '31', '32', '33', '34']]
# 根据内容创建表格,同时添加格式
t = Table(data,style=[
('GRID', (0, 0), (-1, -1), 1, colors.grey),
('GRID', (1, 1), (-2, -2), 1, colors.green),
('BOX', (0, 0), (1, -1), 2, colors.red),
('BACKGROUND', (0, 0), (0, 1), colors.pink),
('BACKGROUND', (1, 1), (1, 2), colors.lavender),
('BACKGROUND', (2, 2), (2, 3), colors.orange),
]
)
# 将表格添加到内容中
story.append(t)
# 将内容输出到PDF中
doc.build(story)
5.1.2 调用setStyle
from reportlab.platypus import SimpleDocTemplate, Table, TableStyle
from reportlab.lib import colors
from reportlab.lib.styles import getSampleStyleSheet
# 调用模板,创建指定名称的PDF文档
doc = SimpleDocTemplate("../datas/wws_tables.pdf")
# 获得模板表格
styles = getSampleStyleSheet()
# 指定模板
style = styles['Normal']
# 初始化内容
story = []
# 初始化表格内容
data = [['00', '01', '02', '03', '04'],
['10', '11', '12', '13', '14'],
['20', '21', '22', '23', '24'],
['30', '31', '32', '33', '34']]
# 根据内容创建表格
t = Table(data)
# 然后调用setStyle添加格式
t.setStyle(TableStyle([
('INNERGRID', (0, 0), (-1, -1), 0.25, colors.black),
('BOX', (0, 0), (-1, -1), 2, colors.black),
('LINEBELOW', (0, 0), (-1, 0), 2, colors.yellow),
('LINEAFTER', (0, 0), (0, -1), 2, colors.blue),
('ALIGN', (1, 1), (-1, -1), 'RIGHT')
])
)
# 将表格添加到内容中
story.append(t)
# 将内容输出到PDF中
doc.build(story)
重点表格格式化命令:
6 图片
在调用接口时,支持默认的jpeg格式。接口如下:
Image(filename, width=None, height=None)
如果宽度和高度有一个没有被指定,则参考原来的图片像素。
from reportlab.platypus import SimpleDocTemplate, Table, TableStyle
from reportlab.lib import colors
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.platypus import SimpleDocTemplate, Image
from reportlab.lib.styles import getSampleStyleSheet
# 调用模板,创建指定名称的PDF文档
doc = SimpleDocTemplate("../datas/wws_tables.pdf")
# 获得模板表格
styles = getSampleStyleSheet()
# 指定模板
style = styles['Normal']
# 初始化内容
story = []
# 初始化表格内容
data = [['00', '01', '02', '03', '04'],
['10', '11', '12', '13', '14'],
['20', '21', '22', '23', '24'],
['30', '31', '32', '33', '34']]
# 根据内容创建表格, 表格后空两行,不然图片连一块了,难看
t = Table(data, spaceAfter=10)
# 然后调用setStyle添加格式
t.setStyle(TableStyle([
('INNERGRID', (0, 0), (-1, -1), 0.25, colors.black),
('BOX', (0, 0), (-1, -1), 2, colors.black),
('LINEBELOW', (0, 0), (-1, 0), 2, colors.yellow),
('LINEAFTER', (0, 0), (0, -1), 2, colors.blue),
('ALIGN', (1, 1), (-1, -1), 'RIGHT')
])
)
# 将表格添加到内容中
story.append(t)
# 添加图片
IMG = Image("C:\\Users\\admin\\Documents\\index\\PS图片\\20230926-144332.jpg", width=120, height=160)
story.append(IMG)
# 将内容输出到PDF中
doc.build(story)
参考
python 生成pdf
reportlab 官网案例
reportlab 官方文档
文档官方demo
flask_reportlab
adding-links-to-pdf
Python的reportlab制作pdf时,如何让插入的图片适应pdf的大小
reportlab 中文问题
作者:桂花很香,旭很美