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

PDF指定位置替换印章问题:新印章位置不符求解决方案

问题描述

需要编写脚本遍历目录中的PDF文件,移除主题为Brick - Entered by Justin的印章,替换为stamp_path指向的新印章。当前代码可成功移除旧印章并添加新印章,但新印章无法定位在旧印章的原坐标位置。现有代码如下:

from pdfrw import PdfReader, PdfWriter, PageMerge, IndirectPdfDict
import os

# define the paths to the stamps and the PDF directory
stamp_path = r"C:\Users\Stamping\SampleStamp\STAMP BRICK_1.pdf"
pdf_directory = r"C:\Users\Stamping\PDF"


for filename in os.listdir(pdf_directory):
    input_file = os.path.join(pdf_directory, filename)
    if filename.endswith(".pdf"):
        old_stamp_pos=[]
        finished = "signed" + filename
        pdf_path = os.path.join(pdf_directory, filename)
        output_file = os.path.join(pdf_directory, finished)
        
        reader_input = PdfReader(input_file)

        
        for i in range(len(reader_input.pages)):
            # get the page
            page = reader_input.pages[i]

            # get the annotations on the page
            annotations = page.Annots or []
            for annotation in annotations:
                if annotation['/Subj'] == '(Brick - Entered by Justin)':
                    # get the position of the old stamp
                    old_stamp_pos = annotation['/Rect']

                    # remove the old stamp
                    page.Annots.remove(annotation)

                    writer_output = PdfWriter()
                    watermark_input = PdfReader(stamp_path)
                    watermark = watermark_input.pages[0]

                    merger = PageMerge(reader_input.pages[i])
                    #define x and y for the new stamp
                    watermark.x = old_stamp_pos[0]
                    watermark.y = old_stamp_pos[1]

                
                    merger.render()


                    # write the modified content to disk
writer_output.write(output_file, reader_input)
解决思路
  • 坐标与尺寸校准:PDF默认以左下角为坐标原点,旧印章的/Rect格式为[x1, y1, x2, y2](左下角到右上角),需确保新印章尺寸与旧印章匹配,否则直接使用x1,y1会导致偏移;同时要避免重复读取水印文件导致的对象复用问题。
  • 修复合并逻辑:原代码仅创建merger对象但未调用add方法将水印添加到页面,merger.render()无法完成合并操作,需先复制水印页面再添加到目标页面合并器。
  • 调整Writer初始化位置:原代码在注释遍历循环内初始化writer_output,会导致每次处理注释时重置Writer,最终仅保留最后一次修改,应将Writer初始化移到每个PDF文件的处理循环内。
  • 安全移除注释:直接在遍历注释列表时移除元素会引发遍历异常,需先收集所有待移除的注释,再统一移除。
修改后的代码
from pdfrw import PdfReader, PdfWriter, PageMerge, IndirectPdfDict
import os

# 定义印章路径和PDF目录
stamp_path = r"C:\Users\Stamping\SampleStamp\STAMP BRICK_1.pdf"
pdf_directory = r"C:\Users\Stamping\PDF"

# 预加载水印PDF,避免重复读取提升效率
watermark_input = PdfReader(stamp_path)
watermark_template = watermark_input.pages[0]
# 计算水印的宽高,用于后续位置校准
watermark_rect = watermark_template.MediaBox
watermark_width = watermark_rect[2] - watermark_rect[0]
watermark_height = watermark_rect[3] - watermark_rect[1]

for filename in os.listdir(pdf_directory):
    if not filename.endswith(".pdf"):
        continue
    input_file = os.path.join(pdf_directory, filename)
    output_file = os.path.join(pdf_directory, f"signed{filename}")
    
    reader_input = PdfReader(input_file)
    writer_output = PdfWriter()  # 每个PDF文件对应一个Writer
    
    for page in reader_input.pages:
        annotations = page.Annots or []
        to_remove = []
        target_pos = None
        
        # 收集目标印章的位置和待移除的注释
        for annotation in annotations:
            if annotation.get('/Subj') == '(Brick - Entered by Justin)':
                target_pos = annotation['/Rect']
                to_remove.append(annotation)
        
        # 移除旧印章注释
        for ann in to_remove:
            page.Annots.remove(ann)
        
        # 若找到旧印章位置,添加新印章
        if target_pos:
            # 旧印章左下角坐标为(target_pos[0], target_pos[1])
            x = target_pos[0]
            y = target_pos[1]
            
            # 复制水印模板,避免修改原对象影响后续页面
            watermark = PageMerge().add(watermark_template)[0]
            # 设置水印位置(匹配旧印章左下角)
            watermark.x = x
            watermark.y = y
            
            # 将水印合并到当前页面
            merger = PageMerge(page)
            merger.add(watermark)
            merger.render()
        
        # 将处理后的页面加入输出Writer
        writer_output.addpage(page)
    
    # 写入最终文件
    writer_output.write(output_file)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 06:10:39