Python办公自动化|学Python,用Python自动创建PDF文档,实现办公自动化

我们经常将DOC/DOCX、PPT文档另存或者转换为PDF文档。但是这个转换过程不可控,结果不一定能够达到我们的版式需求,因此本节介绍如何使用库从零开始制作PDF文档。
8.2.1 用ReportLab库创建PDF文档 ReportLab是一个用于创建PDF文档的Python库,其功能非常强大,安装方法也非常简单,直接用pip命令安装即可。
1.创建简单的PDF文档 下面我们看一下8.1节示例中的PDF文档是如何自动创建的。
首先从reportlab包的pdfgen目录下导入canvas模块。

>>> from reportlab.pdfgen import canvas

canvas是画布的意思,制作PDF文档好比在空白的画布上作画。
canvas模块有个Canvas类,是创建PDF文档的入口。通过help函数可以查询它的用法。
>>> help(canvas.Canvas) ... def__init__(self,filename,pagesize=None,bottomup=1,pageCompression=None,invariant=None,verbosity=0, \ |encrypt=None,cropMarks=None,pdfVersion=None,enforceColorSpace=None,initialFontName=None, \ initialFontSize=None,initialLeading=None,cropBox=None,artBox=None,trimBox=None,bleedBox=None,lang=None,): ...

初始化方法可以传入的值很多,必须传入的是待创建的PDF文档的文件名(filename)。
>>> c=canvas.Canvas('H:\示例\第8章\HelloWorld.pdf') >>> c

方法返回的是
reportlab.pdfgen.canvas.Canvas类的一个实例对象,赋值给变量c,后面用c指代该实例对象。
用dir函数查看对象的属性和方法,主要包括:absolutePosition、acroForm、addLiteral、addOutlineEntry、addPageLabel、addPostScriptCommand、arc、beginForm、beginPath、beginText、bezier、bookmarkHorizontal、
bookmarkHorizontalAbsolute、bookmarkPage、bottomup、circle、clipPath、cross、delCatalogEntry、delViewerPreference、doForm、drawAlignedString、drawBoundary、drawCentredString、drawImage、drawInlineImage、drawPath、drawRightString、drawString、drawText、ellipse、endForm、freeTextAnnotation、getAvailableFonts、getCatalogEntry、getCurrentPageContent、getPageNumber、getViewerPreference、getpdfdata、grid、hasForm、highlightAnnotation、imageCaching、init_graphics_state、inkAnnotation、inkAnnotation0、line、linearGradient、lines、linkAbsolute、linkRect、linkURL、listLoadedFonts0、pageHasData、pop_state_stack、push_state_stack、radialGradient、rect、resetTransforms、restoreState、rotate、roundRect、save、saveState、scale、setArtBox、setAuthor、setBleedBox、setCatalogEntry、setCreator、setCropBox、setDash、setDateFormatter、setEncrypt、setFillAlpha、setFillColor、setFillColorCMYK、setFillColorRGB、setFillGray、setFillOverprint、setFont、setFontSize、setKeywords、setLineCap、setLineJoin、setLineWidth、setMiterLimit、setOutlineNames0、setOverprintMask、setPageCallBack、setPageCompression、setPageDuration、setPageRotation、setPageSize、setPageTransition、setProducer、setStrokeAlpha、setStrokeColor、setStrokeColorCMYK、setStrokeColorRGB、setStrokeGray、setStrokeOverprint、setSubject、setTitle、setTrimBox、setViewerPreference、shade、showFullScreen0、showOutline、showPage、skew、state_stack、stringWidth、textAnnotation、textAnnotation0、transform、translate、wedge。
通过这些方法,我们可以在画布上绘制复杂的PDF文档。
使用setPageSize方法设置页面大小。
>>> c.setPageSize((1200,800))

页面大小也可以在初始化Canvas对象的时候,通过代入.pagesize进行设置。
使用setFont方法设置字体。
>>> c.setFont('Helvetica',200)

设置后,我们可以看到属性值发生了变化。
>>> c._pagesize, c._fontname,c._fontsize ((1200, 800), 'Helvetica', 200)

