python生成PDF报告

2023-09-18 17:27:43

前言

最近接到了一个需求-将项目下的样本信息汇总并以PDF的形式展示出来,第一次接到这种PDF的操作的功能,还是有点慌的,还好找到了reportlab这个包,可以定制化向PDF写内容!

让我们由简入深进行讲解

一、reportlab是什么?

reportlab是久经考验的,超强大的开源引擎,用于创建复杂的,数据驱动的 PDF 文档和自定义矢量图形。它是免费的,开源的,并且是用 Python 编写的。

二、canvas绘制图形文字元素

  • 页面绘制是以坐标系为基准,左下角坐标为(0, 0)

2.1 样式预览

在这里插入图片描述

2.2、代码

from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import A4
from reportlab.pdfbase import pdfmetrics, ttfonts
from reportlab.lib.colors import red, blue

# pagesize可以指定创建的画布尺寸
pdfObj = canvas.Canvas("test.pdf", pagesize=A4)  # 也可以自定义尺寸,如pdfObj.setPageSize((1200,800))


#################################START字符串绘制#################################
# 绘制字符串左对齐,以给定坐标为起始点
pdfObj.drawString(300, 750, "Welcome! Ladies and gentlemen 0")
# 绘制字符串居中,以给定坐标系为字符串中心
pdfObj.drawCentredString(300, 700, "Welcome! Ladies and gentlemen 1")
# 绘制字符串右对齐,以给定坐标系为字符串结束点
pdfObj.drawRightString(300, 650, "Welcome! Ladies and gentlemen 2")
# 绘制<<中文>>字母,需要注册字体并配置字号,注simsun.ttc文件的存储位置可以是绝对或相对路径
pdfmetrics.registerFont(ttfonts.TTFont("宋体", "simsun.ttc"))
# 配置字号
pdfObj.setFont("宋体", 30)
pdfObj.drawString(300, 600, "大学生开学季")
#################################END字符串绘制#################################

#################################START图片的绘制#################################
# 绘制图片
pdfObj.drawImage(r"D:\test\baidu.png", 300, 400, 190, 72)
#################################END图片的绘制#################################

#################################START图形的绘制#################################
# 绘制中横线,参数为起点,终点坐标
pdfObj.line(50, 350, 300, 350)
pdfObj.setLineWidth(1)  # 中横线厚度
# 绘制长方形
pdfObj.setFillColor(red)  # 颜色对象
pdfObj.rect(300, 300, 190, 20, stroke=0, fill=1)  # 长方形区域属性
# 附加属性
pdfObj.setFillColor(blue)  # 颜色对象
# pdfObj.setFillGray(0.75)  # 灰度配置,用的少,先关掉了
pdfObj.setFillAlpha(0.3)  # 透明度配置
pdfObj.rect(300, 650, 200, 50, stroke=0, fill=1)  # 长方形区域属性
#################################END图形的绘制#################################

#################################START继承的绘制#################################
# 将form内包含的绘制保存,以便再下一页继续应用。可用在页眉、页脚、背景色等处
pdfObj.beginForm("new")  # 创建继承体
pdfObj.line(50, 200, 300, 200)
pdfObj.setLineWidth(1)  # 中横线厚度
pdfObj.endForm()  # 结束并保存继承体

for i in range(2):
    pdfObj.doForm("new")  # 应用继承体
    pdfObj.showPage()  # 结束本页翻转下一页
#################################END继承的绘制#################################
# 保存生效
pdfObj.save()

三、页面布局platypus应用

在第一章中,所有的元素都基于坐标进行绘制,每次的排版都需要计算,应用起来有点复杂及繁琐,所以为了减少这种重复劳动,引入模板和样式platypus(Page Layout and Typography Using Scripts),它致力于把文档的样式和内容分开,段落、表格都直接套用相应的格式,页面也可以套用页面模版。
  • 明晰platypus几大层面划分,包含关系由小到大。页面元素(flowables)、页面框架(Frame)、页面模板(PageTemplate)、文档模板(DocTemplate)
  • 页面元素(flowables),如段落、表格、空白、分页符、图片等

3.1、段落Paragraph

3.1.1、样式预览

在这里插入图片描述

3.1.2、代码

from reportlab.lib.styles import getSampleStyleSheet
from reportlab.platypus import SimpleDocTemplate
from reportlab.lib.pagesizes import A4
from reportlab.pdfbase import pdfmetrics, ttfonts
from reportlab.platypus import Paragraph

