dsh-formula-docx
Turn Markdown into a .docx whose equations are real Word equation objects
(OMML) — double-clickable and editable in Word, correct in WPS, sharp in PDF.
把 Markdown 变成公式是 Word 原生公式对象(OMML)的 .docx:在 Word 里可双击编辑,
WPS 正常打开,导出 PDF 不糊。不是公式图片,也不是上标下标拼出来的字。
https://github.com/Red-Rayux/dsh-formula-docx
安装:
dsh plugin add Red-Rayux/dsh-formula-docx
Why / 为什么
Documents with dozens of formulas are where normal Markdown-to-Word pipelines
fall apart: formulas arrive as images, or as x²-style character hacks, or as
LaTeX source that nobody can edit later.
公式密集的文档最容易在这一步翻车:公式变成图片、变成 x² 这种字符拼贴、
或者干脆留一堆 LaTeX 源码没人能改。
This plugin converts each formula through LaTeX → MathML → OMML and writes it
into the document as a native equation, then verifies the result by exporting a
PDF and looking at every page.
这个插件把每个公式走 LaTeX → MathML → OMML 转成原生公式写进文档,
再把文档导出 PDF 逐页看图校验。
Requirements / 依赖
| Need | Why |
|---|---|
| Python 3.9+ | runs the scripts |
pip install lxml latex2mathml python-docx |
conversion + docx writing |
MML2OMML.XSL |
ships with Microsoft Office; auto-detected, or set MML2OMML_XSL |
| Microsoft Word | only for the PDF preview pass (LibreOffice works as fallback) |
pip install pymupdf |
only for the preview pass |
Without Office you can still generate the docx — you just lose the visual check.
Quick start / 快速开始
pip install lxml latex2mathml python-docx pymupdf
# 1. smoke test first -- do not skip this
python scripts/build.py /tmp/smoke.docx examples/smoke.md
python scripts/check_docx.py /tmp/smoke.docx --md examples/smoke.md
python scripts/preview.py /tmp/smoke.docx
# 2. then build your own document
python scripts/build.py out.docx ch01.md ch02.md ch03.md --cover cover.json
# 3. verify
python scripts/check_docx.py out.docx --md ch0*.md --pdf out.pdf
python scripts/preview.py out.docx --dpi 120
build.py accepts one or more markdown files (or globs), joins them in order,
optionally adds a cover page and page numbers.
What it supports / 支持的语法
# Headings (h1 auto page-breaks)
**Bold with an inline formula $E=\pi L$ inside.**
$$R=\frac{\pi\left(L-L_P\right)}{T_\phi\left(T_\theta E_0\cos\theta+E_D\right)}$$
[w:20,30,50]
| Quantity | Definition | Unit |
|---|---|---|
| Radiance | flux per projected area per solid angle | $\mathrm{W\cdot m^{-2}\cdot sr^{-1}}$ |
::: core
**Callout block** — holds paragraphs, lists, and display formulas.
:::
Full reference: references/syntax.md.
The six traps / 六个坑
Every one of these was hit in production, and each has a fix:
- A formula that appears twice renders as an empty box the second time —
the OMML node gets moved out of its first parent. Cache with
deepcopy. ns0:prefixes appear indocument.xmland WPS rejects the file — declarensmapat element creation, neversetxmlns on a live node.- Chinese characters inside
\text{}break the conversion — move the words out of the formula. - Numbered lists restart at 1 when a formula interrupts them — render the original numbers from the Markdown.
**bold with $x$ inside**prints the raw$x$— the bold branch must recurse instead of emitting one run.\xrightarrowdoes not survive the OMML mapping — split into formula + sentence + formula.
Details and code: references/pitfalls.md.
Verification is part of the job / 校验是流程的一部分
check_docx.py compares the equation count in the docx against the LaTeX in
the markdown sources. If they differ, a formula was dropped or double-rendered —
both are silent failures that only show up as a blank box or a doubled formula.
preview.py exports a PDF through Word and renders every page to PNG.
Layout bugs (squeezed table columns, an orphaned heading, a callout split across
pages) are invisible in the XML and obvious in the image.
License
MIT
No comments yet. Be the first to write one.