pdf_README.md 11 KB

PDF处理模块重构说明

📦 模块结构

PDF处理功能已重构为4个模块,便于维护和理解:

ocr_utils/
├── pdf_utils.py                    # 主入口 - 高级API和向后兼容包装
├── pdf_coordinate_transform.py     # 坐标转换功能
├── pdf_text_extraction.py          # 文本提取功能  
├── pdf_image_rendering.py          # 图像渲染功能
└── pdf_README.md                   # 本文档

🔧 各模块功能

1. pdf_utils.py (主入口,~400行)

作用: 高级API和统一入口,保持向后兼容性

主要类: PDFUtils

核心功能:

  • load_and_classify_document(): 加载文档(PDF/图片)并分类
  • merge_cross_page_tables(): 跨页表格合并(TODO)
  • 所有子模块函数的重新导出(向后兼容)

使用示例:

from ocr_utils.pdf_utils import PDFUtils

# 加载PDF并分类
images, pdf_type, pdf_doc, renderer = PDFUtils.load_and_classify_document(
    document_path=Path("test.pdf"),
    dpi=200,
    page_range="1-5",
    renderer="fitz"
)

2. pdf_coordinate_transform.py (~315行)

作用: PDF坐标系与图像坐标系的转换

核心函数:

  • pdf_rotation_to_image_rotation(): PDF旋转角度转换为图片旋转角度
  • transform_bbox_for_rotation_fitz(): fitz引擎的坐标变换(支持正视/旋转后坐标输出)
  • transform_bbox_for_rotation_pypdfium2(): pypdfium2引擎的坐标变换(支持正视/旋转后坐标输出)

⭐ 统一输出逻辑(重要): 两个引擎通过参数统一对外输出行为:

  • 正视坐标return_upright_coords=True,默认,推荐):坐标在正视方向,不受PDF rotation影响
  • 旋转后坐标return_upright_coords=False):坐标在旋转后坐标系,匹配PDF rotation

坐标系说明:

  • PDF坐标系: 左下角原点 (0,0),X向右,Y向上
  • 图像坐标系: 左上角原点 (0,0),X向右,Y向下
  • 正视坐标: 视觉上保持upright(rotation=0)的坐标系
  • 旋转后坐标: 匹配PDF rotation属性的坐标系

旋转定义(重要):

  • PDF rotation: 0/90/180/270度(顺时针旋转,PDF规范)
  • 图片rotation: 0/90/180/270度(逆时针旋转,图像处理标准)
  • 对外API统一返回图片rotation(逆时针定义)

旋转转换映射: | PDF Rotation (顺时针) | 图片 Rotation (逆时针) | |---------------------|---------------------| | 0° | 0° | | 90° | 270° | | 180° | 180° | | 270° | 90° |

引擎原始行为差异: | 特性 | fitz | pypdfium2 | |------|------|-----------|| | 原生返回坐标 | 正视坐标(总是upright) | 旋转后坐标(匹配PDF rotation) | | 坐标系类型 | 与rotation无关 | 与rotation相关 | | 转换需求 | 需转换为旋转后(如需要) | 需转换为正视(如需要) |

统一后的输出: | 参数 | fitz输出 | pypdfium2输出 | 说明 | |------|---------|--------------|------| | to_rotated=False
to_upright=True | 正视坐标 | 正视坐标 | 默认,推荐 | | to_rotated=True
to_upright=False | 旋转后坐标 | 旋转后坐标 | 匹配渲染图像 |

使用示例:

from ocr_utils.pdf_coordinate_transform import (
    transform_bbox_for_rotation_fitz,
    transform_bbox_for_rotation_pypdfium2
)

# fitz引擎: 返回正视坐标(默认,推荐)
upright_bbox = transform_bbox_for_rotation_fitz(
    bbox=[100, 50, 200, 100],
    rotation=90,
    pdf_width=595,
    pdf_height=842,
    scale=2.778,
    to_rotated=False  # 默认值,返回正视坐标
)

