You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为ReportLab生成的PDF添加页脚页码(第X页/共Y页)?已尝试PyPDF

为PDF添加“第X页,共Y页”页脚的两种实现方法

问题背景

已通过ReportLab生成带表格的PDF,文件生成和客户端获取功能正常,但无法添加“第X页,共Y页”样式的页脚,试过PyPDF2和ReportLab基础用法未成功,现有代码如下:

def create_sample_source_report_pdf(task_id):
    ...... data generation ..........

    # Create a byte stream to hold the PDF content
    pdf_byte_stream = io.BytesIO()
    
    # Create a PDF document
    doc = SimpleDocTemplate(pdf_byte_stream, pagesize=landscape(A4))

    # Create a table with the data
    table = Table(data)
    
    # Add style to the table
    style = TableStyle([
        ('TEXTCOLOR', (0, 0), (-1, 0), colors.white),  # Header text color
        ('BACKGROUND', (0, 0), (-1, 0), colors.darkgrey),  # Header background color
        ('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.lightgrey),  # Light grey background for every 2nd row
        ('GRID', (0, 0), (-1, -1), 1, colors.black),
    ])
    
    table.setStyle(style)

    # Build the PDF
    doc.build([table])  # Spacer for title

    # Move the pointer to the beginning of the byte stream
    pdf_byte_stream.seek(0)

    ##################add text with page x of y


    # Now you can use the modified byte stream to create a BlobMedia
    blob_media_pdf = BlobMedia("application/pdf", modified_pdf_byte_stream.read(), name="sample_source_list_with_page_numbers.pdf")

    return blob_media_pdf

方法一:直接用ReportLab生成时添加页码(推荐)

利用ReportLab的SimpleDocTemplate.build()方法支持的回调函数,在生成PDF时直接绘制页脚,无需后续修改PDF文件。

修改后的完整代码

from reportlab.lib.pagesizes import landscape, A4
from reportlab.platypus import SimpleDocTemplate, Table, TableStyle
from reportlab.lib import colors
import io

def create_sample_source_report_pdf(task_id):
    ...... data generation ..........

    # 定义页脚绘制函数
    def draw_footer(canvas, doc):
        # 获取当前页码与总页数
        current_page = canvas.getPageNumber()
        total_pages = doc.page
        footer_text = f"第{current_page}页,共{total_pages}页"
        
        # 设置字体样式
        canvas.setFont("Helvetica", 10)
        # 计算居中位置(距离页面底部20px)
        text_width = canvas.stringWidth(footer_text, "Helvetica", 10)
        x_pos = (doc.pagesize[0] - text_width) / 2
        y_pos = 20
        
        # 绘制页脚文本
        canvas.drawString(x_pos, y_pos, footer_text)

    # Create a byte stream to hold the PDF content
    pdf_byte_stream = io.BytesIO()
    
    # Create a PDF document
    doc = SimpleDocTemplate(pdf_byte_stream, pagesize=landscape(A4))

    # Create a table with the data
    table = Table(data)
    
    # Add style to the table
    style = TableStyle([
        ('TEXTCOLOR', (0, 0), (-1, 0), colors.white),  # Header text color
        ('BACKGROUND', (0, 0), (-1, 0), colors.darkgrey),  # Header background color
        ('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.lightgrey),  # Light grey background for every 2nd row
        ('GRID', (0, 0), (-1, -1), 1, colors.black),
    ])
    
    table.setStyle(style)

    # Build the PDF并传入页脚绘制函数
    doc.build([table], onFirstPage=draw_footer, onLaterPages=draw_footer)

    # Move the pointer to the beginning of the byte stream
    pdf_byte_stream.seek(0)

    # Now you can use the modified byte stream to create a BlobMedia
    blob_media_pdf = BlobMedia("application/pdf", pdf_byte_stream.read(), name="sample_source_list_with_page_numbers.pdf")

    return blob_media_pdf

关键说明

  • draw_footer函数通过canvas.getPageNumber()获取当前页码,doc.page获取总页数
  • 在doc.build()时传入onFirstPage和onLaterPages参数,实现所有页面统一添加页脚
  • 可通过调整setFont的字体、大小,以及x_pos、y_pos修改页脚的样式和位置

方法二:用PyPDF2给已生成的PDF添加页码

如果需要对已生成的PDF文件补加页码,可使用PyPDF2的读写能力实现:

替换原代码中##################add text with page x of y部分的代码

from PyPDF2 import PdfReader, PdfWriter
from PyPDF2.generic import AnnotationBuilder

# 读取已生成的PDF内容
reader = PdfReader(pdf_byte_stream)
writer = PdfWriter()
total_pages = len(reader.pages)

for page_idx, page in enumerate(reader.pages, start=1):
    writer.add_page(page)
    # 构造页脚文本
    footer_text = f"第{page_idx}页,共{total_pages}页"
    # 获取页面尺寸,计算文本居中位置
    page_width = float(page.mediabox[2])
    # 近似计算文本宽度(单字符约5.5px,也可结合ReportLab的stringWidth精准计算)
    text_width = len(footer_text) * 5.5
    x_pos = (page_width - text_width) / 2
    y_pos = 20

    # 创建文本注释并添加到页面
    annotation = AnnotationBuilder.free_text(
        footer_text,
        rect=(x_pos, y_pos, x_pos + text_width, y_pos + 12),
        font="Helvetica",
        font_size=10,
        color=(0, 0, 0)
    )
    writer.add_annotation(page_number=page_idx-1, annotation=annotation)

# 将修改后的PDF写入新字节流
modified_pdf_byte_stream = io.BytesIO()
writer.write(modified_pdf_byte_stream)
modified_pdf_byte_stream.seek(0)

关键说明

  • 遍历每一页,计算总页数与当前页码
  • 使用AnnotationBuilder.free_text创建文本注释,添加到对应页面
  • 若需要更精准的文本宽度计算,可引入ReportLab的stringWidth方法提前计算

内容的提问来源于stack exchange,提问作者KROLN

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 21:44:52