https://docs.reportlab.com/reportlab/userguide/

依赖

安装与使用

您想要用Python快速自动生成丰富、有吸引力且完全定制的PDF文件?

在工作中,你是否遇到过这样的工作场景:

  1. 自动化测试设备,将测试信息自动生成测试报告。
  2. 从XML一步生成PDF文件
  3. 生成包括表格、图片和文字的报告和论文等。
  4. 等等。

那我们今天要学习的Python第三方库ReportLab,就是为你量身打造的,这个库可以解决你在工作中自动生成报告的问题。我曾在某个时期大量使用这个库生成PDF文件。

这个Python库的功能强大,是一个用于生成PDF和图形的开源Python库。每个月使用ReportLab生成的文档超过500万份。

本文中的开发环境是Python 3.8,ReportLab的版本号是3.5.55。文中的代码全部经过验证,你可以直接使用,如果有什么问题,可以私信我。

ReportLab功能强大,但是限于篇幅,本文仅选取最常用的功能:段落、表格和图片。本文按照如下的顺序进行展开:

  1. 安装
  2. 功能概述
  3. PLATYPUS
  4. 段落
  5. 表格
  6. 图片

1.安装

用键盘按Win+R打开运行窗口,输入cmd命令。

  1. C:\Users\Administrator>pip install reportlab

执行结果

  1. Collecting reportlab
  2. Using cached reportlab-3.5.55-cp38-cp38-win_amd64.whl (2.3 MB)
  3. Requirement already satisfied: pillow>=4.0.0 in d:\anaconda3\lib\site-packages (from reportlab) (7.2.0)
  4. Installing collected packages: reportlab
  5. Successfully installed reportlab-3.5.55

在命令行中输入python,进入python编译环境后,输入如下命令:

  1. >>> import reportlab
  2. >>>

如果没有报错,则确认安装成功。

2.概述

在开始学习ReportLab之前,需要先回答下面几个问题:

  • 什么是ReportLab?
  • 我为什么要使用它?
  • 怎么样才能够学会使用这个库?

什么是ReportLab?

简单来说,这个一个允许您使用Python编程语言直接创建PDF格式文件的软件库,它也可以创建各种表格、数据图和位图。

众所周知,PDF是一种电子文档的全球标准,它支持高质量打印,同时又能够很好的在不同的平台之间传播。然而,除了使用Word、专业版的Adobe PDF软件生成PDF文件,直接生成PDF比较困难。

今天要介绍的ReportLab可以通过图形命令行直接生成PDF,并且不需要其他辅助,ReportLab可以极快地生成报告。

ReportLab可以使用于下面的应用场景:

  • 通过网页动态生成PDF文档
  • 大量的报告和数据发布
  • 用XML一步生成PDF

我们在官网上看ReportLab的案例。官网地址:

https://www.reportlab.com/casestudies/www.reportlab.com/casestudies/

ReportLab pdf管理 - 图1

我们选取其中的“Seychelles Travel Guides“作为例子,点击进去后,查看效果。

这个例子的链接是:

https://www.reportlab.com/casestudies/seychelles/www.reportlab.com/casestudies/seychelles/

ReportLab pdf管理 - 图2

这个例子真的是图文并茂,该有的要素一应俱全。

ReportLab功能这么强大。为了学会这个库,我们需要具备扎实的Python编程基础,同时按照我的教程,自己动手实践。

知识是一宝库,而实践就是开启宝库大门的钥匙。 — 富勒

ReportLab中包含的知识点非常多,为了方便大家快速掌握最常见的核心知识点,方便大家快速掌握最常用的核心知识点,我提炼出了最常用的80%的功能:Platypus、段落、表格和图片。

3.PLATYPUS

Platypus是“Page Layout and Typography Using Scripts”,是使用脚本的页面布局和印刷术的缩写,这是一个高层次页面布局库,它可以让你通过编程创造复杂的文档,并且毫不费力。