使用drawString方法在画布上书写,参数包括起点坐标和文本内容。PDF文档中的每个元素都和位置相关,所以绘制元素时必须指定坐标。画布上的每个点都可以用坐标(x,y)表示,原点(0,0)在左下角,向右移动增加x值,向上移动增加y值。
>>> c.drawString(50, 400, 'Hello,World!')

画布画完后,使用showPage方法关闭当前页并翻页,继续绘制下一页。
>>> c.showPage()

本例只有一页,直接保存文件,结束任务。
>>> c.save()

用PDF阅读器或者文本编辑器打开PDF文档,可以看到和8.1.1节的PDF文档是一样的。
我们可以解析PDF文档。
>>> import re >>> from reportlab.lib.utils import import_zlib as z_pdf >>> from reportlab.lib.rl_accel import asciiBase85Decode as abd_pdf >>> pdf=open('H:\示例\第8章\HelloWorld.pdf', 'rb').read() >>> stream=re.compile(b'.*?FlateDecode.*?stream(.*?)endstream', re.S) >>> [z_pdf().decompress(abd_pdf(s.strip(b'\r\n'))) for s in re.findall(stream,pdf)] [b'1 0 0 1 0 0 cmBT /F1 12 Tf 14.4 TL ET\nBT /F1 200 Tf 240 TL ET\nBT 1 0 0 1 50 400 Tm (Hello,World!) Tj T* ET\n \n']

作画之前还可以设置画笔的状态,例如颜色、线条的宽度(_lineWidth)、写字用的字体(_fontname、_fontsize)等。前面我们设置了英文字体,由于reportlab包不带中文字体,需要通过官方渠道下载字体文件(下面用到微软雅黑msyh.ttf),放到reportlab安装包下面的font文件夹中,如图8-5所示。
要注意的是,字体使用之前还需要注册。
>>> from reportlab.pdfbase.ttfonts import TTFont >>> from reportlab.pdfbase import pdfmetrics >>> pdfmetrics.registerFont(TTFont('微软雅黑', 'msyh.ttf'))

Python办公自动化|学Python,用Python自动创建PDF文档,实现办公自动化
文章图片


图8-5
对页面大小的修改在翻页以后仍然有效,但是字体的设置只在本页有效。
>>> c.setPageSize((1200,800)) >>> c.setFont('Helvetica',200) >>> c.showPage() >>> c._pagesize, c._fontname,c._fontsize ((1200, 800), 'Helvetica', 12)

也就是说,每次翻页,字体都恢复到最初状态。最初的字体状态是由类实例化时传入的数值控制的。
>>> c._initialFontName,c._initialFontSize ('Helvetica', 12)

类实例化时调用了init_graphics_state方法,初始化了画笔状态,包括字体、颜色、字符间距、线条宽度等。showPage方法调用了_startPage方法,后者又调用了init_graphics_state方法,最终将字体恢复到最初状态(_initialFontName、_initialFontSize)。
如果我们需要在同一页面多次设置画笔状态,可以使用saveState和restoreState方法保存和还原画笔状态。
下面以字体设置为例。
>>> c.setFont('Courier',100) >>> c.saveState() >>> c._pagesize, c._fontname,c._fontsize ((1200, 800), 'Courier', 100) >>> c.setFont('Helvetica',300)

使用restoreState方法可以将画笔恢复到上次使用saveState方法保存的状态。
>>> c.restoreState() >>> c._pagesize, c._fontname,c._fontsize ((1200, 800), 'Courier', 100)

