PDF 报告生成器:用 reportlab 和 pdfrw 生成自定义 PDF 报告

如果您的工作涉及生成PDF报告,发票等,则您可能已经考虑过使用Python自动化。Python有一些很不错的第三方库用于处理PDF文件,使您可以从脚本中读取和写入PDF。同样,您也可以将这些库作为简单GUI工具的基础,从而为您提供一种在桌面上操作自动填充或编辑PDF报告的简便方法。

在本教程中,我们将使用两个库来创建自定义PDF报告填充器。数据将使用Qt表单收集:只需编辑字段,按“生成”按钮即可在文件夹中获取填写的表单。我们将在这里使用的两个库是:

  • reportlab,可让您使用文本和图片类原件创建PDF

  • pdfrw,一个用于从现有PDF读取和提取页面的库

尽管我们可以使用reportlab来绘制整个PDF,但是使用外部工具设计模板然后在其上叠加动态内容会更容易。我们可以使用pdfrw来读取模板PDF,提取页面,然后可以使用reportlab在该页面上进行绘制。这样一来,我们就可以将自定义信息(来自我们的应用程序)直接覆盖到现有的PDF模板上,并以新名称保存。

在此示例中,我们通过手动输入字段,但是您可以修改应用程序以从外部CSV文件读取PDF数据并从中生成多个PDF。

PDF 模板

为了进行测试,我使用Google Docs创建了一个自定义的TPS报告模板,并将页面下载为PDF。该页面包含许多要填写的字段。在本教程中,我们将编写一个PyQt表单,用户可以填写该表单,然后将数据写到正确位置的PDF上。

模板为A4格式。将其与脚本保存在同一文件夹中。

如果您想使用其他模板,请随时使用。只需记住,编写表单时需要调整表单字段的位置。

布置表单视图

Qt包含一个QFormLayout布局,该布局简化了生成简单表单布局的过程。它的工作方式类似于网格,但是您可以将元素的行添加在一起,并将字符串自动转换为QLabel对象。我们的框架应用程序,包括与模板表单匹配的完整布局,如下所示。

from PyQt5.QtWidgets import QPushButton, QLineEdit, QApplication, QFormLayout, QWidget, QTextEdit, QSpinBox

class Window(QWidget):

    def __init__(self):
        super().__init__()

        self.name = QLineEdit()
        self.program_type = QLineEdit()
        self.product_code = QLineEdit()
        self.customer = QLineEdit()
        self.vendor = QLineEdit()
        self.n_errors = QSpinBox()
        self.n_errors.setRange(0, 1000)
        self.comments = QTextEdit()

        self.generate_btn = QPushButton("Generate PDF")

        layout = QFormLayout()
        layout.addRow("Name", self.name)
        layout.addRow("Program Type", self.program_type)
        layout.addRow("Product Code", self.product_code)
        layout.addRow("Customer", self.customer)
        layout.addRow("Vendor", self.vendor)
        layout.addRow("No. of Errors", self.n_errors)

        layout.addRow("Comments", self.comments)
        layout.addRow(self.generate_btn)

        self.setLayout(layout)


app = QApplication([])
w = Window()
w.show()
app.exec()

在编写用于替换/自动化纸质表格的工具时,尝试模仿纸质表格的布局通常是个好主意,这样就很熟悉了。

上面的代码运行后在窗口中提供以下布局。您已经可以在字段中输入内容,但是按下按钮尚无任何作用 —— 我们尚未编写代码来生成PDF或将其连接到按钮。

生成 PDF 文本

为了将基本模板生成PDF,我们将结合reportlabPdfReader两个库。流程如下:

  • 使用PdfReader读入template.pdf文件,并仅提取第一页。

  • 创建一个reportlabCanvas对象

  • 使用pdfrw.toreportlab.makerl生成画布对象,然后使用canvas.doForm()将其添加到Canvas中。

  • 在画布上绘制自定义位

  • 将PDF保存到文件

代码如下所示,不需要Qt,您可以保存到文件并按原样运行。运行后,生成的PDF将作为result.pdf保存在同一文件夹中。

from reportlab.pdfgen.canvas import Canvas
from pdfrw import PdfReader
from pdfrw.buildxobj import pagexobj
from pdfrw.toreportlab import makerl

outfile = "result.pdf"

template = PdfReader("template.pdf", decompress=False).pages[0]
template_obj = pagexobj(template)

canvas = Canvas(outfile)

xobj_name = makerl(canvas, template_obj)
canvas.doForm(xobj_name)

ystart = 443

# Prepared by
canvas.drawString(170, ystart, "My name here")

canvas.save()

由于生成PDF的过程正在进行IO操作,因此可能会花费一些时间(例如,如果我们从网络驱动器中加载文件)。因此,最好在单独的线程中进行处理。接下来,我们将定义这个自定义线程运行器。

在单独的线程中运行生成器

由于每个生成器都是一个孤立的工作,因此使用Qt的QRunner框架来处理该流程是很有意义的,这也使以后为每个作业添加可自定义的模板变得很简单。我们在使用多线程教程中可以看到相同的方法,在该方法中,我们使用QRunner的子类来保存我们的自定义运行代码,并在单独的QObject子类上实现特定于运行器的信号。

from PyQt5.QtWidgets import QPushButton, QLineEdit, QApplication, QFormLayout, QWidget, QTextEdit, QMessageBox, QSpinBox
from PyQt5.QtCore import QObject, QRunnable, QThreadPool, pyqtSignal, pyqtSlot

from reportlab.pdfgen.canvas import Canvas

from pdfrw import PdfReader
from pdfrw.buildxobj import pagexobj
from pdfrw.toreportlab import makerl


class WorkerSignals(QObject):
    """
    Defines the signals available from a running worker thread.
    """
    error = pyqtSigna
  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值