当前位置: 首页 > news >正文

ReportLab 导出 PDF(文档创建)

文章目录

  • 1. 安装 ReportLab
  • 2. 创建 PDF 文件
  • 3. DocTemplate(文档模板 )
  • 4. PageTemplate(页面模板 )
  • 5. BaseDocTemplate(文档模板基类 目录)
  • 6. SimpleDocTemplate(页眉页脚)
  • 7. SimpleDocTemplate(继承 Canvas 页码)
  • 8. 直接使用 Canvas(复杂场景)

官网:https://docs.reportlab.com/
英文手册:https://docs.reportlab.com/reportlab/userguide/ch1_intro/
中文手册:https://gitcode.com/Open-source-documentation-tutorial/d25f8/blob/main/reportlab%E4%B8%AD%E6%96%87%E6%89%8B%E5%86%8C.pdf

参考:
https://www.cnblogs.com/windfic/p/17157841.html

https://dev59.com/uF7Va4cB1Zd3GeqPKod0
https://www.jb51.net/article/270782.htm
https://www.osgeo.cn/python-tutorial/pdf-reportlab.html
https://blog.51cto.com/u_14940497/12374520
https://blog.csdn.net/qq_40596572/article/details/102896520
https://www.cnblogs.com/jilingxf/p/15857940.html

1. 安装 ReportLab

可以通过pip安装:

pip install reportlab

2. 创建 PDF 文件

下面是一个简单的示例,展示如何使用 ReportLab 创建一个包含文本和图像的 PDF 文件:

from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import letter
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.pdfbase import pdfmetrics# 注册字体
song = "simsun"
pdfmetrics.registerFont(TTFont(song, "simsun.ttc"))
# pdfmetrics.registerFont(TTFont('MyFont', 'path/to/your/font.ttf'))# 创建一个PDF文件
c = canvas.Canvas("example.pdf", pagesize=letter)
c.setFont('simsun', 12)# 添加文本
# 默认情况下,(0,0)原点在页面的左下角。 此外,第一个坐标x往右走,第二个坐标y往上走,这是默认的。
c.drawString(10, 10, "Hello World!")# # 添加图像
c.drawImage('./image.jpg', 10, 60, width=500, height=500)# 保存PDF文件
c.save()

在这里插入图片描述

3. DocTemplate(文档模板 )

Reportlab 的基础使用方式是创建内容块(Flowable),再使用文档模板(DocTemplate)创建 Pdf 文档。
关注点:
Paragraph(段落)、
Image(图像)、
Table(表格)、
VerticalBarChart(柱形图表)

