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

如何用PyPDF2和ReportLab自动为PDF地图目标位置添加唯一递增编号?

我明白你手动给PDF里的每个"A"加编号有多头疼——PyPDF2确实在文本定位这块能力有限,要搞定这个自动化任务,咱们得换个更趁手的工具:PyMuPDF(也就是fitz库),它能精准提取每个文本字符的位置,再结合它本身的PDF编辑功能,就能轻松完成编号添加。

下面给你两种可行的方案,先从最简单的纯PyMuPDF方案开始:

方案1:纯PyMuPDF实现(推荐,更简洁)

PyMuPDF不仅能提取文本位置,还能直接在PDF上添加文本,一步到位。

步骤&代码示例:

首先安装依赖:

pip install pymupdf

然后运行以下代码:

import fitz  # 导入PyMuPDF

# 配置参数
INPUT_PDF = "你的原始图纸.pdf"
OUTPUT_PDF = "带编号的图纸.pdf"
START_NUMBER = 101
# 编号的位置偏移:比如在"A"的右侧20单位,垂直居中(可根据实际调整)
OFFSET_X = 20
OFFSET_Y = 0
# 编号的字体样式(尽量匹配原文档,避免违和)
FONT_SIZE = 12
FONT_NAME = "helv"  # 常用字体:helv(黑体), times(宋体), courier(等宽)

def add_unique_numbers():
    doc = fitz.open(INPUT_PDF)
    current_num = START_NUMBER
    
    for page in doc:
        # 搜索页面中所有"A"字符,获取每个的位置矩形
        text_instances = page.search_for("A")
        
        for rect in text_instances:
            # 计算编号的位置:基于"A"的矩形右上角偏移
            # PyMuPDF坐标原点在左下角,rect的x0,y0是左下角,x1,y1是右上角
            num_x = rect.x1 + OFFSET_X
            num_y = rect.y0 + (rect.y1 - rect.y0)/2 + OFFSET_Y  # 垂直居中
            
            # 添加编号文本
            page.insert_text(
                (num_x, num_y),
                str(current_num),
                fontsize=FONT_SIZE,
                fontname=FONT_NAME,
                color=(0, 0, 0)  # 黑色,可改为(1,0,0)红色等
            )
            current_num += 1
    
    # 保存修改后的PDF
    doc.save(OUTPUT_PDF)
    doc.close()
    print(f"已完成!编号从{START_NUMBER}开始,保存至{OUTPUT_PDF}")

if __name__ == "__main__":
    add_unique_numbers()

关键说明:

  • page.search_for("A")会返回每个"A"所在的矩形区域,包含精确的坐标信息,这是PyPDF2做不到的
  • 你可以调整OFFSET_X和OFFSET_Y来改变编号相对于"A"的位置,比如想放在下方就调大OFFSET_Y(注意坐标原点在左下角,y值越大越靠上)
  • 如果原文档的"A"是特殊字体,可能需要调整FONT_NAME或者加载自定义字体(PyMuPDF支持加载本地字体文件)

方案2:PyMuPDF提取位置 + ReportLab生成叠加层 + PyPDF2合并

如果你坚持要用ReportLab,这个方案也可行:先提取所有"A"的位置,用ReportLab生成一个空白的PDF(只包含编号),再和原PDF合并。

步骤&代码示例:

先安装所有依赖:

pip install pymupdf reportlab PyPDF2

代码分为三部分:提取位置、生成叠加层、合并PDF:

import fitz
from reportlab.pdfgen import canvas
from PyPDF2 import PdfMerger, PdfReader

# 配置参数
INPUT_PDF = "你的原始图纸.pdf"
OVERLAY_PDF = "编号叠加层.pdf"
OUTPUT_PDF = "带编号的图纸.pdf"
START_NUMBER = 101
OFFSET_X = 20
OFFSET_Y = 0
FONT_SIZE = 12

# 第一步:提取所有"A"的位置,按页面存储
def get_a_positions():
    doc = fitz.open(INPUT_PDF)
    positions = {}  # key: 页码(从0开始), value: [(x,y), ...]
    
    for page_num in range(len(doc)):
        page = doc[page_num]
        text_instances = page.search_for("A")
        page_positions = []
        for rect in text_instances:
            # 转换坐标到ReportLab的系统(和PyMuPDF一致,左下角为原点)
            num_x = rect.x1 + OFFSET_X
            num_y = rect.y0 + (rect.y1 - rect.y0)/2 + OFFSET_Y
            page_positions.append((num_x, num_y))
        positions[page_num] = page_positions
    doc.close()
    return positions

# 第二步:用ReportLab生成叠加层PDF
def generate_overlay(positions):
    reader = PdfReader(INPUT_PDF)
    c = canvas.Canvas(OVERLAY_PDF)
    
    current_num = START_NUMBER
    for page_num in range(len(reader.pages)):
        # 设置画布大小和原页面一致
        page = reader.pages[page_num]
        width = float(page.mediabox.width)
        height = float(page.mediabox.height)
        c.setPageSize((width, height))
        
        # 绘制当前页面的所有编号
        for (x, y) in positions.get(page_num, []):
            c.setFont("Helvetica", FONT_SIZE)
            c.drawString(x, y, str(current_num))
            current_num += 1
        
        c.showPage()  # 切换到下一页
    
    c.save()

# 第三步:合并原PDF和叠加层
def merge_pdfs():
    merger = PdfMerger()
    merger.append(INPUT_PDF)
    merger.append(OVERLAY_PDF, pages=(0, len(PdfReader(INPUT_PDF).pages)))
    merger.write(OUTPUT_PDF)
    merger.close()

if __name__ == "__main__":
    positions = get_a_positions()
    generate_overlay(positions)
    merge_pdfs()
    print(f"已完成!保存至{OUTPUT_PDF}")

注意事项:

  • 这个方案需要确保叠加层的页面大小和原PDF完全一致,否则编号会错位
  • ReportLab的字体设置可能和原文档有差异,需要微调字体和大小

两种方案都能解决你的问题,优先推荐方案1,因为代码更简洁,不需要额外的合并步骤,出错概率更低。你可以先拿一页测试,调整偏移量和字体参数,确保编号位置完美后再批量处理。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 18:45:49