wms/nflg-qms-pdf-extract/pdf数据提取方案.md

5.5 KiB
Raw Blame History

PDF 数据提取方案

一、项目概述

本项目从工程图纸 PDF 中提取尺寸标注数据(数值 + 公差 + 直径符号Φ),基于 Java + Spring Boot + PDFBox 3.x。


二、Φ(直径)符号识别方案

2.1 问题背景

工程图纸中,直径标注以 Φ 符号前缀表示(如 Φ280 ±0.15)。不同 PDF 生成方式导致 Φ 符号在文本层的表现完全不同:

PDF 类型 Φ 的存在方式 可提取性
AutoCAD 导出 PDF类型A 文字字符BerlinSansFB-Bold 字体),独立 TextGroup 可提取
其他 CAD 导出 PDF类型B 矢量图形路径(画的圆+斜线) 不可提取

2.2 类型A文字形式 Φ 的提取

流程:

  1. PositionedTextStripper 提取文本,乱码字符(如 ¡¤/U+00A1 U+00A4通过 correctGarbledText() 映射为 ΦU+03A6
  2. TextGrouper 将相邻文本元素分组,但 Φ 和数字因字体/位置差异通常分属不同 TextGroup
  3. DimensionIdentifier.findLeadingSymbolGroup() 在维度数字 TextGroup 的左侧搜索独立的 Φ TextGroup 并拼接

关键参数:

  • 符号集合:Φ(U+03A6), φ(U+03C6), Ø(U+00D8), ø(U+00F8), (U+2205), (U+2300)
  • 空间搜索范围:gapFromSymLeft ∈ [-10, maxGapFromLeft)dy < maxYDelta
    • maxGapFromLeft = max(dimFontSize × 5.0, 70)
    • maxYDelta = max(dimFontSize × 3.0, 40)
  • 渲染顺序过滤seqDiffdimSeq - phiSeq >= 180
    • AutoCAD PDF 中 Φ 符号在早期渲染层seqNum ≈ 33-37数字在后期层seqNum ≈ 228-239
    • 真正配对的 seqDiff = 195~205
    • 误配 "160" 的 seqDiff = 173误配 "6" 的 seqDiff = 6~7
    • 阈值 180 可完美分离

2.3 类型B矢量图形 Φ 的启发式推断

当 PDF 中 Φ 是图形路径时(整个页面无任何 Φ 文本字符),采用配合公差启发式规则:

规则1 — 配合公差直接推断:

  • 文本含配合公差代号(如 230 m6 +0.017)→ 自动加 Φ
  • 排除:大写 R 开头的代号(如 15R4),因为 R+数字 通常表示圆角半径而非配合公差

规则2 — 附近配合公差 TextGroup

  • 搜索范围dx < 100, dy < 50像素坐标
  • 附近存在 2-3 字符的配合代号文本(如独立的 "H7" TextGroup→ 加 Φ
  • 示例:280 ±0.15 附近有 H7(dx=56, dy=14) → 识别为 Φ280

已知局限:

  • 当 Φ 是矢量图形且附近无配合公差代号时(如 Φ55 ±0.15),无法自动识别
  • 此类情况需用户在提取结果中手动添加 Φ 前缀

三、文本提取管线

PDF文件
  ↓
PositionedTextStripper.writeString()    ← 提取每次文本绘制调用
  │  ├─ 重建 Unicode 文本TextPosition.getUnicode()
  │  ├─ correctGarbledText():修复乱码映射
  │  └─ 生成 TextElement含坐标、字号、seqNum
  ↓
TextGrouper.group()                     ← 按空间邻近性分组
  │  └─ 生成 TextGroup 列表
  ↓
DimensionIdentifier.identifyDimensions()  ← 正则匹配 + 符号拼接
  │  ├─ TextNormalizer.normalizeText():二次乱码修复
  │  ├─ 正则模式匹配(公差/配合/螺纹/纯数值)
  │  ├─ findLeadingSymbolGroup():搜索独立Φ TextGroup
  │  ├─ inferDiameterFromContext():配合公差启发式
  │  └─ findNearbyTolerance():搜索附近公差文本
  ↓
DimensionResult 列表               ← 最终输出

四、乱码映射表

4.1 correctGarbledText()PositionedTextStripper

原始乱码 映射结果 说明
¡¤ (U+00A1 U+00A4) Φ (U+03A6) BerlinSansFB-Bold 字体直径符号
¡ã (U+00A1 U+00E3) ° (U+00B0) 度数符号
¡À (U+00A1 U+00C0) ± (U+00B1) 正负公差
¦µ (U+00A6 U+00B5) Φ (U+03A6) 直径符号变体
¡Á (U+00A1 U+00C1) ± (U+00B1) 正负公差变体
单独 ¡ (U+00A1) Φ (U+03A6) ¡¤ 跨 writeString 拆分时
单独 ¤ (U+00A4) 删除 ¡¤ 跨 writeString 拆分时
U+FFFD 删除 Unicode 替换字符

4.2 TextNormalizer.normalizeText()

与 correctGarbledText 类似的映射,加上:

  • Φ\u0080ΦWindows GBK 尾随控制字符)
  • Ø\u0080Ø
  • ±\u0080±
  • Æø (U+00C6 U+00F8) → Ø
  • NFC 规范化

五、正则模式优先级

identifyDimensions() 中的匹配顺序(先匹配先处理):

  1. PAT_COMPOUND_TOL — 复合公差文本(如 +0.03 0)→ 跳过(不作为尺寸)
  2. PAT_DIM_SYM_TOL — 对称公差(如 280 ±0.15
  3. PAT_DIM_ASYM_TOL — 非对称公差/斜线(如 55 +0.03/-0.02
  4. PAT_DIM_LIMIT_TOL — 非对称公差/空格(如 55 +0.03 -0.02
  5. PAT_DIM_FIT — 配合公差(如 230 m6280 H7
  6. PAT_THREAD — 螺纹标注(如 M24×1.5
  7. PAT_PLAIN_DIM — 纯尺寸数值(如 270R15

六、关键文件

文件 职责
PositionedTextStripper.java PDFBox 文本提取、乱码修复、seqNum 赋值
TextGrouper.java 按空间邻近性将 TextElement 分组为 TextGroup
TextNormalizer.java 二次乱码映射、NFC 规范化
DimensionIdentifier.java 尺寸识别核心逻辑(正则 + Φ拼接 + 启发式)
TitleBlockFilter.java 标题栏区域过滤、GD&T/粗糙度排除
RegionFilterService.java 区域框选模式尺寸提取
PdfExtractionService.java 提取服务入口