from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFontfrom reportlab.lib.styles import getSampleStyleSheet
from reportlab.platypus import Paragraph, SimpleDocTemplate, Image, Table
from reportlab.platypus import Spacer
from reportlab.graphics.shapes import Drawing
from reportlab.graphics.charts.barcharts import VerticalBarChart
from reportlab.graphics.charts.legends import Legend
from reportlab.lib import  colors
from reportlab.lib.pagesizes import A4
from reportlab.lib.units import cmdef draw_text(st, text: str):return Paragraph(text, st)def draw_img(path):img = Image(path)       # 读取指定路径下的图片img.drawWidth = 6*cm    # 设置图片的宽度img.drawHeight = 5*cm   # 设置图片的高度return imgdef draw_table(*args):col_width = 120style = [('FONTNAME', (0, 0), (-1, -1), 'song'),  		# 字体('FONTSIZE', (0, 0), (-1, 0), 12),  			# 第一行的字体大小('FONTSIZE', (0, 1), (-1, -1), 10),  			# 第二行到最后一行的字体大小('BACKGROUND', (0, 0), (-1, 0), '#d5dae6'),  	# 设置第一行背景颜色('ALIGN', (0, 0), (-1, -1), 'CENTER'),  		# 第一行水平居中('ALIGN', (0, 1), (-1, -1), 'LEFT'),  			# 第二行到最后一行左右左对齐('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),  		# 所有表格上下居中对齐('TEXTCOLOR', (0, 0), (-1, -1), colors.darkslategray),  # 设置表格内文字颜色('GRID', (0, 0), (-1, -1), 0.5, colors.grey),  	# 设置表格框线为grey色,线宽为0.5('SPAN', (0, 1), (2, 1)),  						# 合并第二行一二三列]table = Table(args, colWidths=col_width, style=style)return tabledef draw_bar(bar_data: list, ax: list, items: list):drawing = Drawing(500, 200)bc = VerticalBarChart()bc.x = 45       	# 整个图表的x坐标bc.y = 45      		# 整个图表的y坐标bc.height = 150     # 图表的高度bc.width = 350      # 图表的宽度bc.data = bar_databc.strokeColor = colors.black      # 顶部和右边轴线的颜色bc.valueAxis.valueMin = 0          # 设置y坐标的最小值bc.valueAxis.valueMax = 20         # 设置y坐标的最大值bc.valueAxis.valueStep = 5         # 设置y坐标的步长bc.categoryAxis.labels.dx = 2bc.categoryAxis.labels.dy = -8bc.categoryAxis.labels.angle = 20bc.categoryAxis.labels.fontName = 'song'bc.categoryAxis.categoryNames = ax# 图示leg = Legend()leg.fontName = 'song'leg.alignment = 'right'leg.boxAnchor = 'ne'leg.x = 475         # 图例的x坐标leg.y = 140leg.dxTextSpace = 10leg.columnMaximum = 3leg.colorNamePairs = itemsdrawing.add(leg)drawing.add(bc)return drawingdef main(filename):pdfmetrics.registerFont(TTFont('song', 'STSONG.ttf'))style = getSampleStyleSheet()ts = style['Heading1']ts.fontName = 'song'    # 字体名ts.fontSize = 18        # 字体大小ts.leading = 30         # 行间距ts.alignment = 1        # 居中ts.bold = Truehs = style['Heading2']hs.fontName = 'song'    # 字体名hs.fontSize = 15        # 字体大小hs.leading = 20         # 行间距hs.textColor = colors.red  # 字体颜色ns = style['Normal']ns.fontName = 'song'ns.fontSize = 12ns.wordWrap = 'CJK'     # 设置自动换行ns.alignment = 0        # 左对齐ns.firstLineIndent = 32 # 第一行开头空格ns.leading = 20content = []content.append(draw_text(ts, '经典游戏盘点'))content.append(draw_img('./image.jpg'))content.append(Spacer(1, 1*cm))content.append(draw_text(ns, ' 《超级马里奥兄弟》于1985年9月13日发售,这是一款任天堂针对FC主机全力度身订造的游戏,被称为TV游戏奠基之作。这个游戏被赞誉为电子游戏的原始范本,确立了角色、游戏目的、流程分布、操作性、隐藏要素、BOSS、杂兵等以后通用至今的制作概念。《超级马里奥兄弟》成为游戏史首部真正意义上的超大作游戏,游戏日本本土销量总计681万份,海外累计更是达到了3342万份的天文数字。'))content.append(draw_text(hs, '经典游戏列表'))# 添加表格data = [('经典游戏', '发布年代', '发行商'),('TOP100',),('超级马里奥兄弟', '1985年', '任天堂'),('坦克大战', '1985年', '南梦宫'),('魂斗罗', '1987年', '科乐美'),('松鼠大战', '1990年', '卡普空'),]content.append(draw_table(*data))# 生成图表content.append(draw_text(hs, '游戏厂商统计'))b_data = [(2, 4, 6, 12, 8, 16), (12, 14, 17, 9, 12, 7)]ax_data = ['任天堂', '南梦宫', '科乐美', '卡普空', '世嘉', 'SNK']leg_items = [(colors.red, '街机'), (colors.green, '家用机')]content.append(draw_bar(b_data, ax_data, leg_items))# 生成pdf文件doc = SimpleDocTemplate(filename, pagesize=A4, topMargin=35)doc.build(content)if __name__ == '__main__':main(filename='example1.pdf')

在这里插入图片描述

4. PageTemplate(页面模板 )

上述的排版都是线性的,如果要有一些混排,比如列式排版,可以使用BalancedColumns,有一些页面排版比较复杂,那可以使用页面模板(PageTemplate)。
其实还可以用传统Web艺能——Table来做排版,我试了一下,只需要指定BOX,GRID为白色即可,线宽为0不行。
关注点:
PageTemplate(页面模板)
Frame(框架)