案例:制作精美的封面
下面我们多次设置画笔状态,书写汉字,并绘制线条和图形。
from reportlab.pdfgen import canvas from reportlab.lib.pagesizes import landscape, letter from reportlab.pdfbase.ttfonts import TTFont from reportlab.pdfbase import pdfmetrics from reportlab.lib.colors import pink, black, red, blue, green ? pdfmetrics.registerFont(TTFont('微软雅黑', 'msyh.ttf')) c=canvas.Canvas(r'H:\示例\第8章\report.pdf') ? c.setPageSize((1200,800)) c.drawImage(r'H:\示例\第8章\background.png',0,500,1200,300) c.drawImage(r'H:\示例\第8章\logo.png',0,800-72,190,72) ? c.setFont('微软雅黑',50) c.drawCentredString(600, 400,'2020年汽车金融专题研究报告') c.setFont('微软雅黑',30) c.drawCentredString(600, 300, '南山研究院 分析师 金融哥') c.setFont('微软雅黑',20) c.drawString(50, 120, '因 / 为 / 专 / 注 / 所 / 以 / 专 / 业') c.setFont('微软雅黑',30) c.drawRightString(1150, 120, '2020年3月') ? c.setLineWidth(10) c.line(0, 100,1200 ,100 ) c.setFont('微软雅黑',15) c.drawString(50, 80, '本产品保密并受到版权法保护') c.drawRightString(1150, 80, 'Confidential and Protected by Copyright Laws') ? c.setFillColor(red) c.rect(800, 500, 1200, 20, stroke=0, fill=1) ? c.setFillGray(0.75) c.setFillAlpha(0.3) c.rect(0, 500, 800, 20, stroke=0, fill=1) c.showPage() c.save()

语句?注册中文字体微软雅黑;语句?设置画布大小;语句?设置书写要用到的字体;语句?设置画笔线条宽度;语句?设置图形填充色;语句?设置矩形的灰度。还用了drawImage方法添加图片,用rect方法绘制矩形,图片和矩形的参数均要指定起始坐标、宽度和高度,另外图片还要指定文件路径。打开生成的PDF文档,效果如图8-6所示。
Python办公自动化|学Python,用Python自动创建PDF文档,实现办公自动化
文章图片


图8-6
如果一个PDF文档有多页,每页都有固定的元素,每页都重复绘制的话,代码量就比较大,因此可以将固定部分的制作代码放入循环。
使用Canvas类的doForm、beginForm、endForm方法也可以达到同样的效果。
from reportlab.pdfgen import canvas from reportlab.pdfbase.ttfonts import TTFont from reportlab.pdfbase import pdfmetrics pdfmetrics.registerFont(TTFont('微软雅黑', 'msyh.ttf')) c=canvas.Canvas(r'H:\示例\第8章\mydoc_form.pdf') c.setPageSize((1200,800)) ? c.beginForm('LOGO') c.drawImage(r'H:\示例\第8章\logo.png',0,800-72,190,72) ? c.endForm() list=['2020年汽车金融专题研究报告','2020年消费金融专题研究报告', '2020年融资租赁专题研究报告','2020年汽车销售专题研究报告'] for item in list: ?c.doForm('LOGO') c.setFont('微软雅黑',80) c.drawCentredString(600, 400,item) c.showPage() c.save()

语句?创建form,并将其命名为LOGO;语句?结束并保持form;语句?和?之间的代码绘制封面的固定内容,通过循环和语句?,完成文字的书写。打开生成的PDF文档,效果如图8-7所示。
Python办公自动化|学Python,用Python自动创建PDF文档,实现办公自动化
文章图片


图8-7
在以上例子中,我们用drawString、line、rect方法可以书写不同类型的内容。但是这种“画图”的方式非常低端,始终离不开坐标,如果我们要写入一大段文字,则需要计算每一行能放多少字,并不断调整坐标。由于所有的文字都是图画点,也就没有“自动换行”的功能。
pdfgen目录里面的模块还有很多,都只能进行比较底层的操作。如果要制作更复杂的内容,就要用到页面布局(platypus)。
2.添加段落、表格与图表 要想提升效率,就要减少重复劳动,多用模板和样式。在reportlab包中,platypus目录里的模块就是用来实现各种样式、版式的。platypus是“Page Layout and Typography Using Scripts”的缩写,它致力于把文档的样式和内容分开,段落、表格都直接套用相应的格式,页面也可以套用页面模版。
platypus包括几个层面:文档模板(DocTemplate)、页面模板(PageTemplate)、页面框架(Frame)、页面元素(flowables)。一个文档可以有多个页面模板,一个页面可以有多个框架,一个框架里可以放很多元素。
flowables,即可流动的元素,这是一个形象的比喻。最常见的页面元素就是段落,同样一段文字,随着框架大小的变化,可以被拆分来适应框架,每行字符不固定,其占据的行数也会发生变化。此外,表格、空白(Spacer)、分页符(PageBreak)、图片(Image)都是flowables。图片无法拆分,当框架太小时,它将移动到下一个框架,所以这些元素和坐标系就没有了联系,我们排版布局时,就不用考虑元素的坐标。只需要选择合适的文档和页面模板,设计不同的框架容器,然后依次放入页面元素,即可生成一个PDF文档。
(1)段落
制作段落需要用platypus子目录中paragraph模块的Paragraph类,其语法如下。
Paragraph(text, style, bulletText=None, caseSensitive=1)