# fitz引擎: 返回旋转后坐标
rotated_bbox = transform_bbox_for_rotation_fitz(
    bbox=[100, 50, 200, 100],
    rotation=90,
    pdf_width=595,
    pdf_height=842,
    scale=2.778,
    to_rotated=True  # 返回旋转后坐标
)

# pypdfium2引擎: 返回正视坐标(默认,推荐)
upright_bbox = transform_bbox_for_rotation_pypdfium2(
    bbox=[100, 50, 200, 100],
    rotation=90,
    pdf_width=595,
    pdf_height=842,
    scale=2.778,
    to_upright=True  # 默认值,返回正视坐标
)

3. pdf_text_extraction.py (~450行)

作用: 从PDF提取文本,支持rotation处理和坐标系选择

核心函数:

  • extract_text_from_pdf(): 从指定区域提取文本(自动检测引擎)
  • extract_all_text_blocks(): 提取页面所有文本块(自动检测引擎,支持坐标系选择)
  • detect_pdf_doc_type(): 检测PDF文档类型(fitz/pypdfium2)
  • bbox_overlap(): 检查bbox重叠

⭐ 坐标系选择参数:

  • return_upright_coords=True(默认):返回正视坐标,所有rotation下坐标一致
  • return_upright_coords=False:返回旋转后坐标,匹配渲染图像
  • with_rotation(已废弃):保留向后兼容,使用时会警告

支持引擎:

  • pypdfium2: MinerU标准引擎
  • fitz (PyMuPDF): 轻量级替代引擎

使用示例:

from ocr_utils.pdf_text_extraction import extract_all_text_blocks

# 方式1: 提取正视坐标(默认,推荐)
text_blocks, rotation = extract_all_text_blocks(
    pdf_doc=pdf_doc,
    page_idx=0,
    scale=2.778,
    return_upright_coords=True  # 默认值
)

# 方式2: 提取旋转后坐标(匹配渲染图像)
text_blocks, rotation = extract_all_text_blocks(
    pdf_doc=pdf_doc,
    page_idx=0,
    scale=2.778,
    return_upright_coords=False
)

# 返回格式:
# text_blocks = [
#     {
#         'text': 'Hello',
#         'bbox': [x1, y1, x2, y2],          # 转换后的坐标(正视或旋转后)
#         'origin_bbox': [x1, y1, x2, y2]    # 原始坐标
#     },
#     ...
# ]
# rotation = 270  # 图片旋转角度:0/90/180/270(逆时针)

⚠️ 坐标系说明:

  • return_upright_coords=True(推荐):bbox在正视坐标系,不同rotation下相同文本坐标一致
  • return_upright_coords=False:bbox在旋转后坐标系,与渲染图像对齐,可直接绘制
  • rotation 返回值采用图片旋转定义(逆时针),不是PDF rotation(顺时针)
  • PDF rotation 90° → 返回 270°(图片需要逆时针旋转270°)
  • PDF rotation 270° → 返回 90°(图片需要逆时针旋转90°)

4. pdf_image_rendering.py (~300行)

作用: PDF页面渲染为图像

核心函数:

  • load_images_from_pdf_unified(): 统一的PDF图像加载接口
  • load_images_pypdfium2(): 使用pypdfium2渲染
  • load_images_fitz(): 使用fitz渲染

渲染引擎对比: | 特性 | pypdfium2 | fitz | |------|-----------|------| | 渲染引擎 | Chrome PDFium | MuPDF | | 多进程加速 | ✅ (非Windows) | ❌ | | 超时控制 | ✅ | ❌ | | 尺寸限制 | 3500px | 4500px | | 超限处理 | 动态调整scale | 降到72 DPI | | MinerU标准 | ✅ | ❌ |

使用示例:

from ocr_utils.pdf_image_rendering import load_images_from_pdf_unified

# 使用pypdfium2(推荐)
images, doc = load_images_from_pdf_unified(
    pdf_bytes=pdf_bytes,
    dpi=200,
    renderer="pypdfium2",
    threads=4
)