from reportlab.lib.colors import Color
from reportlab.lib.pagesizes import A4
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.lib.units import cm
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.pdfgen import canvas
from reportlab.lib import  colors
from reportlab.platypus import BaseDocTemplate, Frame, Paragraph, NextPageTemplate, PageBreak, PageTemplate, Image
from reportlab.lib.units import inchdef draw_text(st, text: str):return Paragraph(text, st)def draw_img(path):img = Image(path)       # 读取指定路径下的图片img.drawWidth = 5*cm    # 设置图片的宽度img.drawHeight = 4*cm   # 设置图片的高度return imgdef main(filename):# pdfmetrics.registerFont(TTFont('微软雅黑', 'msyh.ttf'))pdfmetrics.registerFont(TTFont('simsun', "simsun.ttc"))style = getSampleStyleSheet()ts = style['Heading1']ts.fontName = 'simsun'      # 字体名ts.fontSize = 18            # 字体大小ts.leading = 30             # 行间距ts.alignment = 1            # 居中ts.bold = Truehs = style['Heading2']hs.fontName = 'simsun'      # 字体名hs.fontSize = 15            # 字体大小hs.leading = 20             # 行间距hs.textColor = colors.red   # 字体颜色ns = style['Normal']ns.fontName = 'simsun'ns.fontSize = 12ns.wordWrap = 'CJK'     # 设置自动换行ns.alignment = 0        # 左对齐ns.firstLineIndent = 32 # 第一行开头空格ns.leading = 20doc = BaseDocTemplate(filename, showBoundary=0, pagesize=A4)frameT = Frame(doc.leftMargin, doc.bottomMargin, doc.width, doc.height, id='normal')# 一分为三w = doc.width / 3# 高度等于宽度h = w# 上面一行 底部bm = doc.height - h# 上面一行 左列frame1 = Frame(doc.leftMargin,      bm, w,           h, id='col1')# 上面一行 右列frame2 = Frame(doc.leftMargin + w,  bm, doc.width-w, h, id='col2')# 下面一行frame3 = Frame(doc.leftMargin, doc.bottomMargin, doc.width , bm-doc.topMargin, id='col3')doc.addPageTemplates([PageTemplate(id='TwoCol', frames=[frame1, frame2, frame3]),PageTemplate(id='OneCol', frames=frameT),])elements = []#### 适配 PageTemplate TwoCol# 上面一行 左列elements.append(draw_img("./image.jpg"))# 上面一行 右列elements.append(draw_text(ns, '11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 。'))elements.append(draw_text(ns, '22222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222 。'))elements.append(draw_text(ns, '33333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333 。'))#### 适配 PageTemplate OneColelements.append(NextPageTemplate('OneCol'))# 强制换页elements.append(PageBreak())elements.append(draw_text(ns, "Frame one column, 44444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444 。"))#### 适配 PageTemplate TwoColelements.append(NextPageTemplate('TwoCol'))elements.append(PageBreak())elements.append(draw_img("./image.jpg"))elements.append(draw_text(ns, '55555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555 。'))elements.append(draw_img("./image.jpg"))elements.append(draw_text(ns, '55555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555 。'))doc.build(elements)if __name__ == '__main__':main(filename='example2.pdf')
-------------------------------------在这里插入图片描述-------------------------------------

5. BaseDocTemplate(文档模板基类 目录)

前两种方式都不能精确输出,依赖于模板的排版,精确输出需要Canvas接口。
如果你要在每一页上显示页眉和页脚,那么你可以继承文档模板(BaseDocTemplate)。
如果你要添加目录索引,这就是最方便的方式。
覆盖接口:
handle_documentBegin
handle_pageBegin
handle_pageEnd
handle_frameBegin
handle_frameEnd
handle_flowable
handle_nextPageTemplate
handle_currentFrame
handle_nextFrame
或者实现回调函数:
afterInit
beforeDocument
beforePage
afterPage
filterFlowables
afterFlowable
关注点:
BaseDocTemplate(文档模板)
bookmarkPage(书签)
addOutlineEntry(大纲)

