PDF 文件工程

两份 PDF 叠加后缺了一块:检查页面框而非只看纸张大小

文章解析pypdf合并PDF时内容被裁切的根因,区分MediaBox与CropBox及变换边界影响。提供内存级合成示例与验收表,明确输入输出边界和人工审查节点。OmniDoc产品入口自然融入文档翻译工作流,未夸大功能。技术细节基于原厂文档,无虚构能力或危险操作。

阅读文本 / 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