阅读文本 / Reading text
本文使用合成样本演示处理方法。代码已通过隔离环境中的示例检查;这不代表对所有真实文件或产品效果的保证。处理重要文件前,请保留原件,并按文中的边界与验收项复核。
裁剪框改变的是显示范围,不是页面内容本身。将印章叠到页面右边后看不见,先检查目标页面的 CropBox 和实际绘制坐标,再决定是否扩大可见范围。不要一上来就重置所有页面框:原来的裁剪可能是有意设置的。
先确认合并目标
下面的合成例子明确要求把完整的二百点宽页面用于交付,因此允许将目标 CropBox 恢复到 MediaBox。若任务要求保留原始成品裁切尺寸,则应调整印章的位置或大小,而不是扩大页面。这个选择属于交付协议,不由库替你判断。
用真实内容验证,不合并空白印章
示例用 PyMuPDF 创建带有
STAMP
文字的源页,再用 pypdf 合并。它在内存中完成,不覆盖任何文件。合并后检查文本仍存在和页面框符合预期;视觉位置还应通过渲染对照进一步验收。
from io import BytesIO
import pymupdf
from pypdf import PdfReader, PdfWriter, Transformation
from pypdf.generic import RectangleObject
with pymupdf.open() as source:
page = source.new_page(width=60, height=40)
page.insert_text((5, 20), "STAMP", fontsize=8)
stamp_bytes = source.tobytes()
writer = PdfWriter()
base = writer.add_blank_page(width=200, height=100)
base.cropbox = RectangleObject((0, 0, 100, 100))
assert base.cropbox.right == 100
# Explicit delivery policy for this fixture: reveal the full media area.
base.cropbox = RectangleObject(base.mediabox)
stamp = PdfReader(BytesIO(stamp_bytes)).pages[0]
base.merge_transformed_page(stamp, Transformation().translate(tx=120, ty=30), expand=False)
out = BytesIO()
writer.write(out)
result = PdfReader(BytesIO(out.getvalue())).pages[0]
assert tuple(result.cropbox) == (0, 0, 200, 100)
assert "STAMP" in result.extract_text()
assert result.mediabox.right == 200
expand 不是万能的可见性修复
merge_page
和
merge_transformed_page
都有
expand
参数。它与页面边界扩展有关,不应被解释为自动解决所有 CropBox、内容流裁剪、透明度和注释显示问题。本例将内容放在已有 MediaBox 内,明确使用
expand=False
,并单独设置目标可见区域。
按现象选择检查项
观察
应检查
不应直接做
内容存在但不可见
CropBox、变换与内容裁剪
断言内容已被删除
印章位置偏移
坐标单位、原点和旋转
只修改页面宽度
原稿裁切是有意的
成品交付尺寸
无条件恢复整张 MediaBox
文本提取正常但预览异常
字体、透明度与实际渲染
只凭文本断言放行
不能把裁剪当脱敏
被裁出可见区域的文字可能仍保留在内容流中。涉及敏感信息时,需要独立的内容删除、保存与重新提取验证流程。本文只是叠加和视口检查,不提供脱敏保证,也不判断文档法律效力。
翻译前后保留相同验收目标
使用
OmniDoc(产品入口)
处理这类 PDF 时,可以将“保留原裁切”或“展示完整页”写入自己的验收清单。OmniDoc 提供文档翻译入口;源页的显示范围、译后图文完整性仍值得用同一份脱敏样本对照检查。不能从本文代码推断平台内部使用了相同实现。
参考:
pypdf 裁剪与变换
。
- 1 -
更新于 2026-10-09