@cliven/mddocx 1.0.2 → 1.0.4
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.
- package/.claude-plugin/plugin.json +2 -2
- package/.codex-plugin/plugin.json +1 -1
- package/.cursor-plugin/plugin.json +1 -1
- package/README.md +1 -1
- package/package.json +1 -1
- package/skills/mddoc/SKILL.md +2 -2
- package/skills/mddoc/scripts/__pycache__/md2docx.cpython-312.pyc +0 -0
- package/skills/mddoc/scripts/md2docx.py +44 -3
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mddocx",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"description": "Markdown 转学术格式 Word 文档 (DOCX)。支持三线表、图题/表题自动编号、页码、页眉等学术论文排版规范。",
|
|
5
|
-
"author": "Quan Guanyu",
|
|
5
|
+
"author": { "name": "Quan Guanyu" },
|
|
6
6
|
"keywords": ["markdown", "docx", "word", "academic", "论文", "学术", "转换"],
|
|
7
7
|
"skills": "./skills/"
|
|
8
8
|
}
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# mddocx — Markdown 转学术格式 DOCX
|
|
2
2
|
|
|
3
|
-
[](https://
|
|
3
|
+
[](https://www.claudepluginhub.com/plugins/trisia-mddocx)
|
|
4
4
|
[](https://github.com/openai/codex)
|
|
5
5
|
[](https://cursor.com)
|
|
6
6
|
[](https://opencode.ai)
|
package/package.json
CHANGED
package/skills/mddoc/SKILL.md
CHANGED
|
@@ -213,7 +213,7 @@ p.add_run().add_picture(img_path, width=img_width(img_path))
|
|
|
213
213
|
|
|
214
214
|
### 图题
|
|
215
215
|
|
|
216
|
-
图片下方(不空行)、小五(9pt)
|
|
216
|
+
图片下方(不空行)、小五(9pt)宋体加粗居中、逐章编号。有章标题时格式 `图<章>-<序号> <alt>`,无章标题时格式 `图<序号> <alt>`。若 alt 为空,自动使用图片文件名(不含扩展名)作为图题。
|
|
217
217
|
|
|
218
218
|
```python
|
|
219
219
|
p = doc.add_paragraph()
|
|
@@ -225,7 +225,7 @@ add_empty(doc) # 图题下方空一行
|
|
|
225
225
|
|
|
226
226
|
### 表格 + 表题
|
|
227
227
|
|
|
228
|
-
**三线表**(顶线1.5pt/表头底线0.75pt/底线1.5pt粗,无竖线)。表题在上方(不空行)、五号(10.5pt)
|
|
228
|
+
**三线表**(顶线1.5pt/表头底线0.75pt/底线1.5pt粗,无竖线)。表题在上方(不空行)、五号(10.5pt)宋体加粗居中。有章标题时格式`表<章>-<序号> <描述>`,无章标题时格式`表<序号> <描述>`。
|
|
229
229
|
|
|
230
230
|
```python
|
|
231
231
|
# 表题
|
|
Binary file
|
|
@@ -566,8 +566,40 @@ def add_empty_para(doc):
|
|
|
566
566
|
# ============================================================
|
|
567
567
|
|
|
568
568
|
def download_image(url):
|
|
569
|
-
"""
|
|
569
|
+
"""下载或复制图片到临时文件,返回路径。失败返回 None。
|
|
570
|
+
|
|
571
|
+
支持:
|
|
572
|
+
- HTTP/HTTPS URL:requests 下载
|
|
573
|
+
- 本地文件路径:直接复制到临时文件
|
|
574
|
+
- base64 data URI:解码保存
|
|
575
|
+
"""
|
|
570
576
|
import requests
|
|
577
|
+
import shutil
|
|
578
|
+
|
|
579
|
+
# 1. 本地文件路径(相对于工作目录的路径)
|
|
580
|
+
if os.path.exists(url):
|
|
581
|
+
suffix = os.path.splitext(url)[1] or '.png'
|
|
582
|
+
tmp = tempfile.NamedTemporaryFile(delete=False, suffix=suffix)
|
|
583
|
+
shutil.copy2(url, tmp.name)
|
|
584
|
+
tmp.close()
|
|
585
|
+
return tmp.name
|
|
586
|
+
|
|
587
|
+
# 2. base64 data URI
|
|
588
|
+
if url.startswith('data:'):
|
|
589
|
+
import base64
|
|
590
|
+
# 格式: data:image/png;base64,xxxx 或 data:image/png,xxxx
|
|
591
|
+
header, data = url.split(',', 1)
|
|
592
|
+
is_base64 = ';base64' in header
|
|
593
|
+
suffix = '.png'
|
|
594
|
+
mime_match = re.match(r'data:image/(\w+)', header)
|
|
595
|
+
if mime_match:
|
|
596
|
+
suffix = '.' + mime_match.group(1)
|
|
597
|
+
tmp = tempfile.NamedTemporaryFile(delete=False, suffix=suffix)
|
|
598
|
+
tmp.write(base64.b64decode(data) if is_base64 else data.encode())
|
|
599
|
+
tmp.close()
|
|
600
|
+
return tmp.name
|
|
601
|
+
|
|
602
|
+
# 3. HTTP/HTTPS URL
|
|
571
603
|
headers = {'User-Agent': 'Mozilla/5.0 (compatible; mddoc-converter/1.0)'}
|
|
572
604
|
try:
|
|
573
605
|
resp = requests.get(url, headers=headers, timeout=30)
|
|
@@ -906,6 +938,7 @@ def generate_docx(nodes, output_path, title_text=None):
|
|
|
906
938
|
|
|
907
939
|
# --- 计数器 ---
|
|
908
940
|
chapter_path = [1] # 一级标题序号
|
|
941
|
+
has_chapter = False # 是否遇到章标题(# 一级标题)
|
|
909
942
|
fig_counter = {} # key: chapter index tuple, value: counter
|
|
910
943
|
tab_counter = {}
|
|
911
944
|
eq_counter = {}
|
|
@@ -929,10 +962,14 @@ def generate_docx(nodes, output_path, title_text=None):
|
|
|
929
962
|
return eq_counter[key]
|
|
930
963
|
|
|
931
964
|
def make_fig_label():
|
|
932
|
-
|
|
965
|
+
if has_chapter:
|
|
966
|
+
return f"图{chapter_path[0]}-{incr_fig()}"
|
|
967
|
+
return f"图{incr_fig()}"
|
|
933
968
|
|
|
934
969
|
def make_tab_label():
|
|
935
|
-
|
|
970
|
+
if has_chapter:
|
|
971
|
+
return f"表{chapter_path[0]}-{incr_tab()}"
|
|
972
|
+
return f"表{incr_tab()}"
|
|
936
973
|
|
|
937
974
|
# --- 遍历节点生成内容 ---
|
|
938
975
|
for node in nodes:
|
|
@@ -950,6 +987,7 @@ def generate_docx(nodes, output_path, title_text=None):
|
|
|
950
987
|
lv = node['level']
|
|
951
988
|
if lv == 1:
|
|
952
989
|
# 一级标题:新页 + 三号黑体居中
|
|
990
|
+
has_chapter = True
|
|
953
991
|
chapter_path[0] += 1
|
|
954
992
|
chapter_path[1:] = [0] # reset sub-levels
|
|
955
993
|
|
|
@@ -1017,6 +1055,9 @@ def generate_docx(nodes, output_path, title_text=None):
|
|
|
1017
1055
|
run_img.add_picture(img_path, width=w)
|
|
1018
1056
|
|
|
1019
1057
|
# 图题:小五宋体加粗居中
|
|
1058
|
+
# alt 为空时,使用图片文件名(不含扩展名)作为默认图题
|
|
1059
|
+
if not alt:
|
|
1060
|
+
alt = os.path.splitext(os.path.basename(url))[0]
|
|
1020
1061
|
p_cap = doc.add_paragraph()
|
|
1021
1062
|
p_cap.alignment = WD_ALIGN_PARAGRAPH.CENTER
|
|
1022
1063
|
run_cap = p_cap.add_run(f'{make_fig_label()} {alt}')
|