经常需要撰写公文的同仁们一定深有体会:按照《党政机关公文格式》(GB/T 9704-2012)在 Word 中调整格式,不仅步骤繁琐,还容易出错。那么,能否用 Markdown 写完内容,直接生成符合国标的公文文档呢?答案是肯定的——这就是 md2doc 工具的由来。

背景

在日常办公中,我们常常需要将 Markdown 文档转换为符合国家标准(GB/T 9704-2012)的 Word 或 PDF 公文。手动设置页边距、行距、字体、字号、页码等参数不仅耗时,而且难以保证格式统一。

为此,我开发了 md2doc——一个专注于将 Markdown 转换为标准公文格式的开源工具。

功能亮点

一句话概括:输入 Markdown,输出符合国标的 Word、PDF 或 HTML 公文。

核心功能包括:

  • 实时预览:在编辑 Markdown 的同时,实时预览公文排版效果
  • 多格式输出:支持生成 DOC(兼容 Word 97-2003)、PDF 与 HTML 三种格式
  • 文件上传:支持拖拽或选择上传本地 .md 文件
  • 隐私保护:文件生成并下载后自动从服务器删除,不留存任何用户文档

公文格式规范

工具严格遵循 GB/T 9704-2012 国家标准,自动应用以下格式:

层级 编号格式 字体 字号
标题 方正小标宋简体 二号(22pt)
第一层 一、二、三、… 黑体 三号(16pt)
第二层 (一)(二)(三)… 楷体_GB2312 三号(16pt)
第三层 1. 2. 3. … 仿宋_GB2312 三号(16pt)
第四层 (1)(2)(3)… 仿宋_GB2312 三号(16pt)
正文 仿宋_GB2312 三号(16pt)

页面格式方面,自动设置页边距为上 3.7cm、下 3.5cm、左 2.8cm、右 2.6cm,行距固定为 28.9 磅,正文两端对齐,页码使用 4 号宋体并居右显示。

技术实现

整体架构

项目基于 Flask 构建,采用清晰的三层架构:

1
2
3
4
5
前端界面 (HTML/CSS/JS)
↓ HTTP 请求/响应
Flask Web 服务层

文档转换处理层 (Pandoc + LibreOffice + python-docx)

转换流程

转换过程分为三个关键步骤:

  1. Pandoc 转换:将 Markdown 转换为 DOCX 作为中间格式
  2. 格式规范化:通过 python-docx 对 DOCX 进行公文格式处理,包括设置页边距、识别标题层级、应用对应字体字号、设定固定行距等
  3. 最终输出:使用 LibreOffice 将处理好的 DOCX 转换为目标格式(DOC 或 PDF)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Markdown 文本


Pandoc 转换 (Markdown → DOCX)


formatter.py 进行格式处理
├─ 设置公文页边距
├─ 自动识别标题层级并应用样式
├─ 设置中文字体(仿宋、黑体、楷体等)
├─ 固定行距为 28.9 磅
└─ 添加标准页码


LibreOffice 转换 (DOCX → DOC/PDF)


生成最终文件供下载

标题层级自动识别

工具通过正则表达式自动识别 Markdown 文本中的公文标题结构,用户无需学习额外语法:

1
2
3
4
5
6
HEADING_PATTERNS = {
1: re.compile(r'^[一二三四五六七八九十]+、'), # 匹配“一、”
2: re.compile(r'^([一二三四五六七八九十]+)'), # 匹配“(一)”
3: re.compile(r'^\d+[..]'), # 匹配“1.”
4: re.compile(r'^(\d+)'), # 匹配“(1)”
}

隐私保护机制

为确保用户文档安全,下载完成后文件会被立即删除:

1
2
3
4
5
6
7
8
9
10
@app.route('/download/<filename>')
def download(filename):
# 安全检查文件名
safe_filename = sanitize_filename(filename)
# 将文件内容读入内存
# ...
# 立即从磁盘删除文件
os.unlink(file_path)
# 返回内存中的文件流
return send_file(BytesIO(file_data), as_attachment=True)

XSS 防护

在实时预览功能中,使用 bleach 库对生成的 HTML 进行过滤,仅允许安全的标签,有效防止跨站脚本攻击:

1
2
3
4
5
6
7
allowed_tags = [
'p', 'br', 'strong', 'em', 'b', 'i', 'u',
'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
'ul', 'ol', 'li', 'blockquote', 'pre', 'code',
'table', 'thead', 'tbody', 'tr', 'th', 'td',
]
html = bleach.clean(html, tags=allowed_tags, strip=True)

快速开始

本地运行

1
2
3
4
5
# 安装依赖
pip install -r requirements.txt

# 启动服务
python app.py

启动后,在浏览器中访问 http://localhost:5000 即可使用。

Docker 部署

1
docker-compose up -d

Docker 镜像已预装 Pandoc、LibreOffice 及必要的中文字体(fonts-noto-cjk),真正做到开箱即用。

项目结构

1
2
3
4
5
6
7
8
9
10
11
md2doc/
├── app.py # Flask 主程序(路由、安全校验等)
├── converter.py # 核心转换模块(Pandoc + LibreOffice 调用)
├── formatter.py # 公文格式处理(基于 python-docx)
├── requirements.txt # Python 依赖列表
├── Dockerfile # Docker 镜像构建文件
├── docker-compose.yml # Docker Compose 编排配置
├── templates/
│ └── index.html # 前端页面(采用 GitHub 风格浅色主题)
└── static/
└── favicon.png # 网站图标

技术栈选型

组件 选用技术
后端框架 Flask + Python 3.12
DOC 转换 Pandoc + python-docx + LibreOffice
PDF 生成 LibreOffice(无头模式)
前端实现 原生 HTML/CSS/JavaScript + marked.js
部署方案 Docker + Docker Compose + Gunicorn

未来规划

  • 支持更多公文元素(如发文机关标志、成文日期、印章模拟位置等)
  • 提供用户自定义模板功能
  • 增加批量文件转换支持
  • 进一步优化 Docker 镜像体积

总结

md2doc 巧妙地将 Markdown 的简洁书写体验与公文格式的严谨要求结合在一起。用户只需专注于内容创作,格式规范交给工具自动完成,大幅提升了公文撰写的效率与标准化程度。

访问地址:md2.sujx.net

本文由AI撰写