mathtext2doc 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mathtext2doc-0.1.0/LICENSE +21 -0
- mathtext2doc-0.1.0/MANIFEST.in +5 -0
- mathtext2doc-0.1.0/PKG-INFO +328 -0
- mathtext2doc-0.1.0/README.md +296 -0
- mathtext2doc-0.1.0/SYNTAX_FOR_AI.md +884 -0
- mathtext2doc-0.1.0/mathtext2doc/__init__.py +12 -0
- mathtext2doc-0.1.0/mathtext2doc/__main__.py +5 -0
- mathtext2doc-0.1.0/mathtext2doc/cli.py +249 -0
- mathtext2doc-0.1.0/mathtext2doc/compiler.py +495 -0
- mathtext2doc-0.1.0/mathtext2doc/parser.py +809 -0
- mathtext2doc-0.1.0/mathtext2doc/plotter.py +775 -0
- mathtext2doc-0.1.0/mathtext2doc/texgen.py +228 -0
- mathtext2doc-0.1.0/mathtext2doc.egg-info/PKG-INFO +328 -0
- mathtext2doc-0.1.0/mathtext2doc.egg-info/SOURCES.txt +19 -0
- mathtext2doc-0.1.0/mathtext2doc.egg-info/dependency_links.txt +1 -0
- mathtext2doc-0.1.0/mathtext2doc.egg-info/entry_points.txt +2 -0
- mathtext2doc-0.1.0/mathtext2doc.egg-info/requires.txt +4 -0
- mathtext2doc-0.1.0/mathtext2doc.egg-info/top_level.txt +1 -0
- mathtext2doc-0.1.0/pyproject.toml +47 -0
- mathtext2doc-0.1.0/requirements.txt +4 -0
- mathtext2doc-0.1.0/setup.cfg +4 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 HelloWorld-b
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mathtext2doc
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: 把 AI 生成的数学文本快速转成带公式和函数图像的文档图片
|
|
5
|
+
Author-email: HelloWorld-b <lizhengxu0325@qq.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/HelloWorld-b/LaTeX-tool
|
|
8
|
+
Project-URL: Repository, https://github.com/HelloWorld-b/LaTeX-tool
|
|
9
|
+
Project-URL: Issues, https://github.com/HelloWorld-b/LaTeX-tool/issues
|
|
10
|
+
Keywords: latex,math,markdown,cli,education,chinese,plot,documentation
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: Education
|
|
14
|
+
Classifier: Intended Audience :: Science/Research
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Topic :: Education
|
|
21
|
+
Classifier: Topic :: Scientific/Engineering :: Mathematics
|
|
22
|
+
Classifier: Topic :: Text Processing :: Markup :: LaTeX
|
|
23
|
+
Classifier: Topic :: Utilities
|
|
24
|
+
Requires-Python: >=3.10
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
License-File: LICENSE
|
|
27
|
+
Requires-Dist: matplotlib>=3.5
|
|
28
|
+
Requires-Dist: numpy>=1.20
|
|
29
|
+
Requires-Dist: sympy>=1.10
|
|
30
|
+
Requires-Dist: PyMuPDF>=1.23
|
|
31
|
+
Dynamic: license-file
|
|
32
|
+
|
|
33
|
+
# mathtext2doc
|
|
34
|
+
|
|
35
|
+
把 AI 生成的数学文本快速转成带公式和函数图像的文档图片。
|
|
36
|
+
|
|
37
|
+
本工具是一个 **本地 CLI**,不调用任何 LLM,不上传用户文本。它解析一份 UTF-8 纯文本
|
|
38
|
+
(含中文、基础 Markdown、`$...$` / `$$...$$` LaTeX 公式、`@plot{...}` 绘图指令),
|
|
39
|
+
绘制其中的函数图,生成完整 `.tex` 文件,调用本机 LaTeX 发行版编译,并输出整篇文档
|
|
40
|
+
渲染后的 PNG(多页则多张)。
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## 一、安装依赖
|
|
45
|
+
|
|
46
|
+
### 1. Python 依赖
|
|
47
|
+
|
|
48
|
+
要求 Python ≥ 3.10。
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
pip install matplotlib numpy sympy PyMuPDF
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
> `PyMuPDF` 是 PDF→PNG 转换的默认引擎(纯 Python wheel,无系统依赖)。若不装,工具会自动回退到命令行工具 `pdftoppm`/`pdftocairo`/`convert`。
|
|
55
|
+
|
|
56
|
+
### 2. LaTeX 发行版
|
|
57
|
+
|
|
58
|
+
需要本机已安装以下之一:
|
|
59
|
+
|
|
60
|
+
- **TeX Live**(推荐,Linux/macOS/Windows):https://www.tug.org/texlive/
|
|
61
|
+
- **MiKTeX**(Windows):https://miktex.org/
|
|
62
|
+
- **MacTeX**(macOS):https://www.tug.org/mactex/
|
|
63
|
+
|
|
64
|
+
必须包含 **`xelatex`**(用于中文支持,搭配 `ctex` / `xeCJK` 宏包)。
|
|
65
|
+
TeX Live 默认安装会带上 `ctex`;MiKTeX 在首次编译时会自动下载缺少的宏包。
|
|
66
|
+
|
|
67
|
+
验证:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
xelatex --version
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### 3. PDF→PNG 转换工具(可选)
|
|
74
|
+
|
|
75
|
+
工具会按以下优先级**自动选择**可用的 PDF→PNG 引擎,前一个不可用就回退到下一个:
|
|
76
|
+
|
|
77
|
+
| 优先级 | 工具 | 类型 | 安装方式 |
|
|
78
|
+
|---|---|---|---|
|
|
79
|
+
| 1 | **PyMuPDF** | 纯 Python 库(推荐) | `pip install PyMuPDF` |
|
|
80
|
+
| 2 | `pdftoppm` | 命令行(poppler-utils) | `apt-get install poppler-utils` / `brew install poppler` |
|
|
81
|
+
| 3 | `pdftocairo` | 命令行(poppler-utils) | 同上 |
|
|
82
|
+
| 4 | `convert` | 命令行(ImageMagick) | `apt-get install imagemagick` / `brew install imagemagick` |
|
|
83
|
+
|
|
84
|
+
**推荐**:直接 `pip install PyMuPDF` 即可,无需任何系统依赖。只有在 PyMuPDF 不可用时才需要装 poppler-utils 或 ImageMagick。
|
|
85
|
+
|
|
86
|
+
验证:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
python -c "import fitz; print('PyMuPDF', fitz.__doc__)" # 优先
|
|
90
|
+
pdftoppm -v # 回退 1
|
|
91
|
+
pdftocairo -v # 回退 2
|
|
92
|
+
convert -version # 回退 3
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
> **ImageMagick 注意**:默认 `policy.xml` 会限制 PDF 读取,可能需要把 `<policy domain="coder" rights="none" pattern="PDF" />` 改为 `rights="read|write"`。
|
|
96
|
+
|
|
97
|
+
### 4. 中文字体
|
|
98
|
+
|
|
99
|
+
`ctex` 默认会自动选用系统已有的中文字体。Linux 上推荐安装 Noto Sans CJK SC:
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
sudo apt-get install fonts-noto-cjk
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## 二、CLI 参数
|
|
108
|
+
|
|
109
|
+
```
|
|
110
|
+
usage: mathtext2doc [-h] [--compiler {xelatex,lualatex,pdflatex}]
|
|
111
|
+
[--dpi DPI] [--keep-intermediates | --no-keep-intermediates]
|
|
112
|
+
[--overwrite] [--version]
|
|
113
|
+
input
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
| 参数 | 说明 | 默认 |
|
|
117
|
+
| --- | --- | --- |
|
|
118
|
+
| `input` | 输入文件路径(UTF-8 纯文本) | 必填 |
|
|
119
|
+
| `--compiler` | 指定 LaTeX 编译器:`xelatex` / `lualatex` / `pdflatex` | 自动选择(优先 `xelatex`) |
|
|
120
|
+
| `--dpi` | 目标有效 DPI(每英寸显示长度的像素数)。实际 savefig DPI 会根据每个 `@plot` 的显示宽度自动调整,保持有效分辨率一致 | `150` |
|
|
121
|
+
| `--plot-width` | 函数图在文档中的宽度(相对于 `\paperwidth`,0~1) | `0.7` |
|
|
122
|
+
| `--keep-intermediates` | 保留函数图 PNG 和 `.log`/`.pdf`/`.aux` 等中间文件 | 默认开启 |
|
|
123
|
+
| `--no-keep-intermediates` | 不保留中间文件(仅保留最终 PNG 和 `.tex`) | — |
|
|
124
|
+
| `--overwrite` | 覆盖已有输出文件 | 默认不覆盖 |
|
|
125
|
+
| `--version` | 打印版本号 | — |
|
|
126
|
+
|
|
127
|
+
### 退出码
|
|
128
|
+
|
|
129
|
+
| 码 | 含义 |
|
|
130
|
+
| --- | --- |
|
|
131
|
+
| 0 | 成功 |
|
|
132
|
+
| 1 | 解析错误(Markdown / LaTeX / `@plot` 语法) |
|
|
133
|
+
| 2 | 绘图错误(表达式无法解析、定义域问题等) |
|
|
134
|
+
| 3 | LaTeX 编译错误 |
|
|
135
|
+
| 4 | 输入/输出错误(文件不存在、输出已存在等) |
|
|
136
|
+
| 5 | 其它未预期错误 |
|
|
137
|
+
|
|
138
|
+
### 用法示例
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
# 最简用法
|
|
142
|
+
python -m mathtext2doc input.txt
|
|
143
|
+
|
|
144
|
+
# 指定编译器和 DPI
|
|
145
|
+
python -m mathtext2doc input.txt --compiler xelatex --dpi 200
|
|
146
|
+
|
|
147
|
+
# 调整函数图在文档中的宽度(默认 0.7 = 页面宽度的 70%)
|
|
148
|
+
python -m mathtext2doc input.txt --plot-width 0.5
|
|
149
|
+
|
|
150
|
+
# 覆盖已有输出
|
|
151
|
+
python -m mathtext2doc input.txt --overwrite
|
|
152
|
+
|
|
153
|
+
# 仅保留最终 PNG 和 .tex,清理中间文件
|
|
154
|
+
python -m mathtext2doc input.txt --no-keep-intermediates
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## 三、输入语法
|
|
160
|
+
|
|
161
|
+
### 1. Markdown 子集
|
|
162
|
+
|
|
163
|
+
| 语法 | 含义 |
|
|
164
|
+
| --- | --- |
|
|
165
|
+
| `# 标题` | 一级标题 → `\section{}` |
|
|
166
|
+
| `## 标题` | 二级标题 → `\subsection{}` |
|
|
167
|
+
| `- 文字` | 无序列表项 → `itemize` |
|
|
168
|
+
| `**文字**` | 粗体 → `\textbf{}` |
|
|
169
|
+
| `` `代码` `` | 行内代码 → `\texttt{}` |
|
|
170
|
+
| `\| a \| b \|` 表格 | 基础 Markdown 表格 → `tabular` + `booktabs` |
|
|
171
|
+
|
|
172
|
+
> 普通文本中的 LaTeX 特殊字符(`# $ % & _ { } ~ ^ \`)会自动转义;公式区域保留原样。
|
|
173
|
+
|
|
174
|
+
### 2. LaTeX 公式
|
|
175
|
+
|
|
176
|
+
- **行内公式**:`$...$`,例如 `$e^{i\pi} + 1 = 0$`
|
|
177
|
+
- **块级公式**:`$$...$$`,独占一段,会渲染成 `equation*` 环境
|
|
178
|
+
|
|
179
|
+
公式内容原样传给 LaTeX,不做转义。
|
|
180
|
+
|
|
181
|
+
### 3. `@plot{...}` 绘图指令
|
|
182
|
+
|
|
183
|
+
格式:`@plot{ ... }`,内部用分号 `;` 分隔多个绘制项。
|
|
184
|
+
|
|
185
|
+
可选的宽度选项:`@plot(width=0.5){ ... }`,控制图在文档中的宽度(相对于 `\paperwidth`,0~1)。不指定时用全局默认(CLI `--plot-width`,默认 `0.7`)。
|
|
186
|
+
|
|
187
|
+
**显函数**(`y = f(x)`):
|
|
188
|
+
|
|
189
|
+
```
|
|
190
|
+
y = sin(x), x in [-pi, pi], label="sin(x)"
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
**隐函数**(`F(x, y) = 0`,必须指定 `y in [...]`):
|
|
194
|
+
|
|
195
|
+
```
|
|
196
|
+
x^2 + y^2 = 1, x in [-2, 2], y in [-2, 2], label="单位圆"
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
**多函数同图**(用 `;` 分隔,显隐可混合):
|
|
200
|
+
|
|
201
|
+
```
|
|
202
|
+
@plot{
|
|
203
|
+
y = sin(x), x in [-pi, pi], label="sin(x)";
|
|
204
|
+
y = cos(x), x in [-pi, pi], label="cos(x)";
|
|
205
|
+
x^2 + y^2 = 1, x in [-1.5, 1.5], y in [-1.5, 1.5], label="单位圆"
|
|
206
|
+
}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
**单图指定宽度**:
|
|
210
|
+
|
|
211
|
+
```
|
|
212
|
+
@plot(width=0.5){
|
|
213
|
+
y = sin(x), x in [-pi, pi], label="sin(x)"
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
**几何图形**(`shape=...`):
|
|
218
|
+
|
|
219
|
+
```
|
|
220
|
+
@plot{
|
|
221
|
+
shape=circle, center=(0, 0), r=2, label="圆 C";
|
|
222
|
+
shape=point, at=(2, 0), label="P";
|
|
223
|
+
shape=segment, from=(0, 0), to=(2, 0), label="半径 r"
|
|
224
|
+
}
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
支持的几何图形:`point`、`segment`、`line`、`circle`、`ellipse`、`polygon`、`rectangle`、`vector`、`parabola`。详见 [SYNTAX_FOR_AI.md](./SYNTAX_FOR_AI.md) 第 4.10 节。
|
|
228
|
+
|
|
229
|
+
**规则**:
|
|
230
|
+
|
|
231
|
+
- **定义域必须由用户指定**(函数曲线);几何图形的定义域可选(自动估算)。
|
|
232
|
+
- `label` 可选,支持中文。
|
|
233
|
+
- `label` 默认标注在曲线可见部分的几何中点(按弧长)偏上;几何图形标签锚点因形状而异。
|
|
234
|
+
- 多个标签之间会自动避让(基于 bbox 重叠检测的螺旋外扩算法)。
|
|
235
|
+
- 颜色自动按循环分配。
|
|
236
|
+
- 支持的初等函数 / 常量:`+ - * / ^`、`sin`、`cos`、`tan`、`log`(自然对数)、`ln`、`exp`、`sqrt`、`abs`、`pi`、`e`。
|
|
237
|
+
- 区间 `[a, b]` 中的 `a`、`b` 可以是数字或简单表达式(`pi`、`pi/2`、`-pi`、`2*pi` 等)。
|
|
238
|
+
- 图宽控制:`@plot(width=0.x)` 单图覆盖,或 CLI `--plot-width 0.x` 全局默认。
|
|
239
|
+
|
|
240
|
+
---
|
|
241
|
+
|
|
242
|
+
## 四、输出文件命名
|
|
243
|
+
|
|
244
|
+
设输入文件为 `foo.txt`,输出目录与输入同级:
|
|
245
|
+
|
|
246
|
+
| 文件 | 含义 |
|
|
247
|
+
| --- | --- |
|
|
248
|
+
| `foo.tex` | 生成的完整 LaTeX 文件 |
|
|
249
|
+
| `foo-plot1.png`、`foo-plot2.png` … | 各 `@plot` 的函数图(作为 `\includegraphics` 嵌入 .tex) |
|
|
250
|
+
| `foo.pdf` | LaTeX 编译产物(保留中间文件时) |
|
|
251
|
+
| `foo-1.png`、`foo-2.png` … | 最终整篇文档渲染后的 PNG(多页则多张) |
|
|
252
|
+
| `foo.log` | LaTeX 编译日志(保留中间文件时) |
|
|
253
|
+
| `foo.aux` 等 | LaTeX 其它中间文件(保留中间文件时) |
|
|
254
|
+
|
|
255
|
+
函数图默认宽度为 `0.7\paperwidth`(页面宽度的 70%),可通过 `@plot(width=0.x)` 单图覆盖或 CLI `--plot-width 0.x` 全局调整。
|
|
256
|
+
|
|
257
|
+
**Auto-DPI**:每个函数图 PNG 的实际像素尺寸会根据其显示宽度自动调整,保持有效分辨率一致(默认 150 DPI)。大图(如 `width=0.9`)会渲染更多像素,小图(如 `width=0.4`)渲染更少像素,避免大图糊或小图浪费。savefig DPI 范围 `[80, 400]`,极端宽度会触底/触顶保护。
|
|
258
|
+
|
|
259
|
+
---
|
|
260
|
+
|
|
261
|
+
## 五、编译策略
|
|
262
|
+
|
|
263
|
+
1. **优先尝试直接 PNG 输出**:检测 `latex` + `dvipng`,若源文件不含中文,尝试 `latex` → DVI → `dvipng` PNG。该路径不依赖 `xelatex`,但**不支持中文**,所以含中文时直接跳过。
|
|
264
|
+
2. **回退到 PDF→PNG**:调用 `xelatex` 编译 `.tex` 生成 PDF,再用 PyMuPDF(优先)/ `pdftoppm` / `pdftocairo` / ImageMagick `convert` 把 PDF 按页转 PNG。
|
|
265
|
+
3. **多页输出**:PDF 有几页就输出几张 PNG,命名为 `foo-1.png`、`foo-2.png` …
|
|
266
|
+
4. **失败处理**:编译失败时保留 `.tex`、`.log`、`.pdf`(若有),输出清晰错误信息(含编译器、文件路径、日志末尾 40 行)。
|
|
267
|
+
|
|
268
|
+
---
|
|
269
|
+
|
|
270
|
+
## 六、已知限制
|
|
271
|
+
|
|
272
|
+
1. **不支持 3D 绘图**。`@plot` 仅处理 2D 显函数和隐函数;3D 留待后续扩展。
|
|
273
|
+
2. **不调用 LLM**,只处理 AI 已生成的文本;不做 OCR、不做公式识别、不做符号求解。
|
|
274
|
+
3. **不做自动定义域推断**:用户必须在 `@plot` 中显式给出 `x in [...]`(隐函数还要 `y in [...]`)。
|
|
275
|
+
4. **Markdown 支持范围有限**:仅支持 `#`、`##`、`-`、`**bold**`、`` `code` ``、基础表格。不支持图片、链接、引用块、代码块、嵌套列表、有序列表等。
|
|
276
|
+
5. **表格列对齐**:所有列默认左对齐(`lll...`),不解析 `:---:` 等对齐语法。
|
|
277
|
+
6. **标签避让为启发式算法**:极端密集场景(如 10 条曲线挤在一起)可能仍有重叠;标签会尽量沿 8 个方向螺旋外扩,找不到无重叠位置时会保留最后位置。
|
|
278
|
+
7. **隐函数绘制基于 `contour` 等高线**:对于不可定向、自相交或非常陡峭的隐函数曲线,可能出现锯齿或断点。
|
|
279
|
+
8. **`xelatex` 编译较慢**:首次编译 ctex 文档可能需要 10–30 秒;后续会因 `.aux` 缓存稍快。
|
|
280
|
+
9. **`ImageMagick` 默认禁用 PDF 读取**:若只能用 `convert`,需手动修改 `/etc/ImageMagick-6/policy.xml` 把 `<policy domain="coder" rights="none" pattern="PDF" />` 改为 `rights="read|write"`。
|
|
281
|
+
10. **行内公式不能跨行**:`$...$` 必须在同一行内闭合;`$$...$$` 可以跨多行。
|
|
282
|
+
11. **不支持自定义 LaTeX 模板**:文档结构固定为 `ctexart` + `geometry` + `amsmath` + `graphicx` + `booktabs`。
|
|
283
|
+
|
|
284
|
+
---
|
|
285
|
+
|
|
286
|
+
## 七、项目结构
|
|
287
|
+
|
|
288
|
+
```
|
|
289
|
+
mathtext2doc/
|
|
290
|
+
├── __init__.py # 包入口
|
|
291
|
+
├── __main__.py # python -m mathtext2doc 入口
|
|
292
|
+
├── cli.py # CLI 参数解析与主流程
|
|
293
|
+
├── parser.py # Markdown / LaTeX / @plot 解析
|
|
294
|
+
├── plotter.py # 显函数 / 隐函数 / 多函数同图 + 标签避让
|
|
295
|
+
├── texgen.py # .tex 生成
|
|
296
|
+
└── compiler.py # LaTeX 编译 + PDF→PNG 转换
|
|
297
|
+
examples/
|
|
298
|
+
└── sample_input.txt # 示例输入
|
|
299
|
+
README.md
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
---
|
|
303
|
+
|
|
304
|
+
## 八、快速验证
|
|
305
|
+
|
|
306
|
+
```bash
|
|
307
|
+
# 在项目根目录下
|
|
308
|
+
python -m mathtext2doc examples/sample_input.txt --overwrite
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
预期输出:
|
|
312
|
+
|
|
313
|
+
```
|
|
314
|
+
已生成 .../examples/sample_input.tex
|
|
315
|
+
使用编译器:xelatex
|
|
316
|
+
(已回退到 PDF→PNG 路径)
|
|
317
|
+
输出 PNG:
|
|
318
|
+
.../examples/sample_input-1.png
|
|
319
|
+
.../examples/sample_input-2.png
|
|
320
|
+
保留 PDF:.../examples/sample_input.pdf
|
|
321
|
+
保留日志:.../examples/sample_input.log
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
如果本机未装 LaTeX,会得到清晰的错误提示:
|
|
325
|
+
|
|
326
|
+
```
|
|
327
|
+
LaTeX 编译失败:未找到任何 LaTeX 编译器。请安装 TeX Live / MiKTeX / MacTeX,...
|
|
328
|
+
```
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
# mathtext2doc
|
|
2
|
+
|
|
3
|
+
把 AI 生成的数学文本快速转成带公式和函数图像的文档图片。
|
|
4
|
+
|
|
5
|
+
本工具是一个 **本地 CLI**,不调用任何 LLM,不上传用户文本。它解析一份 UTF-8 纯文本
|
|
6
|
+
(含中文、基础 Markdown、`$...$` / `$$...$$` LaTeX 公式、`@plot{...}` 绘图指令),
|
|
7
|
+
绘制其中的函数图,生成完整 `.tex` 文件,调用本机 LaTeX 发行版编译,并输出整篇文档
|
|
8
|
+
渲染后的 PNG(多页则多张)。
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## 一、安装依赖
|
|
13
|
+
|
|
14
|
+
### 1. Python 依赖
|
|
15
|
+
|
|
16
|
+
要求 Python ≥ 3.10。
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
pip install matplotlib numpy sympy PyMuPDF
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
> `PyMuPDF` 是 PDF→PNG 转换的默认引擎(纯 Python wheel,无系统依赖)。若不装,工具会自动回退到命令行工具 `pdftoppm`/`pdftocairo`/`convert`。
|
|
23
|
+
|
|
24
|
+
### 2. LaTeX 发行版
|
|
25
|
+
|
|
26
|
+
需要本机已安装以下之一:
|
|
27
|
+
|
|
28
|
+
- **TeX Live**(推荐,Linux/macOS/Windows):https://www.tug.org/texlive/
|
|
29
|
+
- **MiKTeX**(Windows):https://miktex.org/
|
|
30
|
+
- **MacTeX**(macOS):https://www.tug.org/mactex/
|
|
31
|
+
|
|
32
|
+
必须包含 **`xelatex`**(用于中文支持,搭配 `ctex` / `xeCJK` 宏包)。
|
|
33
|
+
TeX Live 默认安装会带上 `ctex`;MiKTeX 在首次编译时会自动下载缺少的宏包。
|
|
34
|
+
|
|
35
|
+
验证:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
xelatex --version
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### 3. PDF→PNG 转换工具(可选)
|
|
42
|
+
|
|
43
|
+
工具会按以下优先级**自动选择**可用的 PDF→PNG 引擎,前一个不可用就回退到下一个:
|
|
44
|
+
|
|
45
|
+
| 优先级 | 工具 | 类型 | 安装方式 |
|
|
46
|
+
|---|---|---|---|
|
|
47
|
+
| 1 | **PyMuPDF** | 纯 Python 库(推荐) | `pip install PyMuPDF` |
|
|
48
|
+
| 2 | `pdftoppm` | 命令行(poppler-utils) | `apt-get install poppler-utils` / `brew install poppler` |
|
|
49
|
+
| 3 | `pdftocairo` | 命令行(poppler-utils) | 同上 |
|
|
50
|
+
| 4 | `convert` | 命令行(ImageMagick) | `apt-get install imagemagick` / `brew install imagemagick` |
|
|
51
|
+
|
|
52
|
+
**推荐**:直接 `pip install PyMuPDF` 即可,无需任何系统依赖。只有在 PyMuPDF 不可用时才需要装 poppler-utils 或 ImageMagick。
|
|
53
|
+
|
|
54
|
+
验证:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
python -c "import fitz; print('PyMuPDF', fitz.__doc__)" # 优先
|
|
58
|
+
pdftoppm -v # 回退 1
|
|
59
|
+
pdftocairo -v # 回退 2
|
|
60
|
+
convert -version # 回退 3
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
> **ImageMagick 注意**:默认 `policy.xml` 会限制 PDF 读取,可能需要把 `<policy domain="coder" rights="none" pattern="PDF" />` 改为 `rights="read|write"`。
|
|
64
|
+
|
|
65
|
+
### 4. 中文字体
|
|
66
|
+
|
|
67
|
+
`ctex` 默认会自动选用系统已有的中文字体。Linux 上推荐安装 Noto Sans CJK SC:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
sudo apt-get install fonts-noto-cjk
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## 二、CLI 参数
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
usage: mathtext2doc [-h] [--compiler {xelatex,lualatex,pdflatex}]
|
|
79
|
+
[--dpi DPI] [--keep-intermediates | --no-keep-intermediates]
|
|
80
|
+
[--overwrite] [--version]
|
|
81
|
+
input
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
| 参数 | 说明 | 默认 |
|
|
85
|
+
| --- | --- | --- |
|
|
86
|
+
| `input` | 输入文件路径(UTF-8 纯文本) | 必填 |
|
|
87
|
+
| `--compiler` | 指定 LaTeX 编译器:`xelatex` / `lualatex` / `pdflatex` | 自动选择(优先 `xelatex`) |
|
|
88
|
+
| `--dpi` | 目标有效 DPI(每英寸显示长度的像素数)。实际 savefig DPI 会根据每个 `@plot` 的显示宽度自动调整,保持有效分辨率一致 | `150` |
|
|
89
|
+
| `--plot-width` | 函数图在文档中的宽度(相对于 `\paperwidth`,0~1) | `0.7` |
|
|
90
|
+
| `--keep-intermediates` | 保留函数图 PNG 和 `.log`/`.pdf`/`.aux` 等中间文件 | 默认开启 |
|
|
91
|
+
| `--no-keep-intermediates` | 不保留中间文件(仅保留最终 PNG 和 `.tex`) | — |
|
|
92
|
+
| `--overwrite` | 覆盖已有输出文件 | 默认不覆盖 |
|
|
93
|
+
| `--version` | 打印版本号 | — |
|
|
94
|
+
|
|
95
|
+
### 退出码
|
|
96
|
+
|
|
97
|
+
| 码 | 含义 |
|
|
98
|
+
| --- | --- |
|
|
99
|
+
| 0 | 成功 |
|
|
100
|
+
| 1 | 解析错误(Markdown / LaTeX / `@plot` 语法) |
|
|
101
|
+
| 2 | 绘图错误(表达式无法解析、定义域问题等) |
|
|
102
|
+
| 3 | LaTeX 编译错误 |
|
|
103
|
+
| 4 | 输入/输出错误(文件不存在、输出已存在等) |
|
|
104
|
+
| 5 | 其它未预期错误 |
|
|
105
|
+
|
|
106
|
+
### 用法示例
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
# 最简用法
|
|
110
|
+
python -m mathtext2doc input.txt
|
|
111
|
+
|
|
112
|
+
# 指定编译器和 DPI
|
|
113
|
+
python -m mathtext2doc input.txt --compiler xelatex --dpi 200
|
|
114
|
+
|
|
115
|
+
# 调整函数图在文档中的宽度(默认 0.7 = 页面宽度的 70%)
|
|
116
|
+
python -m mathtext2doc input.txt --plot-width 0.5
|
|
117
|
+
|
|
118
|
+
# 覆盖已有输出
|
|
119
|
+
python -m mathtext2doc input.txt --overwrite
|
|
120
|
+
|
|
121
|
+
# 仅保留最终 PNG 和 .tex,清理中间文件
|
|
122
|
+
python -m mathtext2doc input.txt --no-keep-intermediates
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## 三、输入语法
|
|
128
|
+
|
|
129
|
+
### 1. Markdown 子集
|
|
130
|
+
|
|
131
|
+
| 语法 | 含义 |
|
|
132
|
+
| --- | --- |
|
|
133
|
+
| `# 标题` | 一级标题 → `\section{}` |
|
|
134
|
+
| `## 标题` | 二级标题 → `\subsection{}` |
|
|
135
|
+
| `- 文字` | 无序列表项 → `itemize` |
|
|
136
|
+
| `**文字**` | 粗体 → `\textbf{}` |
|
|
137
|
+
| `` `代码` `` | 行内代码 → `\texttt{}` |
|
|
138
|
+
| `\| a \| b \|` 表格 | 基础 Markdown 表格 → `tabular` + `booktabs` |
|
|
139
|
+
|
|
140
|
+
> 普通文本中的 LaTeX 特殊字符(`# $ % & _ { } ~ ^ \`)会自动转义;公式区域保留原样。
|
|
141
|
+
|
|
142
|
+
### 2. LaTeX 公式
|
|
143
|
+
|
|
144
|
+
- **行内公式**:`$...$`,例如 `$e^{i\pi} + 1 = 0$`
|
|
145
|
+
- **块级公式**:`$$...$$`,独占一段,会渲染成 `equation*` 环境
|
|
146
|
+
|
|
147
|
+
公式内容原样传给 LaTeX,不做转义。
|
|
148
|
+
|
|
149
|
+
### 3. `@plot{...}` 绘图指令
|
|
150
|
+
|
|
151
|
+
格式:`@plot{ ... }`,内部用分号 `;` 分隔多个绘制项。
|
|
152
|
+
|
|
153
|
+
可选的宽度选项:`@plot(width=0.5){ ... }`,控制图在文档中的宽度(相对于 `\paperwidth`,0~1)。不指定时用全局默认(CLI `--plot-width`,默认 `0.7`)。
|
|
154
|
+
|
|
155
|
+
**显函数**(`y = f(x)`):
|
|
156
|
+
|
|
157
|
+
```
|
|
158
|
+
y = sin(x), x in [-pi, pi], label="sin(x)"
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
**隐函数**(`F(x, y) = 0`,必须指定 `y in [...]`):
|
|
162
|
+
|
|
163
|
+
```
|
|
164
|
+
x^2 + y^2 = 1, x in [-2, 2], y in [-2, 2], label="单位圆"
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
**多函数同图**(用 `;` 分隔,显隐可混合):
|
|
168
|
+
|
|
169
|
+
```
|
|
170
|
+
@plot{
|
|
171
|
+
y = sin(x), x in [-pi, pi], label="sin(x)";
|
|
172
|
+
y = cos(x), x in [-pi, pi], label="cos(x)";
|
|
173
|
+
x^2 + y^2 = 1, x in [-1.5, 1.5], y in [-1.5, 1.5], label="单位圆"
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
**单图指定宽度**:
|
|
178
|
+
|
|
179
|
+
```
|
|
180
|
+
@plot(width=0.5){
|
|
181
|
+
y = sin(x), x in [-pi, pi], label="sin(x)"
|
|
182
|
+
}
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
**几何图形**(`shape=...`):
|
|
186
|
+
|
|
187
|
+
```
|
|
188
|
+
@plot{
|
|
189
|
+
shape=circle, center=(0, 0), r=2, label="圆 C";
|
|
190
|
+
shape=point, at=(2, 0), label="P";
|
|
191
|
+
shape=segment, from=(0, 0), to=(2, 0), label="半径 r"
|
|
192
|
+
}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
支持的几何图形:`point`、`segment`、`line`、`circle`、`ellipse`、`polygon`、`rectangle`、`vector`、`parabola`。详见 [SYNTAX_FOR_AI.md](./SYNTAX_FOR_AI.md) 第 4.10 节。
|
|
196
|
+
|
|
197
|
+
**规则**:
|
|
198
|
+
|
|
199
|
+
- **定义域必须由用户指定**(函数曲线);几何图形的定义域可选(自动估算)。
|
|
200
|
+
- `label` 可选,支持中文。
|
|
201
|
+
- `label` 默认标注在曲线可见部分的几何中点(按弧长)偏上;几何图形标签锚点因形状而异。
|
|
202
|
+
- 多个标签之间会自动避让(基于 bbox 重叠检测的螺旋外扩算法)。
|
|
203
|
+
- 颜色自动按循环分配。
|
|
204
|
+
- 支持的初等函数 / 常量:`+ - * / ^`、`sin`、`cos`、`tan`、`log`(自然对数)、`ln`、`exp`、`sqrt`、`abs`、`pi`、`e`。
|
|
205
|
+
- 区间 `[a, b]` 中的 `a`、`b` 可以是数字或简单表达式(`pi`、`pi/2`、`-pi`、`2*pi` 等)。
|
|
206
|
+
- 图宽控制:`@plot(width=0.x)` 单图覆盖,或 CLI `--plot-width 0.x` 全局默认。
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
## 四、输出文件命名
|
|
211
|
+
|
|
212
|
+
设输入文件为 `foo.txt`,输出目录与输入同级:
|
|
213
|
+
|
|
214
|
+
| 文件 | 含义 |
|
|
215
|
+
| --- | --- |
|
|
216
|
+
| `foo.tex` | 生成的完整 LaTeX 文件 |
|
|
217
|
+
| `foo-plot1.png`、`foo-plot2.png` … | 各 `@plot` 的函数图(作为 `\includegraphics` 嵌入 .tex) |
|
|
218
|
+
| `foo.pdf` | LaTeX 编译产物(保留中间文件时) |
|
|
219
|
+
| `foo-1.png`、`foo-2.png` … | 最终整篇文档渲染后的 PNG(多页则多张) |
|
|
220
|
+
| `foo.log` | LaTeX 编译日志(保留中间文件时) |
|
|
221
|
+
| `foo.aux` 等 | LaTeX 其它中间文件(保留中间文件时) |
|
|
222
|
+
|
|
223
|
+
函数图默认宽度为 `0.7\paperwidth`(页面宽度的 70%),可通过 `@plot(width=0.x)` 单图覆盖或 CLI `--plot-width 0.x` 全局调整。
|
|
224
|
+
|
|
225
|
+
**Auto-DPI**:每个函数图 PNG 的实际像素尺寸会根据其显示宽度自动调整,保持有效分辨率一致(默认 150 DPI)。大图(如 `width=0.9`)会渲染更多像素,小图(如 `width=0.4`)渲染更少像素,避免大图糊或小图浪费。savefig DPI 范围 `[80, 400]`,极端宽度会触底/触顶保护。
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
## 五、编译策略
|
|
230
|
+
|
|
231
|
+
1. **优先尝试直接 PNG 输出**:检测 `latex` + `dvipng`,若源文件不含中文,尝试 `latex` → DVI → `dvipng` PNG。该路径不依赖 `xelatex`,但**不支持中文**,所以含中文时直接跳过。
|
|
232
|
+
2. **回退到 PDF→PNG**:调用 `xelatex` 编译 `.tex` 生成 PDF,再用 PyMuPDF(优先)/ `pdftoppm` / `pdftocairo` / ImageMagick `convert` 把 PDF 按页转 PNG。
|
|
233
|
+
3. **多页输出**:PDF 有几页就输出几张 PNG,命名为 `foo-1.png`、`foo-2.png` …
|
|
234
|
+
4. **失败处理**:编译失败时保留 `.tex`、`.log`、`.pdf`(若有),输出清晰错误信息(含编译器、文件路径、日志末尾 40 行)。
|
|
235
|
+
|
|
236
|
+
---
|
|
237
|
+
|
|
238
|
+
## 六、已知限制
|
|
239
|
+
|
|
240
|
+
1. **不支持 3D 绘图**。`@plot` 仅处理 2D 显函数和隐函数;3D 留待后续扩展。
|
|
241
|
+
2. **不调用 LLM**,只处理 AI 已生成的文本;不做 OCR、不做公式识别、不做符号求解。
|
|
242
|
+
3. **不做自动定义域推断**:用户必须在 `@plot` 中显式给出 `x in [...]`(隐函数还要 `y in [...]`)。
|
|
243
|
+
4. **Markdown 支持范围有限**:仅支持 `#`、`##`、`-`、`**bold**`、`` `code` ``、基础表格。不支持图片、链接、引用块、代码块、嵌套列表、有序列表等。
|
|
244
|
+
5. **表格列对齐**:所有列默认左对齐(`lll...`),不解析 `:---:` 等对齐语法。
|
|
245
|
+
6. **标签避让为启发式算法**:极端密集场景(如 10 条曲线挤在一起)可能仍有重叠;标签会尽量沿 8 个方向螺旋外扩,找不到无重叠位置时会保留最后位置。
|
|
246
|
+
7. **隐函数绘制基于 `contour` 等高线**:对于不可定向、自相交或非常陡峭的隐函数曲线,可能出现锯齿或断点。
|
|
247
|
+
8. **`xelatex` 编译较慢**:首次编译 ctex 文档可能需要 10–30 秒;后续会因 `.aux` 缓存稍快。
|
|
248
|
+
9. **`ImageMagick` 默认禁用 PDF 读取**:若只能用 `convert`,需手动修改 `/etc/ImageMagick-6/policy.xml` 把 `<policy domain="coder" rights="none" pattern="PDF" />` 改为 `rights="read|write"`。
|
|
249
|
+
10. **行内公式不能跨行**:`$...$` 必须在同一行内闭合;`$$...$$` 可以跨多行。
|
|
250
|
+
11. **不支持自定义 LaTeX 模板**:文档结构固定为 `ctexart` + `geometry` + `amsmath` + `graphicx` + `booktabs`。
|
|
251
|
+
|
|
252
|
+
---
|
|
253
|
+
|
|
254
|
+
## 七、项目结构
|
|
255
|
+
|
|
256
|
+
```
|
|
257
|
+
mathtext2doc/
|
|
258
|
+
├── __init__.py # 包入口
|
|
259
|
+
├── __main__.py # python -m mathtext2doc 入口
|
|
260
|
+
├── cli.py # CLI 参数解析与主流程
|
|
261
|
+
├── parser.py # Markdown / LaTeX / @plot 解析
|
|
262
|
+
├── plotter.py # 显函数 / 隐函数 / 多函数同图 + 标签避让
|
|
263
|
+
├── texgen.py # .tex 生成
|
|
264
|
+
└── compiler.py # LaTeX 编译 + PDF→PNG 转换
|
|
265
|
+
examples/
|
|
266
|
+
└── sample_input.txt # 示例输入
|
|
267
|
+
README.md
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
---
|
|
271
|
+
|
|
272
|
+
## 八、快速验证
|
|
273
|
+
|
|
274
|
+
```bash
|
|
275
|
+
# 在项目根目录下
|
|
276
|
+
python -m mathtext2doc examples/sample_input.txt --overwrite
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
预期输出:
|
|
280
|
+
|
|
281
|
+
```
|
|
282
|
+
已生成 .../examples/sample_input.tex
|
|
283
|
+
使用编译器:xelatex
|
|
284
|
+
(已回退到 PDF→PNG 路径)
|
|
285
|
+
输出 PNG:
|
|
286
|
+
.../examples/sample_input-1.png
|
|
287
|
+
.../examples/sample_input-2.png
|
|
288
|
+
保留 PDF:.../examples/sample_input.pdf
|
|
289
|
+
保留日志:.../examples/sample_input.log
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
如果本机未装 LaTeX,会得到清晰的错误提示:
|
|
293
|
+
|
|
294
|
+
```
|
|
295
|
+
LaTeX 编译失败:未找到任何 LaTeX 编译器。请安装 TeX Live / MiKTeX / MacTeX,...
|
|
296
|
+
```
|