使用Python和ReportLab生成PDF报告的基础类

  • 代码介绍
  • 项目目录
  • 项目环境
  • 完整代码
  • 运行效果


代码介绍

这个Python代码使用 ReportLab 和 PyPDF4 库来生成 PDF 文件。代码创建一个 PDFGenerator 类,用于添加文本、图片和表格到 PDF 文件中。

初始化 PDFGenerator 对象时,它会注册“STXINGKA”字体,并创建一个新的 PDF writer 对象、内存中的 PDF 文件对象和画布对象以在 PDF 上绘制。然后,它初始化当前坐标(x,y),以便添加文本、图片和表格时知道要将它们放在哪里。

方法_add_text用于添加文本到 PDF 文件中。它将文本分割成行并逐行添加。如果文本的高度超过页面的高度,则它会在新页面上开始一个新的文本块。

方法_add_image用于将图像添加到 PDF 文件中。如果图像的高度超过页面的高度,则它会在新页面上开始一个新的图像块。

方法_add_table用于将表格添加到 PDF 文件中。它需要一个包含表格数据的列表和可选的列宽列表和行高。如果未提供列宽,则列将具有相等的宽度。它计算表格的总宽度和高度,并在 PDF 中绘制一个带边框的矩形。然后,它绘制表格中的单元格并更新当前坐标。

方法save_pdf用于将 PDF 文件保存到磁盘上。它将画布保存到 PDF 文件并使用 PyPDF4 的 PdfFileReader 类从输出文件中读取 PDF。然后,它将报告页面添加到 PDF writer 对象中,并将更新后的 PDF 保存到文件中。

在主函数中,它创建一个 PDFGenerator 对象,然后添加文本、图片和表格。最后,它保存文件。

项目目录

python 解读pdf财报 python制作pdf报表_开发语言


注:STXINGKA.TTF:字体文件是在系统的字体目录复制的,可自行更改为其他字体,使用字体的前提是你的电脑安装了该字体。

python 解读pdf财报 python制作pdf报表_pdf_02

项目环境

# 这是我自己使用的环境
Python 3.10
PyPDF4==1.27.0
reportlab==3.6.12

完整代码

from io import BytesIO
from reportlab.lib.pagesizes import A4
from reportlab.pdfgen import canvas
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from PyPDF4 import PdfFileWriter, PdfFileReader


class PDFGenerator:
    def __init__(self):
        # 注册宋体字体
        pdfmetrics.registerFont(TTFont('STXINGKA', 'STXINGKA.TTF'))
        pdfmetrics.registerFontFamily('STXINGKA', normal='song', italic=None, boldItalic=None)

        # 创建一个新的PDF writer对象
        self.pdf_writer = PdfFileWriter()

        # 创建一个新的内存中的PDF文件对象
        self.pdf_output = BytesIO()

        # 创建一个新的画布对象以在PDF上绘制
        self.pdf_canvas = canvas.Canvas(self.pdf_output, pagesize=A4)

        # 初始化当前坐标
        self.x = 50
        self.y = 750

    def _add_text(self, text):
        # 设置字体为宋体
        self.pdf_canvas.setFont("STXINGKA", 14)

        # 计算文本高度并检查是否适合页面
        text_width = self.pdf_canvas.stringWidth(text)
        text_height = 14
        if self.y - text_height < 50:
            self.pdf_canvas.showPage()
            self.y = 750

        # 将文本添加到页面并更新当前坐标
        self.pdf_canvas.drawString(self.x, self.y, text)
        self.y -= text_height

    def add_text(self, text):
        # 将文本分割成行并逐行添加
        for line in text.split('\n'):
            self._add_text(line)

    def _add_image(self, image_path):
        # 检查图片是否适合页面
        img_width, img_height = 400, 300
        if self.y - img_height < 50:
            self.pdf_canvas.showPage()
            self.y = 750

        # 在页面上绘制图片并更新当前坐标
        self.pdf_canvas.drawImage(image_path, self.x, self.y - img_height, width=img_width, height=img_height)
        self.y -= img_height

    def add_image(self, image_path):
        self._add_image(image_path)

    def save_pdf(self, filename):
        # 将画布保存到PDF文件
        self.pdf_canvas.save()

        # 从输出文件中读取PDF
        pdf_reader = PdfFileReader(self.pdf_output)

        # 将报告页面添加到PDF writer对象中
        for page in pdf_reader.pages:
            self.pdf_writer.addPage(page)

        # 将更新后的PDF保存到文件中
        with open(filename, "wb") as output_file:
            self.pdf_writer.write(output_file)

    def add_table(self, data, col_widths=None, row_height=20):
        """
        添加一个表格到PDF文件中。

        :param data: 一个列表的列表,其中每个列表表示表格中的一行数据。
        :param col_widths: 表格的列宽列表。如果未提供,则列将具有相等的宽度。
        :param row_height: 表格中每行的高度。
        """
        # 如果未提供列宽,则将其设置为相等的宽度
        if not col_widths:
            num_cols = max(len(row) for row in data)
            col_widths = [A4[0] / num_cols] * num_cols

        # 计算表格总宽度
        table_width = sum(col_widths)

        # 根据表格的行数计算表格的高度
        table_height = len(data) * row_height

        # 计算表格开始绘制的 x 和 y 坐标
        x_start = (A4[0] - table_width) / 2
        y_start = self.y - table_height

        # 绘制表格边框
        self.pdf_canvas.rect(x_start, y_start, table_width, table_height)

        # 设置表格单元格的字体和字体大小
        # self.pdf_canvas.setFont(self.font_name, self.font_size)

        # 开始绘制表格单元格
        data.reverse()
        for i, row in enumerate(data):
            y = y_start + (i * row_height)
            x = x_start
            for j, cell in enumerate(row):
                # 绘制单元格内容
                self.pdf_canvas.drawString(x, y, str(cell))
                # 移动到下一个单元格
                x += col_widths[j]

        # 更新y
        self.y -= table_height


if __name__ == '__main__':
    # 创建PDFGenerator对象
    pdf_generator = PDFGenerator()

    # 添加文本
    pdf_generator.add_text("我的报告")
    pdf_generator.add_text("你好世界")
    pdf_generator.add_text("这是我的第一个PDF报告")

    # 添加图片
    pdf_generator.add_image("sample_image.png")

    # 添加表格
    data = [["姓名", "年龄", "性别"], ["Tom", "18", "男"], ["Lucy", "20", "女"]]
    pdf_generator.add_table(data)

    # 保存文件
    pdf_generator.save_pdf("my_report.pdf")

运行效果

python 解读pdf财报 python制作pdf报表_pdf_03