from reportlab.lib.styles import ParagraphStyle
from reportlab.platypus import PageBreak
from reportlab.platypus.paragraph import Paragraph
from reportlab.platypus.doctemplate import PageTemplate, BaseDocTemplate
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.platypus.frames import Frame
from reportlab.lib.units import cmclass MyDocTemplate(BaseDocTemplate):def __init__(self, filename, **kw):self.allowSplitting = 0BaseDocTemplate.__init__(self, filename, **kw)template = PageTemplate('normal', [Frame(2.5*cm, 2.5*cm, 15*cm, 25*cm, id='F1')])self.addPageTemplates(template)self.chapter = 0self.section = 0def afterFlowable(self, flowable):# 针对段落 添加标签和索引if isinstance(flowable, Paragraph):text = flowable.getPlainText()style = flowable.style.nameif style == 'Title':self.chapter += 1# # 书签# self.canv.bookmarkPage(f"chapter{self.chapter}")# # 大纲# self.canv.addOutlineEntry(f"Chapter {self.chapter}", f"chapter{self.chapter}", level=0)# 书签 参数为索引(个人理解)self.canv.bookmarkPage(f"chapter{self.chapter}")# self.canv.bookmarkPage(key=)# 目录 参数为 标题、索引、层级self.canv.addOutlineEntry(text, f"chapter{self.chapter}", level=0)# self.canv.addOutlineEntry(title=, key=, level=)elif style == 'Heading1':self.section += 1self.canv.bookmarkPage(f"section{self.section}")self.canv.addOutlineEntry(f"Section {self.section}", f"section{self.section}", level=1)def main(filename):# pdfmetrics.registerFont(TTFont('微软雅黑', 'msyh.ttf'))pdfmetrics.registerFont(TTFont('simsun', "simsun.ttc"))ts = ParagraphStyle(name = 'Title',fontName = 'simsun',fontSize = 22,leading = 16,alignment = 1,spaceAfter = 20)h1 = ParagraphStyle(name = 'Heading1',fontSize = 14,leading = 16)story = []story.append(Paragraph('继承BaseDocTemplate', ts))story.append(Paragraph('Section 1', h1))story.append(Paragraph('Text in Section 1.1'))# 分页story.append(PageBreak())story.append(Paragraph('Section 2', h1))story.append(Paragraph('Text in Section 1.2'))# 分页story.append(PageBreak())story.append(Paragraph('Chapter 2', ts))story.append(Paragraph('Section 1', h1))story.append(Paragraph('Text in Section 2.1'))doc = MyDocTemplate(filename)doc.build(story)if __name__ == '__main__':main(filename='example3.pdf')

在这里插入图片描述

在这里插入图片描述--------------------------------------------------------------------------

6. SimpleDocTemplate(页眉页脚)

SimpleDocTemplate就是继承BaseDocTemplate的一种简单实现,它覆盖了接口handle_pageBegin,重载了build接口。
它把页面分成两种:首页和后续页,对应回调两个过程onFirstPage=, onLaterPages=,只需要实现这两个回调过程即可。
适用显示页眉和页脚,其它的功能就有限了。
关注点:
SimpleDocTemplate(文档模板)
QrCode(二维码)
drawOn(显示Flowable)

from reportlab.platypus import SimpleDocTemplate, Paragraph
from reportlab.platypus import PageBreak
from reportlab.lib.styles import ParagraphStyle
from reportlab.lib.colors import Color
from reportlab.lib.pagesizes import A4
from reportlab.lib.units import mm
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.graphics.barcode import qr#首页
def myFirstPage(canvas, doc):canvas.saveState()canvas.setFillColorRGB(0, 0, 0)canvas.setFont('simsun',12)str="(内部资料)"canvas.drawCentredString(doc.width/2, 25*mm, str)myLaterPages(canvas, doc)canvas.restoreState()#页眉页脚
def myLaterPages(canvas, doc):canvas.saveState()canvas.setStrokeColorRGB(0.8, 0.8, 0.8)canvas.line(0, 32, doc.width, 32)canvas.line(0, A4[1]-45, doc.width, A4[1]-45)canvas.setFillColorRGB(0, 0, 0)canvas.setFont('simsun',10)str=f"Page {doc.page}"canvas.drawCentredString(doc.width/2, 5*mm, str)canvas.setFillColorRGB(1, 0, 0)canvas.drawCentredString(doc.width/2, A4[1]-9*mm, "XX有限公司版权所有")qr_code = qr.QrCode('https://www.cnblogs.com/windfic', width=45, height=45)canvas.setFillColorRGB(0, 0, 0)qr_code.drawOn(canvas, 0, A4[1]-45)canvas.restoreState()def main(filename):# pdfmetrics.registerFont(TTFont('微软雅黑', 'msyh.ttf'))pdfmetrics.registerFont(TTFont('simsun', "simsun.ttc"))doc = SimpleDocTemplate(filename, pagesize=A4, leftMargin=10, rightMargin=10)title = ParagraphStyle(name = 'Title',fontName = 'simsun',fontSize = 22,leading = 16,alignment = 1,spaceAfter = 20)contents = []contents.append(Paragraph('使用SimpleDocTemplate', title))contents.append(Paragraph('Hello'))contents.append(PageBreak())contents.append(Paragraph('World'))contents.append(PageBreak())contents.append(Paragraph('World2'))doc.build(contents, onFirstPage=myFirstPage, onLaterPages=myLaterPages)if __name__ == '__main__':main(filename='example4.pdf')
---------------------------------------------------------------------------------------------------------------