它可以将文字和样式生成PDF文档中的段落。
参数text表示各个段落的文本内容。
>>> txt_0='什么是汽车金融?' >>> txt_1='''汽车金融是汽车全产业链覆盖的资本流动。狭义的汽车金融隶属于消费金融,广义的汽车金融贯穿全产业链。汽车金融的概念最早源于美国,狭义的汽车金融,更多地关注汽车销售环节,为下游客户提供融资性金融服务,隶属于消费金融。广义的汽车金融,是贯穿汽车的生产、流通、销售、使用、回收等环节中的资金流动,提高资本利用率和资金周转率。''' >>> txt_2='''我国汽车消费金融业萌芽于商业银行贷款,后经政策放宽,形成汽车金融公司、汽车融资租赁公司、互联网汽车金融公司等多元主体并存的局面。''' >>> txt_3='''中国汽车消费金融渗透率与海外成熟市场差距很大。汽车金融的渗透率,指通过贷款、融资等金融方式购买的车辆数量与汽车销量之比。中国汽车消费金融渗透率一直处于较低水平。'''

参数style表示段落样式。调用lib子目录中styles模块的getSampleStyleSheet函数。
>>> from reportlab.lib.styles import getSampleStyleSheet >>> s=getSampleStyleSheet() >>> s

返回的是样式表StyleSheet1对象,它里面有一些基本的样式可供我们直接使用。用dir函数查看对象的属性和方法,主要包括:add、byAlias、byName、get、has_key、list。
使用list方法输出全部样式的样式设置。
>>> s.list()

其中,Normal、Title样式的主要默认属性说明见表8-1。
表8-1
属性
说明
Normal
Title
name
样式名称
Normal
Title
parent
父对象
None
<'Normal'>
alignment
文字对齐
0
1
allowOrphans
页底段落最小行数
0
0
allowWidows
页顶段落最小行数
1
1
backColor
背景颜色
None
None
borderColor
边框颜色
None
None
borderPadding
内容与边距的距离
【Python办公自动化|学Python,用Python自动创建PDF文档,实现办公自动化】0
0
borderRadius
圆角的边框
None
None
borderWidth
边框宽度
0
0
firstLineIndent
首行缩进
0
0
fontName
字体名称
Helvetica
Helvetica-Bold
fontSize
字体大小
10
18
leading
行距
12
22
leftIndent
左缩进
0
0
rightIndent
右缩进
0
0
spaceAfter
段后间隔
0
6
spaceBefore
段前间隔
0
0
textColor
文字颜色
Color(0,0,0,1)
Color(0,0,0,1)
wordWrap
单词中换行
None
None
可以修改样式的默认属性值。
>>> from reportlab.pdfbase.ttfonts import TTFont >>> from reportlab.pdfbase import pdfmetrics >>> pdfmetrics.registerFont(TTFont('微软雅黑', 'msyh.ttf')) >>> s['Title'].fontName,s['Title'].fontSize='微软雅黑' ,30 >>> s['Title'].spaceAfter,s['Normal'].spaceBefore=30,10 >>> s['Normal'].fontName,s['Normal'].fontSize='微软雅黑',20 >>> s['Normal'].leading=30 >>> s['Normal'].firstLineIndent=40

下面生成段落。
由于platypus子目录中的__init__.py中有语句“from .paragraph import *”,所以可以直接调用Paragraph类。
>>> from reportlab.platypus import Paragraph