# 使用fitz
images, doc = load_images_from_pdf_unified(
    pdf_bytes=pdf_bytes,
    dpi=200,
    renderer="fitz"
)

# 返回格式:
# images = [
#     {'img_pil': PIL.Image, 'scale': 2.778},
#     ...
# ]

🔄 向后兼容性

所有原有代码无需修改!

PDFUtils类保留了所有原有方法作为包装函数,内部调用新模块的功能:

# 旧代码继续工作
from ocr_utils.pdf_utils import PDFUtils

# 所有这些方法仍然可用:
PDFUtils.extract_text_from_pdf(...)
PDFUtils.extract_all_text_blocks(...)
PDFUtils.load_images_from_pdf_unified(...)
PDFUtils._transform_bbox_for_rotation_fitz(...)
# ... 等等

📝 最佳实践

1. 新代码: 直接导入子模块

# 推荐: 直接从子模块导入
from ocr_utils.pdf_text_extraction import extract_all_text_blocks
from ocr_utils.pdf_coordinate_transform import transform_bbox_for_rotation_fitz

text_blocks, rotation = extract_all_text_blocks(pdf_doc, 0, 2.778)

2. 旧代码: 继续使用PDFUtils

# 兼容: 通过PDFUtils类使用
from ocr_utils.pdf_utils import PDFUtils

text_blocks, rotation = PDFUtils.extract_all_text_blocks(pdf_doc, 0, 2.778)

3. 渲染引擎选择

# 生产环境推荐: pypdfium2 (MinerU标准)
renderer = "pypdfium2"  # 多进程加速,更好的细节保留

# 开发/测试: fitz (简单轻量)
renderer = "fitz"  # 无需额外依赖,单进程

🎯 重构优势

  1. 代码组织: 从单个984行文件 → 4个模块,每个200-450行
  2. 职责清晰: 坐标变换、文本提取、图像渲染各自独立
  3. 易于测试: 各模块可独立测试
  4. 向后兼容: 现有代码无需修改
  5. 易于扩展: 新功能可加入对应模块,不影响其他部分

✅ 测试验证

重构后通过完整测试验证:

  • ✅ 所有24个测试通过 (4种rotation × 2种引擎 × 2种坐标模式 + 8个对比测试)
  • ✅ fitz引擎: rotation 0°/90°/180°/270° 正视坐标正确
  • ✅ pypdfium2引擎: rotation 0°/90°/180°/270° 正视坐标正确
  • ✅ 两种坐标模式对比测试通过
  • ✅ 坐标边界验证通过
  • ✅ 向后兼容性验证通过

修复的关键bug:

  • 🐛 修复pypdfium2在90°/270°转换时使用错误页面尺寸的问题
    • 问题:使用原始PDF尺寸,导致负坐标
    • 修复:使用旋转后页面尺寸(90°: height×width, 270°: height×width)

测试命令:

cd ocr_tools/universal_doc_parser/tests
python test_pdf_rotation.py

测试覆盖:

  • 正视坐标模式 (return_upright_coords=True)
  • 旋转后坐标模式 (return_upright_coords=False)
  • 两种模式对比验证
  • 可视化验证(生成带bbox标注的图像)

📚 相关文档

🔧 维护指南

添加新功能

根据功能类型选择合适的模块:

  1. 坐标转换相关pdf_coordinate_transform.py
  2. 文本提取相关pdf_text_extraction.py
  3. 图像渲染相关pdf_image_rendering.py
  4. 高级API/工作流pdf_utils.py

修改现有功能

  1. 在对应子模块中修改实现
  2. 如果改变了函数签名,需在pdf_utils.py中更新包装函数
  3. 运行测试验证: python test_pdf_rotation.py

重构日期: 2026-01-05
API改进日期: 2026-01-07
重构原因: pdf_utils.py文件过大(984行),难以维护
重构目标: 按功能层次拆分,提高可维护性,保持向后兼容性
API改进: 统一坐标系输出逻辑,使用语义明确的return_upright_coords参数替代with_rotation