92 lines
3.0 KiB
Python
92 lines
3.0 KiB
Python
# -*- coding: utf-8 -*-
|
||
"""
|
||
将 DOCX 转为 Markdown,并把内嵌图片导出到同级 media 目录,Markdown 内使用相对路径引用。
|
||
|
||
说明:markitdown / MCP 用的默认 mammoth 路径在「表格+多图」等版式下经常出现图片被省略;
|
||
Office Viewer 是编辑器原生渲染 Word,与命令行转换不是同一套逻辑。
|
||
本脚本通过 mammoth 的 convert_image 将图片写入磁盘,便于 AI 与文档工具使用。
|
||
|
||
依赖:pip install mammoth
|
||
|
||
用法:
|
||
python docx_to_markdown_with_images.py input.docx -o out.md
|
||
python docx_to_markdown_with_images.py input.docx -o out.md --media-dir assets/req-images
|
||
|
||
全局安装(推荐,任意仓库可直接调用):
|
||
Windows: 复制本文件到 %USERPROFILE%\\.claude\\scripts\\
|
||
或在 jjb-ai 仓库 .claude\\scripts 下执行: install-docx-converter-global.ps1
|
||
然后: python "%USERPROFILE%\\.claude\\scripts\\docx_to_markdown_with_images.py" ...
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
import argparse
|
||
import os
|
||
import sys
|
||
|
||
|
||
def main() -> int:
|
||
try:
|
||
import mammoth
|
||
except ImportError:
|
||
print("请先安装: pip install mammoth", file=sys.stderr)
|
||
return 1
|
||
|
||
parser = argparse.ArgumentParser(description="DOCX → Markdown,图片落盘")
|
||
parser.add_argument("docx", help="输入 .docx 路径")
|
||
parser.add_argument("-o", "--output", required=True, help="输出 .md 路径")
|
||
parser.add_argument(
|
||
"--media-dir",
|
||
default="media",
|
||
help="媒体目录(相对 output 所在目录),默认 media",
|
||
)
|
||
args = parser.parse_args()
|
||
|
||
out_md = os.path.abspath(args.output)
|
||
base_dir = os.path.dirname(out_md)
|
||
media_rel = args.media_dir.strip("/\\").replace("\\", "/")
|
||
media_abs = os.path.join(base_dir, media_rel.replace("/", os.sep))
|
||
os.makedirs(media_abs, exist_ok=True)
|
||
|
||
counter = {"n": 0}
|
||
|
||
def save_image(image):
|
||
content_type = image.content_type or "image/png"
|
||
ext = content_type.split("/")[-1].lower()
|
||
if ext in ("jpeg", "pjpeg"):
|
||
ext = "jpg"
|
||
counter["n"] += 1
|
||
filename = f"image_{counter['n']:03d}.{ext}"
|
||
path_abs = os.path.join(media_abs, filename)
|
||
with image.open() as stream:
|
||
data = stream.read()
|
||
with open(path_abs, "wb") as f:
|
||
f.write(data)
|
||
rel_src = f"{media_rel}/{filename}".replace("\\", "/")
|
||
return {"src": rel_src}
|
||
|
||
docx_path = os.path.abspath(args.docx)
|
||
if not os.path.isfile(docx_path):
|
||
print(f"文件不存在: {docx_path}", file=sys.stderr)
|
||
return 1
|
||
|
||
with open(docx_path, "rb") as docx_file:
|
||
result = mammoth.convert_to_markdown(
|
||
docx_file,
|
||
convert_image=mammoth.images.img_element(save_image),
|
||
)
|
||
|
||
for msg in result.messages:
|
||
print(msg, file=sys.stderr)
|
||
|
||
with open(out_md, "w", encoding="utf-8") as f:
|
||
f.write(result.value)
|
||
|
||
print(out_md, file=sys.stderr)
|
||
print(f"images: {counter['n']}", file=sys.stderr)
|
||
return 0
|
||
|
||
|
||
if __name__ == "__main__":
|
||
raise SystemExit(main())
|