代入文本和样式参数,生成第1个段落对象。
>>> p_0=Paragraph(txt_0,s['Title']) >>> type(p_0) >>> p_1=Paragraph(txt_1,s['Normal']) >>> p_2=Paragraph(txt_2,s['Normal']) >>> p_3=Paragraph(txt_3,s['Normal'])

使用platypus目录中doctemplate模块的SimpleDocTemplate类。
>>> from reportlab.platypus import SimpleDocTemplate >>> doc=SimpleDocTemplate(r'H:\示例\第8章\mydoc.pdf',pagesize=(1200,800)) >>> doc

使用SimpleDocTemplate对象的build方法,它可以将页面元素放入文档,生成最终的PDF文档。
build(self,flowables,onFirstPage=_doNothing, onLaterPages=_doNothing, canvasmaker=canvas.Canvas)

build方法必要的参数是页面元素,段落就是一种页面元素,但是要将其转为列表,才能作为build方法的参数。
>>> story_text=[p_0,p_1,p_2,p_3] >>> type(story_text)

代入参数,生成文件。
>>> doc.build(story_text)

打开生成的PDF文档,效果如图8-8所示。
除了修改样式,我们还可以使用add(style, alias=None)方法添加样式。
>>> from reportlab.lib.styles import ParagraphStyle >>> s_par=ParagraphStyle(name='A1',fontName='微软雅黑',fontSize=40,firstLineIndent=0) >>> s_par>>> s.add(s_par) >>> p=Paragraph('微软雅黑40号字体',s['A1'])

Python办公自动化|学Python,用Python自动创建PDF文档,实现办公自动化
文章图片


