`Python`的`PDF`操作:`PyPDF2`和`reportlab`的`高级`用法。

Python PDF 操作:PyPDF2 和 reportlab 的高级用法

大家好,今天我们深入探讨 Python 中处理 PDF 文件的两个强大库:PyPDF2 和 reportlab。PyPDF2 主要用于读取、分割、合并和修改现有的 PDF 文件,而 reportlab 则侧重于从头开始创建 PDF 文档。我们将介绍它们的高级用法,包括加密解密、水印添加、复杂布局设计以及动态内容生成。

一、PyPDF2 的高级用法

PyPDF2 是一个纯 Python 库,可以轻松地处理 PDF 文件。它提供了 Reader 和 Writer 对象,分别用于读取和写入 PDF 文件。

1. PDF 加密与解密

PyPDF2 可以对 PDF 文件进行加密和解密,保护敏感信息。

  • 加密 PDF 文件:
import PyPDF2

def encrypt_pdf(input_path, output_path, password):
    """
    加密 PDF 文件。

    Args:
        input_path: 输入 PDF 文件路径。
        output_path: 输出加密后的 PDF 文件路径。
        password: 加密密码。
    """
    with open(input_path, 'rb') as input_file:
        reader = PyPDF2.PdfReader(input_file)
        writer = PyPDF2.PdfWriter()

        for page in reader.pages:
            writer.add_page(page)

        writer.encrypt(password)

        with open(output_path, 'wb') as output_file:
            writer.write(output_file)

# 示例
encrypt_pdf('input.pdf', 'encrypted.pdf', 'secret_password')
  • 解密 PDF 文件:
import PyPDF2

def decrypt_pdf(input_path, output_path, password):
    """
    解密 PDF 文件。

    Args:
        input_path: 输入加密的 PDF 文件路径。
        output_path: 输出解密后的 PDF 文件路径。
        password: 解密密码。
    """
    with open(input_path, 'rb') as input_file:
        reader = PyPDF2.PdfReader(input_file)

        if reader.is_encrypted:
            reader.decrypt(password)

            writer = PyPDF2.PdfWriter()
            for page in reader.pages:
                writer.add_page(page)

            with open(output_path, 'wb') as output_file:
                writer.write(output_file)
        else:
            print("PDF is not encrypted.")

# 示例
decrypt_pdf('encrypted.pdf', 'decrypted.pdf', 'secret_password')

2. 添加水印

在 PDF 文件中添加水印可以保护版权或标识文件。

import PyPDF2

def add_watermark(input_path, watermark_path, output_path):
    """
    向 PDF 文件添加水印。

    Args:
        input_path: 输入 PDF 文件路径。
        watermark_path: 水印 PDF 文件路径。
        output_path: 输出添加水印后的 PDF 文件路径。
    """
    with open(input_path, 'rb') as input_file, open(watermark_path, 'rb') as watermark_file:
        input_reader = PyPDF2.PdfReader(input_file)
        watermark_reader = PyPDF2.PdfReader(watermark_file)
        watermark_page = watermark_reader.pages[0]

        writer = PyPDF2.PdfWriter()

        for page in input_reader.pages:
            page.merge_page(watermark_page)
            writer.add_page(page)

        with open(output_path, 'wb') as output_file:
            writer.write(output_file)

# 示例
add_watermark('input.pdf', 'watermark.pdf', 'watermarked.pdf')

其中 watermark.pdf 应该是一个包含单个页面的 PDF 文件,该页面包含水印内容。

3. 从 PDF 中提取文本

PyPDF2 可以提取 PDF 文件中的文本内容。

import PyPDF2

def extract_text_from_pdf(pdf_path):
    """
    从 PDF 文件中提取文本。

    Args:
        pdf_path: PDF 文件路径。

    Returns:
        提取的文本内容。
    """
    text = ""
    with open(pdf_path, 'rb') as file:
        reader = PyPDF2.PdfReader(file)
        for page in reader.pages:
            text += page.extract_text()
    return text

# 示例
text = extract_text_from_pdf('input.pdf')
print(text)

4. PDF 文件分割

将一个 PDF 文件分割成多个文件。

import PyPDF2

def split_pdf(input_path, output_prefix):
    """
    将 PDF 文件分割成多个文件。

    Args:
        input_path: 输入 PDF 文件路径。
        output_prefix: 输出文件名前缀。
    """
    with open(input_path, 'rb') as input_file:
        reader = PyPDF2.PdfReader(input_file)
        for i, page in enumerate(reader.pages):
            writer = PyPDF2.PdfWriter()
            writer.add_page(page)
            output_path = f"{output_prefix}_{i+1}.pdf"
            with open(output_path, 'wb') as output_file:
                writer.write(output_file)