Platypus设计的目的是尽可能地将高层布局设计与文档内容分离,比如,段落使用段落格式构造,页面使用页面模板,这样做是有好处的,在仅仅修改几行代码的情况下,包含数百个页面的数百个文档就能够被构造成不同的风格。

Platypus从上到下,可以被看成具备多个层次。

DocTemplates:文档最外层的容器

PageTemplates:各种页面布局的规格

Frames:包含流动的文本和图形的文档区域规范

Flowables:能够被“流入文档”的文本、图形和段落等。

ReportLab pdf管理 - 图3

我们常常用DocTemplate、PageTemplates和Flowables来构建文档。

先看一个简单的例子,来见识下ReportLab的威力。

  1. from reportlab.platypus import SimpleDocTemplate, Paragraph
  2. from reportlab.lib.styles import getSampleStyleSheet
  3. # 调用模板,创建指定名称的PDF文档
  4. doc = SimpleDocTemplate("Hello.pdf")
  5. # 获得模板表格
  6. styles = getSampleStyleSheet()
  7. # 指定模板
  8. style = styles['Normal']
  9. # 初始化内容
  10. story =[]
  11. # 将段落添加到内容中
  12. story.append(Paragraph("This is the first Document!",style))
  13. # 将内容输出到PDF中
  14. doc.build(story)

在这个Python文件的同目录下,生成一个文件名为”Hello.pdf“的文件,我们打开看看,执行结果如下:

ReportLab pdf管理 - 图4

4. 段落

段落是一种重要的Flowables,它可以格式化任意的文本。

段落中主要包括两种信息:文本和格式。

下面的语句可以用来创建一个段落的实例。

  1. Paragraph(text, style)

text参数提供了段落的文本,末尾和换行处的空白都会被删除。

style参数用于设置段落的格式,这里段落的格式是指参数的集合,包括字体大小、行间距、首行缩进等参数。我们可以调用如下语句来获得默认段落格式。

  1. from reportlab.lib.styles import ParagraphStyle

那ParagraphStyle中究竟包含哪些参数呢?

  1. class ParagraphStyle(PropertySet):
  2. defaults = {
  3. 'fontName':_baseFontName,
  4. 'fontSize':10,
  5. 'leading':12,
  6. 'leftIndent':0,
  7. 'rightIndent':0,
  8. 'firstLineIndent':0,
  9. 'alignment':TA_LEFT,
  10. 'spaceBefore':0,
  11. 'spaceAfter':0,
  12. 'bulletFontName':_baseFontName,
  13. 'bulletFontSize':10,
  14. 'bulletIndent':0,
  15. #'bulletColor':black,
  16. 'textColor': black,
  17. 'backColor':None,
  18. 'wordWrap':None, #None means do nothing special
  19. #CJK use Chinese Line breaking
  20. #LTR RTL use left to right / right to left
  21. #with support from pyfribi2 if available
  22. 'borderWidth': 0,
  23. 'borderPadding': 0,
  24. 'borderColor': None,
  25. 'borderRadius': None,
  26. 'allowWidows': 1,
  27. 'allowOrphans': 0,
  28. 'textTransform':None, #uppercase lowercase (captitalize not yet) or None or absent
  29. 'endDots':None, #dots on the last line of left/right justified paras
  30. #string or object with text and optional fontName, fontSize, textColor & backColor
  31. #dy
  32. 'splitLongWords':1, #make best efforts to split long words
  33. 'underlineWidth': _baseUnderlineWidth, #underline width
  34. 'bulletAnchor': 'start', #where the bullet is anchored ie start, middle, end or numeric
  35. 'justifyLastLine': 0, #n allow justification on the last line for more than n words 0 means don't bother
  36. 'justifyBreaks': 0, #justify lines broken with <br/>
  37. 'spaceShrinkage': _spaceShrinkage, #allow shrinkage of percentage of space to fit on line
  38. 'strikeWidth': _baseStrikeWidth, #stroke width
  39. 'underlineOffset': _baseUnderlineOffset, #fraction of fontsize to offset underlines
  40. 'underlineGap': _baseUnderlineGap, #gap for double/triple underline
  41. 'strikeOffset': _baseStrikeOffset, #fraction of fontsize to offset strikethrough
  42. 'strikeGap': _baseStrikeGap, #gap for double/triple strike
  43. 'linkUnderline': _platypus_link_underline,
  44. #'underlineColor': None,
  45. #'strikeColor': None,
  46. 'hyphenationLang': _hyphenationLang,
  47. #'hyphenationMinWordLength': _hyphenationMinWordLength,
  48. 'embeddedHyphenation': _embeddedHyphenation,
  49. 'uriWasteReduce': _uriWasteReduce,
  50. }