# 文本数据
txt1 = "尊敬的家长,亲爱的同学们:"
txt2 = "在硕果累累的金秋时节,伴着纤云翩翩,伴着枫红菊香,你们怀揣着无限的憧憬,来到了xx学校。你们的到来,犹如徐徐清风,让我们的校园更为清新宜人,璀璨多姿。xx学院全体师生期盼着你们的到来,我们用比较诚挚的心意衷心的祝福你们,欢迎你们!"
txt3 = "当你跨进这所美丽的校园,你就成了我们大伙庭的一员,在这个大伙庭里,充满着真情,充满着友爱,充满着对一切美好事物的追求。在这个大伙庭里,你将在这优美的校园环境中陶冶你的情操,情发挥你的特长,丰富你的学识,攀登科学的高峰,实现你的梦想。"
txt4 = "新的.面孔、新的价值观念和标准,新的生活方式,需要你用理性的目光和胆识、用辛勤的劳动和汗水,去实现你走向人生成功与辉煌的又一起点。"
txt5 = "谢谢大家!"

# 创建样式对象
styleObj = getSampleStyleSheet()
# <<中文>>需要注册字体并配置字号,注simsun.ttc文件的存储位置可以是绝对或相对路径
pdfmetrics.registerFont(ttfonts.TTFont("宋体", "simsun.ttc"))

# 配置段落标题与正文属性,方式一
styleObj["Title"].fontName, styleObj["Title"].fontSize = "宋体", 15
styleObj["Title"].paragraphObjpaceAfter, styleObj["Normal"].paragraphObjpaceBefore = 30, 10
styleObj["Normal"].fontName, styleObj["Normal"].fontSize = "宋体", 10
styleObj["Normal"].leading = 30
styleObj["Normal"].firparagraphObjtLineIndent = 40

# # 也可以用下面的方式配置段落属性,方式二
# # 中文写入不识别,未查明怎么不生效
# from reportlab.lib.styles import ParagraphStyle
# paragraphStyle = ParagraphStyle(name="A1",fontName="宋体",fontSize=10, firstLineIndent=0)
# styleObj.add(paragraphStyle)

# 创建段落对象
paragraphObj1 = Paragraph(txt1, styleObj["Title"])
paragraphObj2 = Paragraph(txt2, styleObj["Normal"])
paragraphObj3 = Paragraph(txt3, styleObj["Normal"])
paragraphObj4 = Paragraph(txt4, styleObj["Normal"])
paragraphObj5 = Paragraph(txt5, styleObj["Normal"])

# 此处不再使用canvas创建pdf对象,改为文档模板doctemplate模块的SimpleDocTemplate类
doc = SimpleDocTemplate(r"test1.pdf", pagesize=A4)
story_text = [paragraphObj1, paragraphObj2, paragraphObj3, paragraphObj4, paragraphObj5]
doc.build(story_text)

3.2、表格Table

3.2.1、样式预览

在这里插入图片描述

3.2.2、代码

from reportlab.lib.styles import getSampleStyleSheet
from reportlab.platypus import Table
from reportlab.lib.units import inch, cm, pica
from reportlab.platypus import TableStyle
from reportlab.lib import colors
from reportlab.pdfbase import pdfmetrics, ttfonts

pdfmetrics.registerFont(ttfonts.TTFont("宋体", "simsun.ttc"))
# table数据,二维数组
data = [
    ["姓名", "语文", "数学", "英语", "体育"],
    ["张三", 91, 97, 79, "良好"],
    ["李四", 99, 87, 73, "优秀"],
    ["王五", 86, 89, 83, "良好"],
    ["赵六", 95, 88, 86, "良好"],
    # 当需要将数据在一个单元格分两列的话,可以用下面的语法
    ["孙七", 79, 95, 98, "良"+"\n"+"好"],
]
# 配置行高(第一、第二、第三...行高)、列宽(第一、第二、第三...列宽),如有需要,也可以配置单位,如5 * [3 * cm]
col_widths, row_heights = [80, 100, 100, 100, 100], [60, 50, 50, 50, 50, 50]
# 表格行列的表达形式为,同excel,左上方第一个单元格为(0, 0), 右下角单元格为(-1, -1),围起来就是整个表格
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"),  #  垂直居中
    ("INNERGRID", (0, 0), (-1, -1), 0.25, colors.black),  # 单元格分割线
    ("BOX", (0, 0), (-1, -1), 0.25, colors.black),  # 边框
    ("BACKGROUND", (0, 0), (-1, -1), colors.lightgrey),  # 背景色
    ("TEXTCOLOR", (0, 0), (-1, 0), colors.red),  # 区域字体颜色
    ("LINEABOVE", (0, 1), (-1, 1), 1, colors.orange),  # 横线线段
    ('LINEBEFORE', (1, 0), (1, -1), 1, colors.blue)  # 竖线线段
    # ("GRID", (0, 0), (-1, -1), 0.5, colors.black),  #
    # ("SPAN", (0, 3), (-1, 3)),  # 合并单元格
])
table = Table(data, colWidths=col_widths, rowHeights=row_heights, style=table_style)
# 编辑表格标题及样式
tabletitle = """<para alignment=center fontName="宋体" fontSize=20 spaceAfter=30>表1: 学生成绩表</para>"""
# 可以配置上下左右页边距,topMargin=1*cm,bottomMargin=1*cm,leftMargin=1*cm,rightMargin=1*cm
doc = SimpleDocTemplate(r"test2.pdf", pagesize=A4)
story_table = [Paragraph(tabletitle, getSampleStyleSheet()["Normal"]), table]
doc.build(story_table)

