Skip to content

Instantly share code, notes, and snippets.

@philipz
Created June 18, 2026 06:47
Show Gist options
  • Select an option

  • Save philipz/8ae1eab90c0eb62eb52aef2fb106f044 to your computer and use it in GitHub Desktop.

Select an option

Save philipz/8ae1eab90c0eb62eb52aef2fb106f044 to your computer and use it in GitHub Desktop.
Markdown 2 Word docx - python md_to_docx.py VB6.md VB6.docx
import os
import json
import base64
import requests
import argparse
from docx import Document
from docx.shared import Inches, Pt
from docx.enum.text import WD_ALIGN_PARAGRAPH
def get_mermaid_image(code):
# 將 mermaid 語法編碼並發送至 mermaid.ink
data = {
"code": code,
"mermaid": {"theme": "default"}
}
json_str = json.dumps(data)
b64_str = base64.b64encode(json_str.encode('utf-8')).decode('utf-8')
url = f"https://mermaid.ink/img/{b64_str}"
try:
response = requests.get(url, timeout=20)
if response.status_code == 200:
return response.content
except Exception as e:
print(f"Error fetching mermaid image: {e}")
return None
def main():
parser = argparse.ArgumentParser(description="將 Markdown 檔案轉換為 Word (.docx) 檔案,並自動下載與嵌入 Mermaid 流程圖圖片。")
parser.add_argument("md_path", help="來源 Markdown 檔案路徑")
parser.add_argument("docx_path", nargs="?", help="輸出的 Word 檔案路徑 (預設為同檔名且副檔名為 .docx)")
args = parser.parse_args()
md_path = args.md_path
docx_path = args.docx_path
if not docx_path:
docx_path = os.path.splitext(md_path)[0] + ".docx"
if not os.path.exists(md_path):
print(f"Error: 找不到檔案 {md_path}")
return
with open(md_path, "r", encoding="utf-8") as f:
lines = f.readlines()
doc = Document()
# 設定文檔段落基本間距
style = doc.styles['Normal']
font = style.font
font.name = 'Arial'
font.size = Pt(11)
in_mermaid = False
mermaid_code = []
i = 0
while i < len(lines):
line = lines[i]
line_stripped = line.strip()
# 處理 Mermaid 區塊
if line_stripped.startswith("```mermaid"):
in_mermaid = True
mermaid_code = []
i += 1
continue
elif in_mermaid and line_stripped.startswith("```"):
in_mermaid = False
# 渲染 Mermaid 圖片並插入
code_str = "\n".join(mermaid_code)
img_data = get_mermaid_image(code_str)
if img_data:
temp_path = "temp_mermaid.png"
with open(temp_path, "wb") as img_f:
img_f.write(img_data)
# 插入圖片說明
p_desc = doc.add_paragraph()
p_desc.alignment = WD_ALIGN_PARAGRAPH.CENTER
run_desc = p_desc.add_run("【流程圖】")
run_desc.bold = True
run_desc.font.size = Pt(10)
# 插入圖片,水平置中
p = doc.add_paragraph()
p.alignment = WD_ALIGN_PARAGRAPH.CENTER
p.add_run().add_picture(temp_path, width=Inches(5.8))
# 刪除暫存檔
os.remove(temp_path)
else:
p = doc.add_paragraph()
p.alignment = WD_ALIGN_PARAGRAPH.CENTER
p.add_run("[無法載入 Mermaid 流程圖圖片]").bold = True
# 加個空行
doc.add_paragraph()
i += 1
continue
if in_mermaid:
mermaid_code.append(line.rstrip('\n'))
i += 1
continue
# 處理標題
if line_stripped.startswith("### "):
doc.add_heading(line_stripped[4:], level=3)
elif line_stripped.startswith("## "):
doc.add_heading(line_stripped[3:], level=2)
elif line_stripped.startswith("# "):
doc.add_heading(line_stripped[2:], level=1)
elif line_stripped.startswith("情況一:") or line_stripped.startswith("情況二:"):
# 大標題
doc.add_heading(line_stripped, level=2)
# 處理文字流程圖段落
elif any(c in line for c in ["├──", "└──", "│", "───>"]):
p = doc.add_paragraph()
run = p.add_run(line.rstrip('\n'))
run.font.name = 'Consolas'
run.font.size = Pt(9.5)
p.paragraph_format.space_after = Pt(2)
p.paragraph_format.space_before = Pt(2)
else:
if line_stripped == "":
pass
else:
doc.add_paragraph(line_stripped)
i += 1
doc.save(docx_path)
print(f"Successfully converted to {docx_path}")
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment