5.5 KiB
5.5 KiB
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:文字形式 Φ 的提取
流程:
PositionedTextStripper提取文本,乱码字符(如¡¤/U+00A1 U+00A4)通过correctGarbledText()映射为 Φ(U+03A6)TextGrouper将相邻文本元素分组,但 Φ 和数字因字体/位置差异通常分属不同 TextGroupDimensionIdentifier.findLeadingSymbolGroup()在维度数字 TextGroup 的左侧搜索独立的 Φ TextGroup 并拼接
关键参数:
- 符号集合:
Φ(U+03A6),φ(U+03C6),Ø(U+00D8),ø(U+00F8),∅(U+2205),⌀(U+2300) - 空间搜索范围:
gapFromSymLeft ∈ [-10, maxGapFromLeft),dy < maxYDeltamaxGapFromLeft = max(dimFontSize × 5.0, 70)maxYDelta = max(dimFontSize × 3.0, 40)
- 渲染顺序过滤(seqDiff):
dimSeq - 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() 中的匹配顺序(先匹配先处理):
- PAT_COMPOUND_TOL — 复合公差文本(如
+0.03 0)→ 跳过(不作为尺寸) - PAT_DIM_SYM_TOL — 对称公差(如
280 ±0.15) - PAT_DIM_ASYM_TOL — 非对称公差/斜线(如
55 +0.03/-0.02) - PAT_DIM_LIMIT_TOL — 非对称公差/空格(如
55 +0.03 -0.02) - PAT_DIM_FIT — 配合公差(如
230 m6、280 H7) - PAT_THREAD — 螺纹标注(如
M24×1.5) - PAT_PLAIN_DIM — 纯尺寸数值(如
270、R15)
六、关键文件
| 文件 | 职责 |
|---|---|
PositionedTextStripper.java |
PDFBox 文本提取、乱码修复、seqNum 赋值 |
TextGrouper.java |
按空间邻近性将 TextElement 分组为 TextGroup |
TextNormalizer.java |
二次乱码映射、NFC 规范化 |
DimensionIdentifier.java |
尺寸识别核心逻辑(正则 + Φ拼接 + 启发式) |
TitleBlockFilter.java |
标题栏区域过滤、GD&T/粗糙度排除 |
RegionFilterService.java |
区域框选模式尺寸提取 |
PdfExtractionService.java |
提取服务入口 |