7. SimpleDocTemplate(继承 Canvas 页码)

控制Canvas的另一种方法是继承Canvas。
与继承文档模板(DocTemplate)类似,不过网上能找到的例子也就是显示页码,不是很实用。

from reportlab.platypus import SimpleDocTemplate, Image, Paragraph, PageBreak
from reportlab.pdfgen import canvas
from reportlab.lib.units import mm
from reportlab.lib.colors import Color
from reportlab.lib.pagesizes import A4
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.lib.styles import ParagraphStyleclass NumberedCanvas(canvas.Canvas):def __init__(self, *args, **kwargs):canvas.Canvas.__init__(self, *args, **kwargs)self._saved_page_states = []def showPage(self):self._saved_page_states.append(dict(self.__dict__))self._startPage()def save(self):"""add page info to each page (page x of y)"""num_pages = len(self._saved_page_states)for state in self._saved_page_states:self.__dict__.update(state)self.draw_page_number(num_pages)canvas.Canvas.showPage(self)canvas.Canvas.save(self)def draw_page_number(self, page_count):self.setFont("Helvetica", 9)self.setStrokeColor(Color(0, 0, 0, alpha=0.5))self.line(10*mm, 15*mm, A4[0] - 10*mm, 15*mm)self.setFillColor(Color(0, 0, 0, alpha=0.5))self.drawCentredString(A4[0]/2, 10*mm, "Page %d of %d" % (self._pageNumber, page_count))def main(filename):# pdfmetrics.registerFont(TTFont('微软雅黑', 'msyh.ttf'))pdfmetrics.registerFont(TTFont('simsun', "simsun.ttc"))title = ParagraphStyle(name = 'Title',fontName = 'simsun',fontSize = 22,leading = 16,alignment = 1,spaceAfter = 20)image = Image("image.jpg")image.drawWidth = 160# image.drawHeight = 160*(image.imageHeight/image.imageWidth)# image.drawHeight = 160*(image.imageWidth/image.imageHeight)image.drawHeight = 160elements = [Paragraph('继承Canvas', title),Paragraph("Hello"),image,PageBreak(),Paragraph("world"),PageBreak(),image,]doc = SimpleDocTemplate(filename)doc.build(elements, canvasmaker=NumberedCanvas)if __name__ == "__main__":main(filename='example5.pdf')
---------------------------------------------------------------------------------------------------------------

8. 直接使用 Canvas(复杂场景)

当PDF内容非常复杂,难以用以上的方法实现,可以直接使用Canvas创建PDF
直接使用Canvas类,可以精确输出,但需要自己排版,而且它的坐标原点在左下角
其中也可以放置Flowable,需要排版的Flowable,如Table等,调用warp函数即可自动排版。
如果是内容已经排版的格式转换程序,非常推荐使用这种方式。