# 示例
split_pdf('input.pdf', 'split_page')

二、reportlab 的高级用法

reportlab 是一个强大的库,用于从头开始创建复杂的 PDF 文档。它提供了丰富的 API,可以控制文档的布局、字体、颜色和图像。

1. 创建基本 PDF 文档

首先,我们创建一个简单的 PDF 文档。

from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import letter
from reportlab.lib.units import inch

def create_basic_pdf(output_path):
    """
    创建一个基本的 PDF 文档。

    Args:
        output_path: 输出 PDF 文件路径。
    """
    c = canvas.Canvas(output_path, pagesize=letter)
    c.drawString(inch, 10.5 * inch, "Hello, ReportLab!")
    c.save()

# 示例
create_basic_pdf('basic.pdf')

2. 使用 Paragraph 进行文本排版

Paragraph 对象可以处理更复杂的文本排版,例如换行、对齐和样式。

from reportlab.platypus import SimpleDocTemplate, Paragraph
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.lib.units import inch

def create_paragraph_pdf(output_path):
    """
    使用 Paragraph 创建 PDF 文档。

    Args:
        output_path: 输出 PDF 文件路径。
    """
    doc = SimpleDocTemplate(output_path, pagesize='A4')
    styles = getSampleStyleSheet()
    story = []

    text = "This is a long paragraph of text that will be wrapped automatically.  " * 20
    p = Paragraph(text, styles['Normal'])
    story.append(p)

    doc.build(story)

# 示例
create_paragraph_pdf('paragraph.pdf')

3. 使用 Table 创建表格

Table 对象可以创建表格,并控制单元格的样式和内容。

from reportlab.platypus import SimpleDocTemplate, Table, TableStyle
from reportlab.lib import colors

