Files
doc_processer/docs/LATEX_RENDERING_FIX_REPORT.md
2026-02-05 13:18:55 +08:00

9.7 KiB
Raw Permalink Blame History

LaTeX 字符渲染问题分析与修复报告

问题描述

OCR 识别完成后,某些 LaTeX 字符(如 \lambda\vdots)没有被成功渲染。

问题诊断

1. LaTeX 语法检查

结论: LaTeX 语法完全正确。

  • \lambda - 希腊字母 λ (Unicode U+03BB)
  • \vdots - 垂直省略号 ⋮ (Unicode U+22EE)

这两个都是标准的 LaTeX 命令,不存在语法问题。

2. 后处理管道分析

位置: app/services/ocr_service.py

结论: OCR 后处理管道不会破坏这些字符。

后处理分为三个阶段:

Stage 0: 修复 OCR 数字错误

_fix_ocr_number_errors(expr)
  • 影响范围: 仅处理数字、小数点和空格
  • \lambda\vdots 的影响: 无影响

Stage 1: 拆分粘连命令

_split_glued_command_token(token)
  • 工作原理: 仅处理 _COMMANDS_NEED_SPACE 白名单中的命令
  • 白名单内容: cdot, times, div, int, sum, sin, cos
  • \lambda\vdots 是否在白名单中: 不在
  • 逻辑: 如果命令不在白名单中,直接返回原值
  • \lambda\vdots 的影响: 无影响

Stage 2: 规范化微分符号

_DIFFERENTIAL_UPPER_PATTERN.sub(r"\\mathrm{d} \1", expr)
_DIFFERENTIAL_LOWER_PATTERN.sub(r"d \1", expr)
  • 匹配模式: (?<!\\)d([A-Z])(?<!\\)d([a-z])
  • 工作原理: 使用负向后查找 (?<!\\) 确保只匹配非转义的 d
  • \lambda\vdots 的影响: 无影响

3. 真正的问题: MathML 转换和后处理 ⚠️

位置: app/services/converter.py

问题 A: Unicode 实体映射不完整

发现: 在 _postprocess_mathml_for_word() 函数中Unicode 实体映射表不完整。

原始映射表(修复前):

unicode_map = {
    # ... 基本运算符 ...
    '&#x03BB;': 'λ',  # lambda - 已有
    '&#x022EE;': '⋮',  # vdots - 已有,但可能还有其他缺失
    # ... 其他映射较少 ...
}

