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

如何基于已知变换矩阵对齐PDF文本且保留原有文本结构?

问题描述

存在多个文本块错位问题的PDF文件,需依据已知变换矩阵生成文本对齐后的新PDF。
使用PyMuPDF(fitz)提取源PDF文本信息插入目标PDF的实现方式,会丢失全部文本结构信息(blocks块、lines行、spans跨度等),复现代码如下:

import fitz

src_doc = fitz.open('my.pdf')
tgt_doc = fitz.open()

src_page = doc[0]
tgt_page = tgt_doc[0]

text_dict = src_page.get_text('dict')
transform = fitz.Matrix(1, 1) # would be non-identity in practice
tw = fitz.TextWriter(tgt_page.rect)

for block in text['blocks']:
    if block['type'] != 1: # ignore images
        blocks.append(block)
        for line in block['lines']:
            for span in line['spans']:                      
                tw.append(span['origin'], span['text'])

tw.write_text(tgt_page, morph=[fitz.Point([0.0, 0.0]), transform])

tgt_doc.save('aligned.pdf')
src_doc.close()
tgt_doc.close()

上述代码可实现基础文本对齐效果,但会完全丢失原有文本结构,最终生成的目标页面包含的文本块数量远多于源页面。需求为实现同等文本对齐效果的同时,不破坏原页面的文本结构。此前参考ocrmypdf项目实现,使用pikepdf库完成相关操作时,发现pikepdf仅支持ASCII字符,处理非拉丁文本存在障碍,可接受其他满足需求的第三方库推荐。

解决方案

方案1:使用PyMuPDF原生块级变换(推荐,无结构损失)

原有代码丢失结构的核心原因是TextWriter会将所有提取到的文本打散重排为新的连续文本流,不会保留原始PDF内容流中的块、行分段标记。不需要重写文本,直接在复制的源页面上对原始文本块应用变换矩阵即可100%保留原有结构,参考实现如下:

import fitz

src_doc = fitz.open("my.pdf")
tgt_doc = fitz.open()
# 直接将源页面完整拷贝到目标文档,保留所有原始内容、结构、字体信息
tgt_doc.insert_pdf(src_doc)
tgt_page = tgt_doc[0]

transform = fitz.Matrix(1, 1) # 替换为实际使用的非单位变换矩阵
pivot = fitz.Point(0, 0) # 变换锚点,可根据实际变换逻辑调整

# 获取源页面所有文本块的边界范围
text_dict = tgt_page.get_text("dict")
for block in text_dict["blocks"]:
    if block["type"] != 0: # 跳过图片块
        continue
    block_bbox = fitz.Rect(block["bbox"])
    # 对单个原始文本块应用变换,不拆分块内的行、span结构
    tgt_page.add_redact_annot(
        block_bbox,
        morph=(pivot, transform)
    )

# 应用变换时跳过图片、矢量图形,仅处理文本块
tgt_page.apply_redactions(
    images=fitz.PDF_REDACT_IMAGE_NONE,
    graphics=fitz.PDF_REDACT_LINE_ART_NONE
)

tgt_doc.save("aligned.pdf")
src_doc.close()
tgt_doc.close()

如果需要更细粒度的控制,可以直接解析页面原始内容流,定位每个BT...ET标记包裹的独立文本对象,直接修改其内置的变换矩阵参数,该方法不会触发任何文本重绘,结构保留度最高。

方案2:其他可选第三方库

  • borb:纯Python实现的PDF处理库,支持直接操作文本块的变换属性,对中文、日文、阿拉伯文等非拉丁文本支持完善,操作时不会破坏原有文本结构,缺点是大文件处理速度低于PyMuPDF。
  • pikepdf+fontTools组合:pikepdf本身并非不支持非ASCII字符,非拉丁文本乱码的核心原因是操作时没有正确处理字体的ToUnicode映射表和字体子集嵌入,搭配fontTools补全字体相关配置后即可正常处理非拉丁文本,该方案也是ocrmypdf处理多语言PDF的底层实现逻辑,缺点是配置复杂度较高。

不推荐使用PyPDF2、pdfplumber等库,前者块级操作支持极差,后者仅适合文本提取,不具备完善的PDF写入修改能力。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.01 20:18:29