word文档内的一页:
将文本取出来,生成自定义格式的PDF文件:
从word取出文本时标题的标号和页码是取不出来的,要自己加。另外就是目录也要自己生成和添加:
代码和解释如下:
from reportlab.lib.styles import ParagraphStyle as PS
# 段落格式
from reportlab.platypus import PageBreak
# 分页符
from reportlab.platypus.paragraph import Paragraph
# 生成段落用
from reportlab.platypus.doctemplate import PageTemplate, BaseDocTemplate # 用于生成页面模版,文档模版
from reportlab.platypus.tableofcontents import TableOfContents # 用于生成目录
from reportlab.platypus.frames import Frame
# 生成页面模版是定义页面内的框架frame
from reportlab.lib.units import cm, inch
# 尺度单位
# 注册中文字体
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.pdfbase import pdfmetrics
pdfmetrics.registerFont(TTFont('lively', '/Library/Fonts/Chinese/ChaoZiSheZengYuBoShouShuJian-2.ttf'))
pdfmetrics.registerFont(TTFont('apple', '/Library/Fonts/Chinese/XiaoHuYao-2.ttf'))
# 定义标题、普通段落和代码的段落格式
h1 = PS(name = 'Heading1', fontSize = 16, leading = 24, fontName = 'lively', spaceAfter = 15)
h2 = PS(name = 'Heading2', fontSize = 14, leading = 20, leftIndent = 10, fontName = 'lively', spaceBefore = 10, spaceAfter = 10)
h3 = PS(name = 'Heading3', fontSize = 12, leading = 16, leftIndent = 20, fontName = 'lively', spaceBefore = 10, spaceAfter = 10)
normalText = PS(name = 'normal', fontSize = 12, leading = 14, firstLineIndent = 25, fontName = 'apple')
code = PS(name = 'code', fontSize = 10, leading = 14, leftIndent = 35,fontName = 'apple')
class MyDocTemplate(BaseDocTemplate):
# 是BaseDocTemplate的子类
def __init__(self, filename, **kw):
BaseDocTemplate.__init__(self, filename, **kw)
template = PageTemplate('normal', [Frame(2.5*cm, 2.5*cm, 15*cm, 25*cm, id='F1')], onPageEnd=self.footer)
# 定义页面模版,页脚可有可无
self.addPageTemplates(template) # 加入页面模版
# 打开word取出文字内容,生成段落flowable放进story
def feedContent(self, filename, story):
from docx import Document # 帮忙处理word文档
docWord = Document(filename)
# 打开word文档,生成word文档对象
h1Num = 0; h2Num = 0; h3Num = 0
# 因为要给标题加序号,三级序号,所以用变量记录所在层级的序号
for para in docWord.paragraphs:
# 遍历word文档的各个段落
docStyle = para.style.name
# 取出word文档中的段落格式
if docStyle == 'Heading 1':
# 如果是第一级标题,先加上序号再填进story
h1Num += 1
# 标记第一级标题的序号增1
seq = str(h1Num) + '、 '
# 第一级标题的格式为1、
story.append(Paragraph(seq + para.text, h1)) # 生成段落followable加入story
elif docStyle == 'Heading 2': # 第二级标题
h2Num += 1
# 标记第二级标题的序号增1
seq = str(h1Num) + '.' + str(h2Num) + ' '
# 第二级标题格式1.1
story.append(Paragraph(seq + para.text, h2))
elif docStyle == 'Heading 3': # 第三级标题
h3Num += 1
# 标记第三级标题的序号增1
seq = str(h1Num) + '.' + str(h2Num) + '.' + str(h3Num) + ' '
# 第三级标题的序号1.1.1
story.append(Paragraph(seq + para.text, h3))
elif docStyle == 'Code':
# 普通段落和代码直接填进story,注意代码用Preformatted()保留代码的缩进格式(杭首空格)
from reportlab.platypus import Preformatted
story.append(Preformatted(para.text, code))
else:
story.append(Paragraph(para.text, normalText))
# 生成一个flowable后判断是否为标题,是标题填进目录,二三级目录生成书签链接
def afterFlowable(self, flowable): # 注册目录的条目
if flowable.__class__.__name__ == 'Paragraph':
text = flowable.getPlainText() # 取出文字
style = flowable.style.name # 取出段落格式
if style == 'Heading1': # 第一级标题
self.notify('TOCEntry', (0, text, self.page))
if style == 'Heading2': # 第二级标题
key = 'h2-{}'.format(self.seq.nextf('heading2')) # 生成书签名
self.canv.bookmarkPage(key) # 生成书签页
self.notify('TOCEntry', (1, text, self.page, key))
# 'TOCEntry':通知类型;(1, text, self.page, key):
# (目录层级、文本内容、当前页数、可选的书签名)
if style == 'Heading3': # 第三级标题
key = 'h3-{}'.format(self.seq.nextf('heading3'))
self.canv.bookmarkPage(key)
self.notify('TOCEntry', (2, text, self.page, key))
# 页脚给出第几页
def footer(self, myCanvas, myDoc):
myCanvas.setFont('lively',10) # 设置字体
myCanvas.drawRightString(7.6*inch,.5*inch, "{}".format(self.page))
# 画页脚
toc = TableOfContents() # 生成目录对象
toc.levelStyles = [h1, h2, h3]
# 定义目录的格式,三层,每层的格式用段落格式定义
story = []
# 列表story存放生成的各个flowable
story.append(toc)
# 将目录对象填进story,此时目录只是架子,内容还没填进去
story.append(PageBreak()) # 分页符
docPDF = MyDocTemplate('mintoc.pdf')
# 生成PDF文档对象
docPDF.feedContent('excerpt.docx', story)
# 打开word文档,取出内容生成flowable放进story中
docPDF.multiBuild(story)
# 这个文档的生成要过两遍,第一遍加了个目录的空架子,
# 文档内容生成之后才能把目录内容填进去,所以用multiBuild()而不是build()