def create_table_pdf(output_path):
    """
    使用 Table 创建 PDF 文档。

    Args:
        output_path: 输出 PDF 文件路径。
    """
    doc = SimpleDocTemplate(output_path, pagesize='A4')
    story = []

    data = [
        ['Header 1', 'Header 2', 'Header 3'],
        ['Row 1, Col 1', 'Row 1, Col 2', 'Row 1, Col 3'],
        ['Row 2, Col 1', 'Row 2, Col 2', 'Row 2, Col 3']
    ]

    table = Table(data)
    table.setStyle(TableStyle([
        ('BACKGROUND', (0, 0), (-1, 0), colors.grey),
        ('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke),
        ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
        ('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),
        ('BOTTOMPADDING', (0, 0), (-1, 0), 12),
        ('BACKGROUND', (0, 1), (-1, -1), colors.beige),
        ('GRID', (0, 0), (-1, -1), 1, colors.black)
    ]))

    story.append(table)
    doc.build(story)

# 示例
create_table_pdf('table.pdf')

4. 使用 Canvas 进行绘图

Canvas 对象允许直接在 PDF 页面上进行绘图,可以创建各种图形和图表。

from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import letter
from reportlab.lib import colors

def create_drawing_pdf(output_path):
    """
    使用 Canvas 进行绘图创建 PDF 文档。

    Args:
        output_path: 输出 PDF 文件路径。
    """
    c = canvas.Canvas(output_path, pagesize=letter)
    c.setFillColor(colors.blue)
    c.rect(100, 100, 200, 100, fill=1) # x, y, width, height
    c.setFillColor(colors.red)
    c.circle(200, 300, 50, fill=1) # x, y, radius
    c.save()

# 示例
create_drawing_pdf('drawing.pdf')

5. 添加图像

将图像添加到 PDF 文件中。

from reportlab.platypus import SimpleDocTemplate, Image
from reportlab.lib.pagesizes import letter

def create_image_pdf(output_path, image_path):
    """
    添加图像到 PDF 文档。

    Args:
        output_path: 输出 PDF 文件路径。
        image_path: 图像文件路径。
    """
    doc = SimpleDocTemplate(output_path, pagesize=letter)
    story = []

    img = Image(image_path, width=200, height=100)  # 调整图像大小
    story.append(img)

    doc.build(story)

# 示例
create_image_pdf('image.pdf', 'image.jpg')  # 替换为你的图像文件路径

6. 生成动态内容

reportlab 可以根据数据动态生成 PDF 文档。例如,从数据库或 CSV 文件中读取数据,并将其添加到 PDF 表格中。

from reportlab.platypus import SimpleDocTemplate, Table, TableStyle
from reportlab.lib import colors

def create_dynamic_table_pdf(output_path, data):
    """
    使用动态数据创建 PDF 表格。

    Args:
        output_path: 输出 PDF 文件路径。
        data: 表格数据,列表的列表。
    """
    doc = SimpleDocTemplate(output_path, pagesize='A4')
    story = []

    table = Table(data)
    table.setStyle(TableStyle([
        ('BACKGROUND', (0, 0), (-1, 0), colors.grey),
        ('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke),
        ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
        ('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),
        ('BOTTOMPADDING', (0, 0), (-1, 0), 12),
        ('BACKGROUND', (0, 1), (-1, -1), colors.beige),
        ('GRID', (0, 0), (-1, -1), 1, colors.black)
    ]))

    story.append(table)
    doc.build(story)

# 示例:从 CSV 文件读取数据
import csv

def create_pdf_from_csv(csv_path, pdf_path):
    """
    从 CSV 文件读取数据并创建 PDF 文件。

    Args:
        csv_path: CSV 文件路径。
        pdf_path: 输出 PDF 文件路径。
    """
    data = []
    with open(csv_path, 'r') as csvfile:
        reader = csv.reader(csvfile)
        for row in reader:
            data.append(row)

    create_dynamic_table_pdf(pdf_path, data)

create_pdf_from_csv('data.csv', 'dynamic_table.pdf') # 确保 data.csv 文件存在

三、PyPDF2 和 reportlab 的结合使用

可以将 PyPDF2 和 reportlab 结合起来使用,例如,使用 PyPDF2 读取现有 PDF 文件的内容,然后使用 reportlab 创建新的 PDF 文件,并将读取的内容添加到新文件中。或者在用ReportLab生成的内容中,加入已经存在的PDF文件作为背景。

import PyPDF2
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import letter

def combine_pypdf2_and_reportlab(input_pdf_path, output_pdf_path):
    """
    结合 PyPDF2 和 reportlab 创建 PDF 文档。

    Args:
        input_pdf_path: 输入 PDF 文件路径。
        output_pdf_path: 输出 PDF 文件路径。
    """
    # 1. 使用 PyPDF2 读取现有 PDF 文件
    with open(input_pdf_path, 'rb') as input_file:
        reader = PyPDF2.PdfReader(input_file)
        first_page = reader.pages[0] # 读取第一页

    # 2. 使用 reportlab 创建新的 PDF 文件
    c = canvas.Canvas(output_pdf_path, pagesize=letter)

    # 添加文本
    c.drawString(100, 750, "This text is generated by ReportLab.")

    # 从现有 PDF 复制内容到新的 PDF (将读取到的第一页画到reportlab的canvas上)
    c.saveState() #保存当前Canvas状态
    c.translate(50,50) #将原点平移到(50,50)
    c.scale(0.5,0.5) #缩放0.5倍
    c.doFormXobj(first_page) #绘制PDF页面的内容。
    c.restoreState() #恢复Canvas状态

    # 3. 保存 PDF 文件
    c.save()

# 示例
combine_pypdf2_and_reportlab('input.pdf', 'combined.pdf')

这段代码首先使用 PyPDF2 读取 input.pdf 的第一页。然后,它使用 reportlab 创建一个新的 PDF 文件 combined.pdf,并在其中添加一些文本。 最关键的是c.doFormXobj(first_page)这句,它将读取的PyPDF2的Page对象渲染到reportlab的Canvas上。

四、实际应用案例

  • 自动生成报告: 从数据库中读取数据,使用 reportlab 创建包含表格、图表和文本的 PDF 报告。
  • 批量添加水印: 使用 PyPDF2 批量向 PDF 文件添加公司 logo 或版权声明。
  • PDF 文档加密: 使用 PyPDF2 对包含敏感信息的 PDF 文件进行加密,防止未经授权的访问。
  • 电子发票生成: 利用ReportLab精确控制布局的能力,结合数据库中的发票数据,生成符合规范的电子发票。
  • 简历生成器: 用户填写信息后,利用ReportLab动态生成个性化简历PDF。

五、总结与展望

通过本讲座,我们深入了解了 PyPDF2 和 reportlab 的高级用法,包括加密解密、水印添加、复杂布局设计以及动态内容生成。这两个库在 PDF 处理方面各有优势,可以根据实际需求选择合适的工具。它们的应用场景非常广泛,可以帮助我们自动化生成各种 PDF 文档,提高工作效率。 在未来,随着人工智能和机器学习技术的发展,PDF 处理将更加智能化,例如,自动识别 PDF 文档中的文本和表格,并进行数据提取和分析。

总结

  • PyPDF2 擅长处理现有 PDF 文件,如合并、分割、加密等。
  • reportlab 擅长从头创建 PDF 文档,可以精细控制页面布局和内容。
  • 两者结合使用,可以满足更复杂的 PDF 处理需求。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注