3.2、图表

项目没用到,搁置先不写了

3.4、空白

3.5、图片

3.6、升华Frame

四、结束!

更多推荐

卷积神经网络实现咖啡豆分类 - P7

🍨本文为🔗365天深度学习训练营中的学习记录博客🍖原作者:K同学啊|接辅导、项目定制🚀文章来源:K同学的学习圈子目录环境步骤环境设置包引用全局设备对象数据准备查看图像的信息制作数据集模型设计手动搭建的vgg16网络精简后的咖啡豆识别网络模型训练编写训练函数编写测试函数开始训练展示训练过程模型效果展示总结与心得体

四、二叉树-上(Binary tree)

文章目录一、算法核心思想二、算法模型(一)回溯1.[104.二叉树的最大深度](https://leetcode.cn/problems/maximum-depth-of-binary-tree/)(1)思路(2)代码(3)复杂度分析2.[144.二叉树的前序遍历](https://leetcode.cn/proble

基础组件(线程池、内存池、异步请求池、Mysql连接池)

文章目录1、概述2、线程池2、异步请求池3、内存池1、概述池化技术,减少了资源创建次数,提高了程序响应性能,特别是在高并发场景下,当程序7*24小时运行,创建资源可能会出现耗时较长和失败等问题,池化技术,主要是程序初始化之前创建多个可用连接,集中管理起来,后续直接使用,使用完并归还。2、线程池线程池主要解决问题:1、解

碳当量及相关指数

声明本文是学习GB-T713.1-2023承压设备用钢板和钢带第1部分:一般要求.而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们1范围本文件规定了承压设备用钢板和钢带的牌号表示方法、订货内容、尺寸、外形、重量、技术要求、检验规则、试验方法、包装、标志及质量证明书。本文件适用于锅炉、压力容器、压力管

ardupilot开发 --- 避障篇

避障的类型空中防碰撞ADSB,主要是防止与其他飞行器的碰撞;避障,防止与天花板地板障碍物的碰撞;实现避障必要的传感器ADSBreceiversRangefindersorProximitySensorsorRealsenseDepthCameraADSBhttps://ardupilot.org/copter/docs

基于微信小程序的语言课学习系统的设计与实现(源码+lw+部署文档+讲解等)

前言💗博主介绍:✌全网粉丝10W+,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战✌💗👇🏻精彩专栏推荐订阅👇🏻2023-2024年最值得选的微信小程序毕业设计选题大全:100个热门选

PT@古典概型@等概率模型

文章目录abstract等可能概型(古典概型)🎈古典型概率公式基本性质导出性质例抽样方式放回抽样不放回抽样mmm次取求不放回和一次性取mmm个球例:取色球和古典概型古典概型经典问题放球问题两人同一天生日问题超几何分布概型整除取数问题抽签问题取最大号球问题@错位相减分组分配问题古典概型假设条件和实际推断原则其他古典概型

共享WiFi贴项目怎么实施与运营,微火为你提供高效解答!

共享WiFi贴是一项有前景的商业项目,不仅可以满足用户对网络的需求,还可以为创业者带来盈利的机会。那么,我们来看看如何有效地开展共享WiFi贴项目。最重要的是选择合适的位置。共享WiFi贴项目的成功与否很大程度上取决于位置选择。优先选择人流量较大、需求旺盛的地方,如商业区、写字楼、学校、咖啡馆等。通过深入了解目标用户群

LeetCode解法汇总2591. 将钱分给最多的儿童

目录链接:力扣编程题-解法汇总_分享+记录-CSDN博客GitHub同步刷题项目:https://github.com/September26/java-algorithms原题链接:力扣(LeetCode)官网-全球极客挚爱的技术成长平台描述:给你一个整数money,表示你总共有的钱数(单位为美元)和另一个整数chi

工业物联网大数据解决方案:排水设备远程监控和大数据统计系统

一、项目背景给排水系统,作为城市的基础设施建设,是居民生产生活的必要保障。由于给排水系统通常站点零散分布,运维管理涉及的区域广泛,水位、流量、机泵运行等运行参数的测报,目前采取人工测量的,上令下达的方式也相对落后,调度管理工作比较被动,很难做到调度的科学性、及时性。因此采取高科技手段,为给排水设施建立全方位二十四小时的

【lesson8】操作系统的理解和类比

文章目录操作系统是什么?为什么要有操作系统?怎么做?学校的例子(理解管理)银行的例子(类比操作系统)操作系统是什么?操作系统是一款软件,是为了进行软硬件资源管理的软件。为什么要有操作系统?操作系统是为了给用户提供一个良好,安全,简单的运行环境。这就是操作系统的目的。怎么做?上面的两个话题我们在Linux发展史这篇博客中

热文推荐