Created
June 18, 2026 06:47
-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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