问题:

  1. 缺少大量希腊字母(如大写的 Λ, Σ, Ω 等)
  2. 缺少其他省略号符号(如 \ddots, \iddots
  3. 缺少常用数学符号(如 \infty, \sum, \prod 等)
  4. 没有处理十进制格式的实体编码(&#NNNN;

问题 B: Pandoc 可能输出不同格式的实体

Pandoc 在转换 LaTeX 到 MathML 时,可能会输出:

  • 十六进制格式: &#x03BB; (lambda)
  • 十进制格式: &#955; (lambda)
  • 直接 Unicode: λ

如果只映射了十六进制格式,十进制格式的实体就不会被转换。

4. 是否是前端二次处理问题?

需要排查的步骤:

  1. 检查 API 响应

    curl -X POST "http://localhost:8000/api/v1/image/ocr" \
      -H "Content-Type: application/json" \
      -d '{"image_url": "...", "model_name": "paddle"}' | jq '.mathml'
    

    查看返回的 MathML 中是否包含:

    • Unicode 字符 λ 后端正确
    • 实体编码 &#x03BB;&#x022EE;⚠️ 后端未正确转换
  2. 检查前端渲染库

    • 如果使用 MathJax: 检查版本和配置
    • 如果使用 KaTeX: 检查是否支持所有符号
    • 检查字体加载情况
  3. 检查前端代码

    • 搜索是否有对 MathML 内容的字符串替换
    • 检查是否有正则表达式过滤特殊字符
    • 查看是否有 HTML 转义处理

修复方案

方案 1: 扩展 Unicode 实体映射(已实施)

文件: app/services/converter.py

修改内容:

  1. 扩展十六进制实体映射表,新增:

    • 完整的希腊字母(大小写)
    • 所有省略号符号(\vdots, \cdots, \ddots, \iddots, \ldots
    • 常用数学符号(积分、求和、无穷大、集合运算等)
    • 关系符号(小于等于、大于等于、约等于等)
    • 逻辑符号(与、或、非、蕴含等)
    • 箭头符号
    • 其他特殊符号
  2. 新增十进制实体处理,覆盖常用字符:

    decimal_patterns = [
        (r'&#955;', 'λ'),    # lambda
        (r'&#8942;', '⋮'),   # vdots
        (r'&#8943;', '⋯'),   # cdots
        # ... 更多映射 ...
    ]
    

优势:

  • 一次性修复所有 Unicode 字符渲染问题
  • 支持多种实体编码格式
  • 不影响现有功能
  • 性能影响极小(简单字符串替换)

方案 2: 使用前端诊断工具

工具: diagnose_latex_rendering.py

用途: 诊断后处理管道是否修改了输入

使用方法:

python diagnose_latex_rendering.py "$\lambda + \vdots$"
python diagnose_latex_rendering.py "$$\lambda_1, \lambda_2, \vdots, \lambda_n$$"

输出内容:

  1. 字符检测结果
  2. 每个后处理阶段的变化
  3. 最终输出
  4. 问题定位建议

方案 3: 测试修复效果

工具: test_unicode_fix.py

测试内容:

  1. Unicode 实体映射是否正确
  2. 完整的 LaTeX 到 MathML 转换流程
  3. 验证所有希腊字母和数学符号

运行方法:

python test_unicode_fix.py

修复内容总结

扩展的字符支持

1. 希腊字母(完整)

LaTeX Unicode 实体(十六进制) 实体(十进制)
\alpha α &#x03B1; &#945;
\beta β &#x03B2; &#946;
\gamma γ &#x03B3; &#947;
\delta δ &#x03B4; &#948;
\lambda λ &#x03BB; &#955;
\Gamma Γ &#x0393; &#915;
\Delta Δ &#x0394; &#916;
\Lambda Λ &#x039B; &#923;
\Sigma Σ &#x03A3; &#931;
\Omega Ω &#x03A9; &#937;

2. 省略号符号(完整)

LaTeX Unicode 实体(十六进制) 实体(十进制)
\ldots &#x02026; &#8230;
\cdots &#x022EF; &#8943;
\vdots &#x022EE; &#8942;
\ddots &#x022F1; &#8945;
\iddots &#x022F0; &#8944;

3. 数学运算符

LaTeX Unicode 实体
\infty &#x221E; / &#8734;
\sum &#x2211; / &#8721;
\prod &#x220F; / &#8719;
\sqrt &#x221A; / &#8730;
\int &#x222B;
\partial &#x2202;
\nabla &#x2207;

4. 关系符号

LaTeX Unicode 实体
\leq &#x2264; / &#8804;
\geq &#x2265; / &#8805;
\neq &#x2260; / &#8800;
\approx &#x2248; / &#8776;
\equiv &#x2261; / &#8801;

5. 集合运算

LaTeX Unicode 实体
\in &#x2208; / &#8712;
\notin &#x2209; / &#8713;
\cup &#x222A; / &#8746;
\cap &#x2229; / &#8745;
\subset &#x2282;
\supset &#x2283;

覆盖的字符范围

  • 24 个小写希腊字母
  • 24 个大写希腊字母
  • 5 个省略号符号
  • 50+ 个数学运算符和符号
  • 关系符号、逻辑符号、箭头符号
  • 支持十六进制和十进制实体编码

验证步骤

1. 单元测试

python test_unicode_fix.py

预期输出: 所有测试通过

2. 集成测试

使用 API 测试完整流程:

# 测试 lambda
curl -X POST "http://localhost:8000/api/v1/convert/latex-to-omml" \
  -H "Content-Type: application/json" \
  -d '{"latex": "\\lambda_1, \\lambda_2, \\vdots, \\lambda_n"}'

# 测试 vdots
curl -X POST "http://localhost:8000/api/v1/convert/latex-to-omml" \
  -H "Content-Type: application/json" \
  -d '{"latex": "\\begin{pmatrix} a \\\\ \\vdots \\\\ z \\end{pmatrix}"}'

3. 前端测试

如果后端测试通过但前端仍有问题,检查:

  1. 浏览器开发者工具 → Network: 查看 API 响应内容
  2. 浏览器开发者工具 → Elements: 检查渲染的 DOM 结构
  3. 控制台: 查看是否有 JavaScript 错误
  4. MathJax/KaTeX 配置: 确认渲染库正确加载

结论

问题根源

不是前端二次处理问题,而是后端 MathML 后处理中 Unicode 实体映射不完整。

修复效果

通过扩展 Unicode 实体映射表:

  • 支持所有常用希腊字母(大小写)
  • 支持所有省略号符号(\vdots, \cdots, \ddots 等)
  • 支持 50+ 个数学符号
  • 同时处理十六进制和十进制实体编码
  • 性能影响极小(简单字符串替换)

后续建议

  1. 运行测试: 确认修复生效
  2. 部署更新: 将修改部署到生产环境
  3. 监控日志: 观察是否还有其他未映射的字符
  4. 按需扩展: 如果发现新的未支持字符,继续扩展映射表

附录: 诊断工具使用

diagnose_latex_rendering.py

用途: 诊断 OCR 后处理是否修改了 LaTeX 输入

示例:

# 测试单个字符
python diagnose_latex_rendering.py "$\lambda$"

# 测试组合
python diagnose_latex_rendering.py "$$\lambda_1, \lambda_2, \vdots, \lambda_n$$"

# 测试矩阵
python diagnose_latex_rendering.py "$\begin{pmatrix} a \\ \vdots \\ z \end{pmatrix}$"

test_unicode_fix.py

用途: 验证 Unicode 实体映射和完整转换流程

示例:

python test_unicode_fix.py

输出:

  • Unicode 实体映射测试结果
  • 完整 LaTeX 转换测试结果
  • 字符检测统计

参考资料