图8-8
(2)表格
一般来说,PDF文档中的表格和图表都是通过Excel表格生成,再以图片的形式插入PDF文档中,但是这种图像在放大以后就会变得很模糊,下面尝试直接在PDF文档中绘制表格和图表。
和段落一样,表格也是一种页面元素。
下面需要用platypus子目录中tables模块的Table类制作表格,其语法如下。
Table(data,colWidths=None,rowHeights=None,style=None,repeatRows=0,repeatCols=0,splitByRow=1,emptyTableAction=None,ident=None,hAlign=None,vAlign=None,normalizedData=https://www.it610.com/article/0,cellStyles=None,rowSplitRange=None, spaceBefore=None,spaceAfter=None,longTableOptimize=None,minRowHeights=None)

数据源data是必须指定的,它是一个二维数组,和要显示的表的每一行、每一列对应。其余的都是可选参数,常用的包括前3个。参数colWidths是一个列表,表示各列的宽度,例如col_widths=[100,50, 50]表示第1列宽100,第2、3列宽50;参数rowHeights表示行高,其设置方法与列宽类似,如果不设置这两个参数,列宽和行高就会变成自适应;参数style表示表格的样式,具体使用TableStyle对象来逐个项目逐个单元格地设置。
首先,构造表格数据参数。
>>> data=https://www.it610.com/article/[['姓名','一季度','二季度','三季度','四季度'], ...['小赵',100,110,125,135], ['小钱',110,114,126,123], ...['小孙',120,115,127,141],['小李',130,117,128,165], ...['小王',120,127,122,125]]

其次,构造表格列宽、行高参数。
>>> col_widths, row_heights=[80,100,100,100,100],[60,50,50,50,50,50]

然后,构造表格样式参数。调用platypus子目录中Table模块的TableStyle类。
>>> from reportlab.platypus import TableStyle >>> from reportlab.lib import colors >>> from reportlab.pdfbase.ttfonts import TTFont >>> from reportlab.pdfbase import pdfmetrics >>> pdfmetrics.registerFont(TTFont('微软雅黑', 'msyh.ttf')) >>> table_style=TableStyle([ ...('FONT', (0, 0), (0, -1), '微软雅黑', 30), ...('FONT', (0, 0), (-1, 0), '微软雅黑', 30), ...('FONT', (1, 1), (-1, -1), '微软雅黑', 15), ...('ALIGN', (0, 0), (-1, -1), 'CENTER'), ...('VALIGN', (0, 0), (-1, -1), 'MIDDLE'), ...('GRID', (0,0), (-1,-1), 0.5, colors.black), ...('INNERGRID', (0,0), (-1,-1), 0.25, colors.black), ...('BOX', (0,0), (-1,-1), 0.25, colors.black), ...('BACKGROUND',(0,0),(-1,-1),colors.white)])

设置表格样式的语法比较特殊,它使用“属性,左上角,右下角,属性值”,表示对某个单元格区域设置属性。0表示第一行或者第一列,?1表示最后一行或最后一列。例如(0, 0)表示左上角单元格,(?1, ?1)表示右下角单元格,围起来的区域就是整个表格。
有了全部参数,下面使用Table类实例化一个表格。
>>> from reportlab.platypus import Table >>> table=Table(data,colWidths=col_widths,rowHeights=row_heights,style=table_style) >>> type(table)

给表格增加一个标题。
>>> tabletitle='''表1: 销售情况表''' >>> from reportlab.lib.styles import getSampleStyleSheet >>> styles=getSampleStyleSheet() >>> from reportlab.platypus import Paragraph

一起放入列表。
>>> story_table=[Paragraph(tabletitle,styles['Normal']),table]

调用SimpleDocTemplate类的build方法,生成PDF文档。
>>> from reportlab.platypus import SimpleDocTemplate >>> doc=SimpleDocTemplate(r'H:\示例\第8章\mydoc_table.pdf',pagesize=(1200,800)) >>> doc.build(story_table)

打开生成的PDF文档,效果如图8-9所示。
(3)图表
在PDF文档中添加各种图形,需要用到graphics子目录中的各个模块。下面尝试直接在PDF文档中绘制图表。
调用shapes模块的Drawing类。
>>> from reportlab.graphics.shapes import Drawing

实例化Drawing类,指定绘图区的宽、高。
>>> d=Drawing(100, 100) >>> d

获得一个绘图区Drawing对象,用dir函数查看对象的属性和方法,主要包括:add、asDrawing、asGroup、asString、background、contents、copy、draw、drawOn、dumpProperties、expandUserNodes、getBounds、getContents、getKeepWithNext、getProperties、getSpaceAfter、getSpaceBefore、hAlign、height、identity、insert、isIndexing、minWidth、renderScale、resized、rotate、save、scale、setProperties、shift', 'skew、split、splitOn、transform、translate、vAlign、verify、width、wrap、wrapOn。
Python办公自动化|学Python,用Python自动创建PDF文档,实现办公自动化
文章图片


图8-9
有了绘图区,下一步就是绘制条形图。
绘制条形图需要使用barcharts模块中的VerticalBarChart类。
>>> from reportlab.graphics.charts.barcharts import VerticalBarChart >>> bar=VerticalBarChart() >>> bar

获得一个垂直条形图VerticalBarChart对象,用dir函数查看对象的属性和方法,主要包括:background、barLabelArray、barLabelFormat、barLabels、barSpacing、barWidth、bars、calcBarPositions、categoryAxis、categoryNALabel、data、debug、demo、draw、dumpProperties、fillColor、getBounds、getProperties、getSeriesName、getSeriesOrder、groupSpacing、height、makeBackground、makeBars、makeSwatchSample、naLabel、provideNode、reversePlotOrder、setProperties、strokeColor、strokeWidth、useAbsolute、valueAxis、verify、width、x、y、zIndexOverrides。
下面设置对象的各种属性。
>>> bar.x,bar.y,bar.height,bar.width,bar.valueAxis.valueMin=50,-150,280,500,0 >>> bar.categoryAxis.categoryNames=['2012','2013','2014','2015','2016'] >>> bar.data=https://www.it610.com/article/[[16, 17, 18, 24, 25]]>>> bar.bars[0].fillColor,bar.barLabels.nudge=colors.black,18 >>> bar.barLabelFormat,bar.valueAxis.labels.fontSize='%0.0f',20 >>> bar.categoryAxis.labels.fontSize,bar.barLabels.fontSize=20,30

通过Drawing对象的add方法将条形图放入绘图区。
>>> d.add(bar)

下面在绘图区中添加一个标题。
>>> from reportlab.graphics.charts.textlabels import Label >>> title=Label() >>> title.setText('图1: 汽车金融公司数量') >>> title.fontSize,title.fontName,title.dx,title.dy=20,'微软雅黑',260,160 >>> d.add(title)

将绘图区放入列表,为了防止太靠近顶端,在绘图区上方添加空格。
>>> from reportlab.platypus import Spacer >>> story_chart=[Spacer(1,75),d]

调用SimpleDocTemplate类的build方法,生成PDF文档。
>>> from reportlab.platypus import SimpleDocTemplate >>> doc=SimpleDocTemplate(r'H:\示例\第8章\mydoc_chart.pdf',pagesize=(1200,800)) >>> doc.build(story_chart)

打开生成的PDF文档,效果如图8-10所示。
Python办公自动化|学Python,用Python自动创建PDF文档,实现办公自动化
文章图片


图8-10
本例中的图表是矢量化的图表,即使放大也不会变模糊。
绘图区的保存方式有多种。
>>> from reportlab.pdfgen import canvas >>> my_canvas=canvas.Canvas(r'H:\示例\第8章\mydoc_chart.pdf', pagesize=(1200,800)) >>> d.drawOn(my_canvas, 100, 100) >>> my_canvas.save()

或者以下方式。
>>> d.save(formats=['pdf'],fnRoot=r'H:\示例\第8章\mydoc_chart')

或者以下方式。
>>> from reportlab.graphics import renderPDF >>> renderPDF.drawToFile(d,r'H:\示例\第8章\mydoc_chart.pdf',autoSize=0)

3.页面布局设计 单个的段落、表格、图表都容易实现,但有时候我们需要将其混排在一起。前面提到的段落、表格、图表都属于Flowable对象,其位置和坐标没关系,是可以变化的,那么如何才能准确地排版呢?那就需要把它们放置在固定的区域内。使用框架可以将复杂的PDF页面分为不同的区域,用来放置文字、表格、图表等内容。
导入框架类Frame。
>>> from reportlab.platypus import Frame

查看Frame类的帮助信息。
>>> help(Frame)

在帮助文档中可以查到Frame类的实例化参数。
class Frame(builtins.object) Frame(x1, y1, width,height, leftPadding=6, bottomPadding=6, rightPadding=6, topPadding=6, id=None, showBoundary=0)

Frame的外观示意图如图8-11所示。
Python办公自动化|学Python,用Python自动创建PDF文档,实现办公自动化
文章图片


图8-11
Frame主要用于界定了画布上可以放元素的区域。我们看到Frame的左下角的坐标为(x1,y1),该坐标相对于使用时的画布;尺寸为width×height;Padding是指定边距,扣除边距剩下的就是可供绘图的空间;参数id表示识别符;参数showBoundary表示边界线。
下面将页面分为3个区域,分别放入文字、图表、表格。
>>> f1=Frame(0, 0, 600, 400, showBoundary=1, id='f1') >>> f2=Frame(600, 0, 600, 400, showBoundary=1, id='f2') >>> f3=Frame(0, 400, 1200, 400, showBoundary=1, id='f3') >>> f3

用dir函数查看Frame对象的方法和属性,主要包括:add、addFromList、add_generated_content、drawBoundary、id、showBoundary、split。
可以通过设置showBoundary=0不显示框架的线条,这样既可以对齐内容,又不会显得页面太乱,即使是复杂的版式也显得井井有条。
有了框架,我们就再也不用担心画布上的元素无法对齐了。下面创建一个画布。
>>> from reportlab.pdfgen.canvas import Canvas >>> c=Canvas(r'H:\示例\第8章\mydoc_Frame.pdf') >>> c.setPageSize((1200,800))

使用Frame对象的addFromList(drawlist, canv)方法,可以将元素列表(包含flowables的list)按照框架规定的位置放到画布上面。story_chart、story_table、story_text的制作过程前面已经介绍过,此处不再赘述。
>>> f1.addFromList(story_chart,c) >>> f2.addFromList(story_table,c) >>> f3.addFromList(story_text,c) >>> c.save()

打开生成的PDF文档,效果如图8-12所示。
Python办公自动化|学Python,用Python自动创建PDF文档,实现办公自动化
文章图片


图8-12
有时候我们需要在每一页都添加固定的内容,如公司Logo、页码等信息,这时就要用到页眉和页脚。页眉和页脚应当是自动化生成的,在前面调用doForm方法的案例中,我们插入的logo不是页眉,因为下一页的logo还要手动插入,而无法自动生成。
前面我们用到的build方法,还有两个参数onFirstPage和onLaterPages,用于指定在首页的操作和在后面所有页的操作。
我们看一个例子。
from reportlab.platypus import SimpleDocTemplate, Paragraph,PageBreak, Spacer from reportlab.lib.styles import getSampleStyleSheet from reportlab.pdfbase.ttfonts import TTFont from reportlab.pdfbase import pdfmetrics pdfmetrics.registerFont(TTFont('微软雅黑', 'msyh.ttf')) def header_footer(c, doc): c.drawImage(r'H:\示例\第8章\logo.png',1200-190,800-72,190,72) c.setFont('微软雅黑',20) c.drawString(50, 60, '因 / 为 / 专 / 注 / 所 / 以 / 专 / 业') c.setLineWidth(3) c.line(0, 50,1200 ,50 ) c.line(0, 800-75,1200 ,800-75 ) c.setFont('微软雅黑',20) c.drawString(50, 30, '本产品保密并受到版权法保护') c.drawRightString(1150, 30, 'Confidential and Protected by Copyright Laws') page_num=c.getPageNumber() c.setFont('微软雅黑',30) text='第 %s页' % page_num c.drawRightString(580,20, text) c.setFont('微软雅黑',50) c.rotate(30) c.setFillAlpha(0.2) c.drawString(600, 0, '版权所有 南山金融研究') c.rotate(-30) myPDF=SimpleDocTemplate(r'H:\示例\第8章\mydoc.pdf',pagesize=(1200,800)) story=[] list=['2020年汽车金融专题研究报告','2020年消费金融专题研究报告', '2020年融资租赁专题研究报告','2020年汽车销售专题研究报告'] styles=getSampleStyleSheet() styles['Normal'].fontName='微软雅黑' styles['Normal'].fontSize=40 for item in list: story.append(Spacer(1,200)) story.append(Paragraph(item, styles['Normal'])) story.append(PageBreak()) myPDF.build(story, onFirstPage=header_footer, onLaterPages=header_footer)

函数header_footer定义了制作页眉和页脚的操作,build方法的参数传入了函数名header_footer,即onFirstPage=header_footer、onLaterPages=header_footer,表示每一页都会自动完成添加页眉和页脚的操作。
打开生成的PDF文档,效果如图8-13所示。
Python办公自动化|学Python,用Python自动创建PDF文档,实现办公自动化
文章图片


图8-13
本例还实现了在新建文件中添加水印的效果,给已有的文件添加水印,将用其他库来实现。当然,这种水印也很容易去除。还可以将PDF文档的页面转换成图片,然后在图片上加水印,最后将加完水印的图片组合生成PDF文档,这样的水印就难以去除了。
本文截选自《学Python 不加班 轻松实现办公自动化》
Python办公自动化|学Python,用Python自动创建PDF文档,实现办公自动化
文章图片


这是一本关于如何利用Python提高日常办公效率的书,书中凝聚了作者多年的实践经验和独特思考,旨在帮助读者准确、高效地完成大量高重复度的工作。

《学Python,不加班:轻松实现办公自动化》汇集了日常办公和处理文档时常见的问题,通过实例的演示与讲解,帮助读者灵活有效地使用Python处理工作中遇到的问题。全书共11章,涵盖Python的各种应用场景,具体包括文件管理自动化,网络信息自动获取,TXT、XLS/XLSX、DOC/DOCX、PPT、PDF、图片文件的自动化处理,模拟鼠标、键盘操控本地软件,自动化运行管理等。本书力图淡化编程中的抽象概念,贴合工作场景,注重实战效果,通过对Python技术的巧妙讲解,帮助读者成为高效率的办公室“超人”。

《学Python,不加班:轻松实现办公自动化》适合任何想要学习Python编程的读者,尤其适合缺乏编程经验的初学者。同时本书提供所有案例的源代码文件,方便读者边学边练,爱上Python编程。

    推荐阅读