我们选取几个重要的参数进行说明:

  • fontName:字体名称
  • fontSize:字体大小
  • leading:行间距
  • leftIndent:左缩进
  • rightIndent:右缩进
  • firstLineIndent:首行缩进
  • alignment:对齐方式
  • spaceBefore:段前间隙
  • spaceAfter:段后间隙
  • bulletFontName:列表名称
  • bulletFontSize:列表字体大小
  • bulletIndent:列表缩进
  • textColor:字体颜色
  • backColor:背景色
  • borderWidth:边框粗细
  • borderPadding:边框间距
  • borderColor:边框颜色

ParagraphStyle是段落的默认格式,也就是在调用Paragraph(text, style)语句时,如果不传入style参数,默认的段落格式。

我们还有其他方式获得ReportLab提供的段落格式。

  1. from reportlab.lib.styles import getSampleStyleSheet
  2. stylesheet=getSampleStyleSheet()
  3. normalStyle = stylesheet['Normal']

这里就是获得系统提供的Normal格式,其实Normal格式与ParagraphStyle是一模一样的,除了Normal格式,还可以获得其他的格式。

  • Normal
  • BodyText
  • Italic
  • Heading1
  • Title
  • Heading2
  • Heading3
  • Heading4
  • Heading5
  • Heading6
  • Bullet
  • Definition
  • Code
  • UnorderedList
  • OrderedList

假如想要获得Title格式,我们只需要按照如下格式调用即可

  1. from reportlab.lib.styles import getSampleStyleSheet
  2. stylesheet=getSampleStyleSheet()
  3. titleStyle = stylesheet['Title']

那这些格式究竟是效果?可以用两种方法验证,一是直接使用看效果,二是查看源代码。

比如Title的源代码:

  1. stylesheet.add(ParagraphStyle(name='Title',
  2. parent=stylesheet['Normal'],
  3. fontName = _baseFontNameB,
  4. fontSize=18,
  5. leading=22,
  6. alignment=TA_CENTER,
  7. spaceAfter=6),
  8. alias='title')

可以看到,Title的效果是:字体18号;行间距22;对齐方式:居中;段落后间距:6。

5.表格

表格是Flowable的派生类,是一种简单文本表格机制。表格可以保存所有能被转换为字符串或Flowerable是所有事物。

如果我们不提供行高,它们可以根据数据自动计算出行高。

如果需要,它们可以跨页分割,你可以指定跨页分割后,需要重复的行数。

表格风格和表格数据是分离的,因此你可以声明一系列的风格,然后将它们用于一大堆报告。

表格使用如下代码进行创建:

  1. Table(data, colWidths=None, rowHeights=None, style=None, splitByRow=1,
  2. repeatRows=0, repeatCols=0, rowSplitRange=None, spaceBefore=None,
  3. spaceAfter=None)

