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
相关产品推荐
相关产品推荐