from reportlab.pdfgen import canvas
from reportlab.platypus import Image, Table
from reportlab.lib.pagesizes import A4
from reportlab.lib.units import mm
from reportlab.lib.colors import Color
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.lib import  colors
from reportlab.graphics.shapes import Drawing
from reportlab.graphics.charts.barcharts import VerticalBarChart
from reportlab.graphics.charts.legends import Legend
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.platypus import Paragraph
from reportlab.graphics.barcode import qrdef draw_bar(bar_data: list, ax: list, items: list):drawing = Drawing(500, 200)bc = VerticalBarChart()bc.x = 45           # 整个图表的x坐标bc.y = 45           # 整个图表的y坐标bc.height = 150     # 图表的高度bc.width = 350      # 图表的宽度bc.data = bar_databc.strokeColor = colors.black       # 顶部和右边轴线的颜色bc.valueAxis.valueMin = 0           # 设置y坐标的最小值bc.valueAxis.valueMax = 20          # 设置y坐标的最大值bc.valueAxis.valueStep = 5          # 设置y坐标的步长bc.categoryAxis.labels.dx = 2bc.categoryAxis.labels.dy = -8bc.categoryAxis.labels.angle = 20bc.categoryAxis.labels.fontName = 'simsun'bc.categoryAxis.categoryNames = ax# 图示leg = Legend()leg.fontName = 'simsun'leg.alignment = 'right'leg.boxAnchor = 'ne'leg.x = 475         # 图例的x坐标leg.y = 140leg.dxTextSpace = 10leg.columnMaximum = 3leg.colorNamePairs = itemsdrawing.add(leg)drawing.add(bc)return drawingdef draw_table(*args):# col_width = 120col_width = (A4[0]-100)/3style = [('FONTNAME', (0, 0), (-1, -1), 'simsun'),       # 字体('FONTSIZE', (0, 0), (-1, 0), 12),              # 第一行的字体大小('FONTSIZE', (0, 1), (-1, -1), 10),             # 第二行到最后一行的字体大小('BACKGROUND', (0, 0), (-1, 0), '#d5dae6'),     # 设置第一行背景颜色('ALIGN', (0, 0), (-1, -1), 'CENTER'),          # 第一行水平居中('ALIGN', (0, 1), (-1, -1), 'LEFT'),            # 第二行到最后一行左右左对齐('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),         # 所有表格上下居中对齐# ('TEXTCOLOR', (0, 0), (-1, -1), colors.darkslategray),  # 设置表格内文字颜色('TEXTCOLOR', (0, 0), (-1, -1), Color(0, 255, 10, 0.7)),  # 设置表格内文字颜色('GRID', (0, 0), (-1, -1), 0.5, colors.grey),   # 设置表格框线为grey色,线宽为0.5('SPAN', (0, 1), (2, 1)),                       # 合并第二行一二三列]table = Table(args, colWidths=col_width, style=style)return tabledef draw_page_number(c, page, count):c.setFillColorRGB(1, 0, 0)      # 红色c.setFont("simsun", 9)c.drawCentredString(A4[0]/2, A4[1]-9*mm, "XX有限公司版权所有")# c.drawCentredString(A4[0]/2, A4[1]-1*mm, "XX有限公司版权所有")qr_code = qr.QrCode('https://www.cnblogs.com/windfic', width=45, height=45)# c.setFillColorRGB(0, 0, 0)c.setFillColorRGB(0, 1, 0)      # 绿色qr_code.drawOn(c, 0, A4[1]-45)# 线段 起点(x,y)和终点(x,y)# c.line(10*mm, A4[1]-45, A4[0], A4[1]-45)c.line(10*mm, A4[1]-45, A4[0] - 10*mm, A4[1]-45)    # 上横线c.setFont("simsun", 9)c.setStrokeColor(Color(0, 0, 0, alpha=0.5))         # 下横线 白色 透明度0.5c.line(10*mm, 15*mm, A4[0] - 10*mm, 15*mm)c.setFillColor(Color(0, 0, 0, alpha=0.5))           # 黑色 页码c.drawCentredString(A4[0]/2, 10*mm, "Page %d of %d" % (page, count))def main(filename):# pdfmetrics.registerFont(TTFont('微软雅黑', 'msyh.ttf'))pdfmetrics.registerFont(TTFont('simsun', "simsun.ttc"))c = canvas.Canvas(filename)#### 标题页c.bookmarkPage("title")c.addOutlineEntry("my book", "title", level=0)#### 第一页c.setFont("simsun", 16)c.setFillColor(Color(0, 0, 1, alpha=0.9))c.drawString(320, A4[1] - 95, "超级马里奥兄弟")c.setFont("simsun", 12)c.setFillColor(Color(0, 0, 0, alpha=0.7))c.drawString(320, A4[1] - 125, "SUPER MARIO BROS.")c.drawString(320, A4[1] - 195, "1985年9月13日发售")img = Image("./image.jpg")img.drawWidth = 160# img.drawHeight = 160*(img.imageHeight/img.imageWidth)# img.drawHeight = int(160*(img.imageHeight/img.imageWidth))img.drawHeight = 160# 不能打印,图片被拉伸(为什么?)# print("image", img.imageHeight, img.imageWidth, (img.imageHeight/img.imageWidth), 160*(img.imageHeight/img.imageWidth), img.drawHeight)img.drawOn(c, 150, A4[1]-210)# img.drawOn(c, 160, A4[1]-200)data = [('经典游戏', '发布年代', '发行商'),('TOP100',),('超级马里奥兄弟', '1985年', '任天堂'),('坦克大战', '1985年', '南梦宫'),('魂斗罗', '1987年', '科乐美'),('松鼠大战', '1990年', '卡普空'),]t = draw_table(*data)# t.wrap(800, 600)t.wrap(2000, 600)t.drawOn(c, 50, A4[1] - 400)styleSheet = getSampleStyleSheet()style = styleSheet['BodyText']style.fontName = "simsun"p=Paragraph(' 《超级马里奥兄弟》于1985年9月13日发售,这是一款任天堂针对FC主机全力度身订造的游戏,被称为TV游戏奠基之作。这个游戏被赞誉为电子游戏的原始范本,确立了角色、游戏目的、流程分布、操作性、隐藏要素、BOSS、杂兵等以后通用至今的制作概念。《超级马里奥兄弟》成为游戏史首部真正意义上的超大作游戏,游戏日本本土销量总计681万份,海外累计更是达到了3342万份的天文数字。',style)# 左右margen 各为50p.wrap(A4[0]-100, 100)p.drawOn(c, 50, A4[1] - 280)b_data = [(2, 4, 6, 12, 8, 16), (12, 14, 17, 9, 12, 7)]ax_data = ['任天堂', '南梦宫', '科乐美', '卡普空', '世嘉', 'SNK']leg_items = [(colors.red, '街机'), (colors.green, '家用机')]d = draw_bar(b_data, ax_data, leg_items)d.drawOn(c, 50, A4[1] - 620)draw_page_number(c, 1, 2)c.bookmarkPage("section1")c.addOutlineEntry("first section", "section1", level=1)c.showPage()    # 手动开始新的一页#### 第二页c.drawString(50, A4[1] - 70, ("This is Paragraph number. ") * 5)draw_page_number(c, 2, 2)c.bookmarkPage("section2")c.addOutlineEntry("second section", "section2", level=1)c.showPage()    # 手动开始新的一页# c.showOutline()c.save()if __name__ == "__main__":main(filename='example6.pdf')

