如何替换PDF隐藏文本层文本,使复制粘贴时替换内容位置正确
你遇到的问题是fitz的红框注释默认将替换文本作为独立内容流追加到页面末尾,没有融入原文本的排版顺序结构,因此跨区域复制文本或者全页提取时,替换内容不会出现在原有位置。
可行实现方案
方案1:重写整页文本(兼容性最好,文本顺序100%匹配原排版)
该方案通过先提取全页结构化文本,替换敏感词后重新写入页面,同时绘制遮盖矩形保证图像层敏感内容被覆盖,完全符合复制粘贴的顺序要求。
import fitz phrase_to_redact = "example" placeholder = "x" * len(phrase_to_redact) # 等长占位符 color = (1, 1, 1) # 白色填充,可按需调整 path = "你的文件路径.pdf" doc = fitz.open(path) for page in doc: # 第一步:提取页面所有带格式的文本块 blocks = page.get_text("dict", flags=fitz.TEXTFLAGS_TEXT)["blocks"] new_blocks = [] redact_rects = [] for block in blocks: if block["type"] != 0: # 非文本块直接保留(图片、矢量图等) new_blocks.append(block) continue for line in block["lines"]: for span in line["spans"]: # 查找包含敏感词的文本片段 if phrase_to_redact in span["text"]: # 记录要遮盖的坐标 redact_rects.append(fitz.Rect(span["bbox"])) # 替换敏感词为占位符 span["text"] = span["text"].replace(phrase_to_redact, placeholder) new_blocks.append(block) # 第二步:清空原页面所有内容 page.clean_contents() page.clear() # 第三步:把修改后的文本块按原顺序写回页面 for block in new_blocks: if block["type"] != 0: # 非文本块原样插入 page.insert_image(block["bbox"], stream=block["image"]) continue for line in block["lines"]: for span in line["spans"]: # 按原字体、字号、坐标插入修改后的文本 page.insert_text( (span["bbox"][0], span["bbox"][3] - span["descender"]), # 文本基线坐标 span["text"], fontsize=span["size"], fontname=span["font"], color=fitz.sRGB_to_pdf(span["color"]) ) # 第四步:绘制填充矩形遮盖图像层可能残留的敏感内容 for rect in redact_rects: page.draw_rect(rect, color=color, fill=color, overlay=True) doc.save("替换后文件.pdf", garbage=4, deflate=True)
方案2:基于红框注释的轻量修改(适合小范围替换场景)
如果不想重写全页内容,可以在应用红框注释后,手动调整内容流的顺序,将替换文本插入到原内容的对应位置,PyMuPDF 1.20+版本支持page.move_contents()方法调整内容流顺序:
import fitz phrase_to_redact = "example" placeholder = "x" * len(phrase_to_redact) color = (1,1,1) path = "你的文件路径.pdf" doc = fitz.open(path) for page in doc: rects = page.search_for(phrase_to_redact) # 记录原内容流长度 orig_contents_len = len(page.get_contents()) for rect in rects: page.add_redact_annot(rect, text=placeholder, fill=color) page.apply_redactions() # 把新增的替换文本内容流移到对应位置,匹配原排版顺序 new_contents = page.get_contents()[orig_contents_len:] for xref in new_contents: page.move_contents(xref, 0) doc.save("替换后文件.pdf", garbage=4, deflate=True)
注意事项
- 方案1的兼容性更好,几乎适配所有PDF阅读器的文本复制逻辑,同时能保证图像层和文本层的敏感内容都被彻底覆盖
- 等长占位符建议使用同宽度字符(比如全角
x或者*),避免替换后文本排版错位 - 处理带特殊字体的PDF时,如果出现插入文本字体不匹配的问题,可以提前把字体嵌入到PDF文件中
内容的提问来源于stack exchange,提问作者nietoperz21
相关产品推荐
相关产品推荐