这里挑选几个关键参数进行讲解。

  • data:数据参数是一系列的表格值,每个表格值能够被转换为字符串或者Flowable实例。data值的第一行是data[0],第i行j列表格值是data[i] [j]。
  • colWidths:是一系列值,这些值代表每列的宽度。如果传递的是None,则对应列宽需要被自动计算。
  • rowHeights:是一系列值,这些值代表每行的高度。如果传递的是None,则对应的行高需要被自动计算。
  • style:表格被创建时的初始样式值。
  • splitByRow:布尔值,当指定值为1时,允许跨页分割表格,当指定指为0时,不允许跨页分割表格。
  • repeatRows:指定跨页分行时,需要重复的行数。
  • repeatCols:暂时没用。
  • spaceBefore:指定表格前的行数。
  • spaceAfter:指定表格后的行数。

先来看个例子。

  1. from reportlab.platypus import SimpleDocTemplate, Table
  2. from reportlab.lib.styles import getSampleStyleSheet
  3. # 调用模板,创建指定名称的PDF文档
  4. doc = SimpleDocTemplate("Hello.pdf")
  5. # 获得模板表格
  6. styles = getSampleStyleSheet()
  7. # 指定模板
  8. style = styles['Normal']
  9. # 初始化内容
  10. story =[]
  11. # 初始化表格内容
  12. data= [['00', '01', '02', '03', '04'],
  13. ['10', '11', '12', '13', '14'],
  14. ['20', '21', '22', '23', '24'],
  15. ['30', '31', '32', '33', '34']]
  16. # 根据内容创建表格
  17. t = Table(data)
  18. # 将表格添加到内容中
  19. story.append(t)
  20. # 将内容输出到PDF中
  21. doc.build(story)

执行结果是:

ReportLab pdf管理 - 图5

打开“Hello.pdf”,看到是一个无边框的表格。如果我们需要指定表格的显示方式呢?细看下一节的表格格式。

表格格式

指定表格格式有两种方式,一种是在调用创建表格接口时,传入style参数,一种是在创建完表格后,调用如下接口:

  1. Table.setStyle(tblStyle)

直接传入style参数

  1. from reportlab.platypus import SimpleDocTemplate, Table
  2. from reportlab.lib import colors
  3. from reportlab.lib.styles import getSampleStyleSheet
  4. doc = SimpleDocTemplate("Hello.pdf")
  5. styles = getSampleStyleSheet()
  6. style = styles['Normal']
  7. story =[]
  8. data= [['00', '01', '02', '03', '04'],
  9. ['10', '11', '12', '13', '14'],
  10. ['20', '21', '22', '23', '24'],
  11. ['30', '31', '32', '33', '34']]
  12. t=Table(data,style=[
  13. ('GRID',(0,0),(-1,-1),1,colors.grey),
  14. ('GRID',(1,1),(-2,-2),1,colors.green),
  15. ('BOX',(0,0),(1,-1),2,colors.red),
  16. ('BACKGROUND', (0, 0), (0, 1), colors.pink),
  17. ('BACKGROUND', (1, 1), (1, 2), colors.lavender),
  18. ('BACKGROUND', (2, 2), (2, 3), colors.orange),
  19. ])
  20. story.append(t)
  21. doc.build(story)

查看执行结果:

ReportLab pdf管理 - 图6

调用setStyle

  1. from reportlab.platypus import SimpleDocTemplate, Table, TableStyle
  2. from reportlab.lib import colors
  3. from reportlab.lib.styles import getSampleStyleSheet
  4. doc = SimpleDocTemplate("Hello.pdf")
  5. styles = getSampleStyleSheet()
  6. style = styles['Normal']
  7. story =[]
  8. data= [['00', '01', '02', '03', '04'],
  9. ['10', '11', '12', '13', '14'],
  10. ['20', '21', '22', '23', '24'],
  11. ['30', '31', '32', '33', '34']]
  12. t=Table(data)
  13. t.setStyle(TableStyle(
  14. [('INNERGRID', (0,0), (-1,-1), 0.25, colors.black),
  15. ('BOX', (0,0), (-1,-1), 2, colors.black),
  16. ('LINEBELOW', (0,0), (-1,0), 2, colors.yellow),
  17. ('LINEAFTER', (0,0), (0,-1), 2, colors.blue),
  18. ('ALIGN', (1,1), (-1,-1), 'RIGHT')]
  19. ))
  20. story.append(t)
  21. doc.build(story)

