PDF处理功能已重构为4个模块,便于维护和理解:
ocr_utils/
├── pdf_utils.py # 主入口 - 高级API和向后兼容包装
├── pdf_coordinate_transform.py # 坐标转换功能
├── pdf_text_extraction.py # 文本提取功能
├── pdf_image_rendering.py # 图像渲染功能
└── pdf_README.md # 本文档
作用: 高级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"
)
作用: 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 Rotation (顺时针) | 图片 Rotation (逆时针) | |---------------------|---------------------| | 0° | 0° | | 90° | 270° | | 180° | 180° | | 270° | 90° |
引擎原始行为差异: | 特性 | fitz | pypdfium2 | |------|------|-----------|| | 原生返回坐标 | 正视坐标(总是upright) | 旋转后坐标(匹配PDF rotation) | | 坐标系类型 | 与rotation无关 | 与rotation相关 | | 转换需求 | 需转换为旋转后(如需要) | 需转换为正视(如需要) |
统一后的输出:
| 参数 | fitz输出 | pypdfium2输出 | 说明 |
|------|---------|--------------|------|
| to_rotated=Falseto_upright=True | 正视坐标 | 正视坐标 | 默认,推荐 |
| to_rotated=Trueto_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 # 默认值,返回正视坐标
)
作用: 从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(已废弃):保留向后兼容,使用时会警告支持引擎:
使用示例:
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页面渲染为图像
核心函数:
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(...)
# ... 等等
# 推荐: 直接从子模块导入
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)
# 兼容: 通过PDFUtils类使用
from ocr_utils.pdf_utils import PDFUtils
text_blocks, rotation = PDFUtils.extract_all_text_blocks(pdf_doc, 0, 2.778)
# 生产环境推荐: pypdfium2 (MinerU标准)
renderer = "pypdfium2" # 多进程加速,更好的细节保留
# 开发/测试: fitz (简单轻量)
renderer = "fitz" # 无需额外依赖,单进程
重构后通过完整测试验证:
修复的关键bug:
测试命令:
cd ocr_tools/universal_doc_parser/tests
python test_pdf_rotation.py
测试覆盖:
根据功能类型选择合适的模块:
pdf_coordinate_transform.pypdf_text_extraction.pypdf_image_rendering.pypdf_utils.pypdf_utils.py中更新包装函数python test_pdf_rotation.py重构日期: 2026-01-05
API改进日期: 2026-01-07
重构原因: pdf_utils.py文件过大(984行),难以维护
重构目标: 按功能层次拆分,提高可维护性,保持向后兼容性
API改进: 统一坐标系输出逻辑,使用语义明确的return_upright_coords参数替代with_rotation