Imported from EdwardS201/MySkillLibrary (
formula-image-to-word/SKILL.md). Install upstream withnpx skills add EdwardS201/MySkillLibrary --skill formula-image-to-word. Copyright stays with the author.
图片公式 → Word 原生公式:流程文档
用途 (When to use)
把"以图片形式存在的数学公式"批量转成 Word 原生可编辑公式 (OMML)。两种起点都适用:
- 起点 A:一份内嵌公式图片的
.docx(需先抽图,走步骤 0)。 - 起点 B:目录里已经是一批独立公式 PNG(直接从步骤 1 开始)。
前置条件
- Pandoc(必需,做 LaTeX→OMML 的引擎;建议 ≥ 3.x)。
- 图片 → LaTeX 的识别能力(二选一):
- 多模态模型直接读图——本项目采用此方式(Claude 等有视觉能力的模型);
- 或 专用数学 OCR 工具(Mathpix API / pix2tex / LaTeX-OCR)——当使用无视觉能力的模型或纯脚本流水线时必需。
- 可选:System.Drawing 或任意图像库,用于读取像素宽度以设置缩略图尺寸。
- Python 视情况:主流程(多模态读图)与纯脚本方案 B(Mathpix)都不需要 Python;仅纯脚本方案 A(pix2tex 本地 OCR)需要 Python。
全流程总览
[.docx] --(0 解压抽图)--> word/media/*.png
|
PNG 图片 --(1 识别: 多模态读图 / 或专用数学OCR)--> imageNN|||<latex> (UTF-8 数据文件, 真源)
|
--(2 生成 Markdown 中间层)--> formulas.md
每条 = 文件名标注 + 原图嵌入 + $latex$
|
--(3 Pandoc)--> output.docx ($...$ → <m:oMath> 原生公式)
|
--(4 校验)--> 解 zip 数 <m:oMath> / <w:drawing> / media
步骤详解
步骤 0(可选):从源 .docx 抽取图片
.docx 本质是 ZIP。
- 复制一份,改名
.docx→.zip(或直接用解压工具打开)。 - 内嵌图片在
word/media/下(image1.png,image2.png…)。 - 拷到独立工作目录。
⚠️
word/media里的编号顺序 不一定等于公式在文档中的出现顺序。若顺序重要,需按word/document.xml里的引用关系重排。 若起点已是独立 PNG(起点 B),跳过本步。
PowerShell 抽图示例:
Copy-Item .\source.docx .\source.zip
Expand-Archive -Path .\source.zip -DestinationPath .\_unzip -Force
New-Item -ItemType Directory -Force .\images | Out-Null
Copy-Item .\_unzip\word\media\*.png -Destination .\images\
步骤 1:识别每张图 → LaTeX
重要边界:本文档所说的"OCR"= 多模态模型直接读图,不是传统 OCR 引擎。 本项目上一次执行时,是由具备视觉能力的模型(Claude)通过读取工具把 PNG 作为图像读入、逐条手写成 LaTeX,没有调用任何独立 OCR 软件(未用 Mathpix / Tesseract / pix2tex)。据此决定步骤 1 的实现方式:
- 用 有视觉能力的多模态模型 复用 → 直接读图转写即可(本项目方式)。
- 用 无视觉能力的模型 / 纯脚本流水线 复用 → 本步必须替换为 专用数学 OCR(Mathpix API / pix2tex / LaTeX-OCR),否则整条链会在第一步断掉。落地命令见下文《纯脚本路线(无视觉模型)》一节。
- 两种方式都可能在下标/上标等细节上出错,因此步骤 2 坚持嵌入原图供人工核对(见附录 C)。
- 每张图输出一段 LaTeX(本项目由多模态模型读图完成)。
- 落盘为数据文件,每行
文件名|||<latex>,UTF-8 编码:image13|||\dfrac{\partial S}{\partial t} image14|||\omega_B - \omega_{S_1} - 为什么单独存数据文件:它是"真源"(source of truth)——改一条重跑即可,不必重新 OCR;也便于人工复核、版本对比、跨会话续跑。
- LaTeX 必须落在 Pandoc texmath 支持子集 内(见附录 A)。
步骤 2:生成 Markdown 中间层(关键步骤)
这是把"公式 + 原图 + 标注"一次性交给 Pandoc 的桥梁。逐条生成,每条三块:
**image13.png**
{width=2.10in}
$\dfrac{\partial S}{\partial t}$
- 文件名标注:
**imageNN.png**;若改用### imageNN.png标题,Word 里可生成可跳转的导航目录/大纲。 - 原图嵌入:
{width=X.XXin}—— 供人工核对 OCR 是否正确。- 路径用 正斜杠
/+ 绝对路径,最稳(反斜杠会被当转义)。 - 宽度建议
width = min(像素宽 / 150, 6.0)英寸(上限 6in,下限约 0.30in)。
- 路径用 正斜杠
- 公式本体:行内用
$...$;独立成行/大公式用$$...$$(本项目gen.ps1用$$...$$)。 - 为什么要 Markdown 中间层,而不是把裸 LaTeX 直接喂 Pandoc:
- Pandoc 一趟就能同时产出"原生公式 + 嵌图 + 标注"。
formulas.md是 人可读、可编辑 的中间产物,最终渲染前能直接改。- 出错时定位在 md 层,成本低。
步骤 3:Pandoc Markdown → docx
pandoc formulas.md -o output.docx
$...$/$$...$$→ 原生<m:oMath>公式(在 Word 里可点开编辑)。![]()引用的图片被打包进 docx 的word/media/。
步骤 4:校验(docx 也是 ZIP)
用 System.IO.Compression 打开 docx,正则统计并核对:
<m:oMath数量 == 公式条数?<w:drawing数量 == 嵌图数量?word/media/文件数 == 图片数量?- 不得 残留
begin{/aligned/dfrac等字样 —— 若出现,说明该处 LaTeX 未被转成 OMML(越界或语法错),需回步骤 1 修数据文件重跑。
纯脚本路线(无视觉模型)
适用场景:不依赖多模态模型,仅用脚本把公式 PNG 转成 Word 原生公式。
关键点:只有步骤 1 变——由脚本调用专用数学 OCR 生成 imageNN|||<latex> 数据文件;步骤 2 / 3 / 4 与主流程逐字复用。
PNG 图片 --(1' 脚本调用数学OCR)--> imageNN|||<latex>
--> [步骤2 gen.ps1] --> formulas.md
--> [步骤3 pandoc] --> output.docx
--> [步骤4 校验]
在下面两个引擎里 选一个 实现步骤 1。随附的可运行脚本见文末《附带脚本》。
方案 A(推荐:本地、离线、免费):pix2tex / LaTeX-OCR
Python 包,本地跑,不联网、无需 API key。
- 安装(会一并拉取 PyTorch,首次下载较大,约 1–2 GB):
python -m pip install "pix2tex[cli]"⚠️ 若
python打开应用商店或无输出退出,它是 Windows 应用执行别名(Store stub);改用真实解释器完整路径,例如 Anaconda:& 'D:\ProgramData\anaconda\python.exe' -m pip install "pix2tex[cli]"(见附录 B)。装了 uv 亦可uv pip install。 首次运行会自动下载模型权重。 - 用随附的
ocr_batch.py(图片目录 → 数据文件;支持--limit/--only/--out)。核心逻辑:from pix2tex.cli import LatexOCR from PIL import Image model = LatexOCR() latex = model(Image.open("image13.png")) # -> LaTeX 字符串 - 运行(可先加
--limit 3小样验证):& 'D:\ProgramData\anaconda\python.exe' .\_build\ocr_batch.py --limit 3 --out .\_build\formulas_sample.txt
方案 B(无 Python:纯 PowerShell):Mathpix API
仅需网络 + API key,不装 Python;精度高,但按量付费。用随附的 ocr_mathpix.ps1。
⚠️ 安全:App ID / Key 只能从 环境变量 读,严禁写进脚本或提交到 Git(见
rules/security.md)。先设置:$env:MATHPIX_APP_ID = "<your_app_id>" $env:MATHPIX_APP_KEY = "<your_app_key>"
核心是对每张图 POST 到 https://api.mathpix.com/v3/text(body 含 base64 图与 formats:["latex_styled"]),取 resp.latex_styled 写入数据文件。
之后:与主流程完全一致
拿到 OCR 数据文件(ocr_batch.py 默认写 _build/formulas_data_ocr.txt)后,接回步骤 2–4:
.\_build\gen.ps1 -DataFiles .\_build\formulas_data_ocr.txt -OutFile .\formulas.md # 步骤 2
pandoc .\formulas.md -o .\output.docx # 步骤 3
# 步骤 4:解 zip 校验 <m:oMath>/<w:drawing>/media 数量,检查无 begin{ / aligned / dfrac 残留
gen.ps1不带参数时读本项目既有的formulas_data*.txt(那 100 条已人工核对的公式);带-DataFiles/-OutFile时用你指定的输入/输出,二者互不干扰。
纯脚本路线的必做校验
数学 OCR 不是零错误,落地前务必:
- 越界构造:OCR 可能输出 Pandoc texmath 不支持的写法(个别
\operatorname、非常规环境)→ 步骤 4 会看到begin{等残留,回改数据文件。 - 下标/上标误识:仍可能错(
ω_ivsω_1)→ 步骤 2 已嵌入原图,人工过一遍即可(见附录 C)。 - 先小样后批量:先拿 3–5 张图跑通全链,确认 docx 里公式可编辑,再全量跑。
引擎对比
| 引擎 | 依赖 | 联网 | 费用 | 精度 |
|---|---|---|---|---|
| pix2tex / LaTeX-OCR | Python + PyTorch | 首次下权重需,之后否 | 免费 | 中上 |
| Mathpix API | 仅 PowerShell | 是 | 按量付费 | 高 |
| texify | Python + PyTorch | 首次下权重需,之后否 | 免费 | 中上 |
附录 A:Pandoc texmath 已验证可用构造
\begin{aligned}、\begin{cases}、\begin{bmatrix}、\dfrac、\triangleq、\mathbf、\mathrm、\overline、\varphi、\partial、\mid,以及常规上下标、希腊字母等。
越界的 LaTeX 会原样漏进文档正文(步骤 4 的校验会抓到)。
附录 B:Windows 上的两个脚本陷阱(务必注意)
B1 — PowerShell 5.1 编码坑。 PowerShell 5.1 会把 无 BOM 的 UTF-8 .ps1 当成 ANSI/GBK 读,导致脚本里的中文(路径、标题)乱码 → 连锁解析报错。规避:
.ps1脚本体 只用 ASCII;- 路径用
$PSScriptRoot推导,别在脚本里硬写中文路径; - 所有中文文案放进 UTF-8 数据文件,用
Get-Content -Encoding UTF8读入; - 写出
.md用[System.IO.File]::WriteAllText($path, $text, (New-Object System.Text.UTF8Encoding($false)))(UTF-8 无 BOM)。
B2 — python 应用执行别名 stub。 若 python 指向 ...\AppData\Local\Microsoft\WindowsApps\python.exe(版本 0.0.0.0),那是 Windows 应用执行别名 stub,会静默退出(本机实测 exit 49、无输出),并非真解释器;py 启动器在本机也不存在。用真实解释器完整路径调用(本机为 D:\ProgramData\anaconda\python.exe),或在「设置 → 应用 → 应用执行别名」关掉 python 的别名。
附录 C:OCR 复核纪律
下标/上标最易错(如 ω_i vs ω_1、α_1)。因此 保留原图嵌入是刻意设计——让人一眼比对。识别有歧义处,应在交付时显式标注出来,而不是默默选一个。
附带脚本(bundled scripts)
本流程随附三个脚本(本项目在 _build/;作为 skill 时在 scripts/):
gen.ps1— 步骤 2 生成器。读一份或多份*_data.txt→ 按文件名数字排序 → 用 System.Drawing 算每张缩略图宽度 → 输出 Markdown(UTF-8 无 BOM)。- 无参:读本项目既有
formulas_data*.txt→ 写../formulas.md。 -DataFiles <f1,f2,…>:指定输入数据文件;-OutFile <path>:指定输出;-HeaderFile <path>:可选表头(不存在则跳过)。
- 无参:读本项目既有
ocr_batch.py— 纯脚本方案 A(pix2tex 本地 OCR)。参数:--img-dir(默认项目根)、--out(默认_build/formulas_data_ocr.txt)、--limit N、--only image13,image31。ocr_mathpix.ps1— 纯脚本方案 B(Mathpix API,纯 PowerShell)。参数:-ImgDir/-Out/-Limit/-Only;密钥从MATHPIX_APP_ID/MATHPIX_APP_KEY环境变量读,不硬编码。