查看执行结果:

ReportLab pdf管理 - 图7

看到这里,小伙伴们可能一头雾水,这里需要补充基础知识。

表格的位置索引方式与列表的索引方式一致,即左上角第一个是data[0] [0],第二行第一个是data[1] [0],最后一行第一个位置是data[-1] [0],依次类推。

上面的例子中,列举了不少的表格格式化命令,这里将我知道的命令都列举完毕,方便大家学习掌握。

  • FONTNAME:字体名称
  • FONTSIZE:字体大小
  • LEADING:行间距
  • TEXTCOLOR:字体颜色
  • ALIGNMENT:水平对齐方式(可选值:”LEFT”,”RIGHT“,”CENTER“)
  • LEFTPADDING:左边填充
  • RIGHTPADDING:右边填充
  • BOTTOMPADDING:底部填充
  • TOPPADDING:顶部填充
  • BACKGROUND:背景色
  • VALIGN:垂直对齐方式(可选值:”TOP”,“MIDDLE”,“BOTTOM”)
  • GRID:表格颜色,被指定的行列中的所有子行和子列都被设置成相应颜色
  • INNERGRID:表格颜色,仅仅修改指定的子行和子列的相应颜色(不包括边框)
  • BOX:边框颜色,被指定的边框的颜色
  • LINEBELOW:指定块底部的行颜色
  • LINEAFTER:指定块右边的行颜色。

6.图片

图片的调用接口比较简单,在调用该接口时,支持默认的jpeg格式。接口如下:

  1. Image(filename, width=None, height=None)
  • filename:指定文件名
  • width:指定图片的宽度
  • height:指定图片的高度

如果宽度和高度有一个没有被指定,则参考原来的图片像素。

先举一个例子:

  1. from reportlab.platypus import SimpleDocTemplate, Image
  2. from reportlab.lib.styles import getSampleStyleSheet
  3. doc = SimpleDocTemplate("Hello.pdf")
  4. styles = getSampleStyleSheet()
  5. style = styles['Normal']
  6. story =[]
  7. t = Image("C:\\Users\\Administrator\\Desktop\\timg.jpg")
  8. story.append(t)
  9. doc.build(story)

打开指定的PDF文件,查看效果如下:

ReportLab pdf管理 - 图8

后记:本文介绍了ReportLab中最常用的4个功能:Platypus、段落、表格和图片。

在使用过程中,还会遇到很多问题,比如在使用中文时,需要首先注册字体等问题,需要大家自己摸索,当然也可以留言一起讨论哦。

中文问题

https://www.jianshu.com/p/41284e4e25f5

用reportlab生成pdf文件,碰到中文就会变成黑色的小方块,如下图。
image.png

解决方法

1.下载中文字体SimSun.ttf
2.把下载下来的字体放到/Library/Python/2.7/site-packages/reportlab/fonts文件夹下。(文件夹根据自己安装的reportlab的路径来)
3.注册字体并使用

  1. from reportlab.platypus import SimpleDocTemplate, Image, Paragraph
  2. from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
  3. from reportlab.pdfbase import pdfmetrics
  4. from reportlab.pdfbase.ttfonts import TTFont
  5. pdfmetrics.registerFont(TTFont('SimSun', 'SimSun.ttf')) #注册字体
  6. styles = getSampleStyleSheet()
  7. styles.add(ParagraphStyle(fontName='SimSun', name='Song', leading=20, fontSize=12)) #自己增加新注册的字体
  8. Paragraph(describe, styles['Song']), #使用新字体

还有文字换行问题,暂时用了下面的方式

  1. Paragraph(u'<br/>%s<br/>' % describe, styles['Song'])

参考

https://zhaobugs.com/2018/07/09/%E4%BD%BF%E7%94%A8Python%E7%94%9F%E6%88%90PDF-reportlab%E7%AF%87/