在这里插入图片描述
效果很好,问题也很严重。第二页不会自动分页!!!
在这里插入图片描述

相关文章:

  • vue里provide作用:将一组全局方法注入到 Vue 应用的所有子组件中
  • 【正点原子STM32MP257连载】第四章 ATK-DLMP257B功能测试——USB测试 #USB HOST #USB 鼠标
  • 京东硬核挑战潜规则,外卖算法要变天?
  • 阶段性使用总结-通义灵码
  • 协程从原理到最新的c++协程特性
  • 从服务器多线程批量下载文件到本地
  • 4.14【Q】pc homework3
  • 有序二叉树各种操作实现(数据结构C语言多文件编写)
  • 基础知识:Dify 错误排查
  • 基础学习(4): Batch Norm / Layer Norm / Instance Norm / Group Norm
  • ReactNative中处理安全区域问题
  • 深入解析 OrdinalEncoder 与 OneHotEncoder:核心区别与实战应用
  • Linux——信号量
  • linux 内核 ida机制分析
  • 【SpringMVC】深入解析自定义拦截器、注册配置拦截器、拦截路径方法及常见拦截路径、排除拦截路径、拦截器的执行流程
  • 视觉SLAM和激光SLAM建图输出的文件类型
  • 域控制器升级的先决条件验证失败,证书服务器已安装
  • 基于大模型的反流食管炎手术全流程风险预测与治疗方案研究报告
  • 【钱包】Tron签名总结
  • c# 数据结构 链表篇 有关双向链表的一切
  • 魔都眼|上海半马鸣枪:白金标运动员、“箱根之子”齐参赛
  • 人民日报和音:书写周边命运共同体建设新篇章
  • 上海古籍书店重新开卷,在这里淘旧书获新知
  • 碎片化时代如何阅读?巴金图书馆推出世界读书日系列活动
  • 云南省交通发展投资有限责任公司原党委书记、董事长陈以东接受审查调查
  • 寺庙餐饮,被年轻人追捧成新顶流