二进制文件
安装 Pandoc
1
2
3
4
5
6
7
8
9
|
wget https://github.com/jgm/pandoc/releases/download/3.8.3/pandoc-3.8.3-linux-amd64.tar.gz
tar -xzvf pandoc-3.8.3-linux-amd64.tar.gz
cd pandoc-3.8.3
cp bin/pandoc /usr/local/bin/
pandoc --version
|
安装 wkhtmltopdf 引擎
1
2
3
4
5
6
7
8
9
10
|
# 使用0.12.4的通用Linux版本(兼容性好)
wget https://github.com/wkhtmltopdf/wkhtmltopdf/releases/download/0.12.4/wkhtmltox-0.12.4_linux-generic-amd64.tar.xz
tar -xvf wkhtmltox-0.12.4_linux-generic-amd64.tar.xz
# 然后直接使用解压目录内的可执行文件,或将其复制到系统路径,如/usr/local/bin/
sudo cp wkhtmltox/bin/wkhtmltopdf /usr/local/bin/
# 查看版本
wkhtmltopdf --version
|
转换MD文件为PDF
1
|
pandoc "xxxxxx.md" -o "xxxxxx.pdf" --pdf-engine=wkhtmltopdf
|
Docker
目录结构
pandoc3/
├── Dockerfile # Docker 镜像构建文件(不包含脚本)
├── build.sh # 构建镜像脚本
├── test-convert.sh # 转换脚本(挂载 scripts/ 目录)
├── pandoc-3.1.8-linux-amd64.tar.gz
└── scripts/ # 脚本文件夹(运行时挂载到容器)
├── mermaid-process.sh # Mermaid 图表处理脚本
├── pandoc-pdf.sh # Pandoc PDF 转换主脚本
└── convert-md-to-pdf.sh # 简化版转换脚本
Dockerfile
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
|
FROM debian:bookworm
ENV DEBIAN_FRONTEND=noninteractive
# 🚨 强制允许不安全 APT(解决被 MITM 的 GPG 问题)
RUN echo 'Acquire::AllowInsecureRepositories "true";\n\
Acquire::AllowDowngradeToInsecureRepositories "true";\n\
APT::Get::AllowUnauthenticated "true";' \
> /etc/apt/apt.conf.d/99insecure
RUN apt-get update && apt-get install -y --allow-unauthenticated \
wget \
curl \
git \
unzip \
xz-utils \
libssl-dev \
ca-certificates \
fonts-liberation \
fonts-dejavu-core \
fonts-freefont-ttf \
fonts-noto-cjk \
fonts-wqy-zenhei \
fonts-wqy-microhei \
fonts-arphic-ukai \
fonts-arphic-uming \
texlive-xetex \
texlive-latex-base \
texlive-latex-extra \
texlive-fonts-recommended \
texlive-fonts-extra \
texlive-lang-chinese \
texlive-lang-cjk \
texlive-latex-recommended \
texlive-plain-generic \
texlive-metapost \
texlive-pictures \
texlive-science \
lmodern \
cm-super \
dvipng \
ghostscript \
librsvg2-bin \
python3 \
python3-pip \
python3-setuptools \
python3-wheel \
build-essential \
libffi-dev \
libcairo2-dev \
pkg-config \
libjpeg-dev \
libgif-dev \
librsvg2-dev \
pandoc \
pandoc-data \
chromium \
libnss3 \
libatk1.0-0 \
libatk-bridge2.0-0 \
libcups2 \
libxcomposite1 \
libxrandr2 \
libxdamage1 \
libxfixes3 \
libxkbcommon0 \
libgbm1 \
libasound2 \
libpangocairo-1.0-0 \
libgtk-3-0 \
&& rm -rf /var/lib/apt/lists/*
# ============================================
# 安装 Pandoc - 二选一
# ============================================
# 方式 1: 从网络下载 Pandoc(适合网络良好的用户)
# 取消下面的注释以启用此方式
# RUN wget -q https://github.com/jgm/pandoc/releases/download/3.1.8/pandoc-3.1.8-linux-amd64.tar.gz && \
# tar -xzf pandoc-3.1.8-linux-amd64.tar.gz && \
# mv pandoc-*/bin/* /usr/local/bin/ && \
# rm -rf pandoc-*
# 方式 2: 使用本地文件(适合网络不好或已提前下载的用户)
# 使用前请将 pandoc-3.1.8-linux-amd64.tar.gz 放在 Dockerfile 同级目录下
# 取消下面的注释以启用此方式,同时注释掉方式 1
COPY pandoc-3.1.8-linux-amd64.tar.gz /tmp/
RUN tar -xzf /tmp/pandoc-3.1.8-linux-amd64.tar.gz -C /tmp/ && \
mv /tmp/pandoc-*/bin/* /usr/local/bin/ && \
rm -rf /tmp/pandoc-*
# 安装 Node.js 18 LTS
RUN curl -fsSL https://deb.nodesource.com/setup_18.x | bash - && \
apt-get install -y nodejs && \
node --version && npm --version && \
rm -rf /var/lib/apt/lists/*
# 保留国内镜像(确保能下载 Chromium)
ENV PUPPETEER_DOWNLOAD_HOST=https://cdn.npmmirror.com/binaries
# 安装 Mermaid CLI
RUN npm config set registry https://registry.npmmirror.com && \
npm install -g @mermaid-js/mermaid-cli@10.6.1
# 安装 Python 包
RUN pip3 install --no-cache-dir --break-system-packages \
pandocfilters \
matplotlib \
pillow \
cairosvg
# 设置字体缓存
RUN fc-cache -fv
# 创建工作目录
WORKDIR /workspace
# Puppeteer 配置(给 mermaid-cli 用)
RUN cat > /tmp/puppeteer-config.json <<'EOF'
{
"executablePath": "/usr/bin/chromium",
"args": [
"--no-sandbox",
"--disable-setuid-sandbox"
]
}
EOF
ENV PUPPETEER_SKIP_DOWNLOAD=true
ENV PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium
ENV PUPPETEER_CONFIG='{"args":["--no-sandbox","--disable-setuid-sandbox"]}'
ENV MERMAID_PUPPETEER_CONFIG='{"args":["--no-sandbox","--disable-setuid-sandbox"]}'
# 设置环境变量
ENV LANG=C.UTF-8
ENV LC_ALL=C.UTF-8
ENV PATH="/usr/local/bin:$PATH"
# 默认命令
CMD ["pandoc", "--version"]
|
build.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
#!/bin/bash
echo "=========================================="
echo "Pandoc 中文+Mermaid Docker 镜像构建脚本"
echo "=========================================="
# 检查 Docker 是否安装
if ! command -v docker &> /dev/null; then
echo "错误: Docker 未安装或未运行"
echo "请先安装 Docker: https://docs.docker.com/get-docker/"
exit 1
fi
# 检查 Docker 是否运行
if ! docker info &> /dev/null; then
echo "错误: Docker 服务未运行"
echo "请启动 Docker 服务"
exit 1
fi
echo "正在构建 Docker 镜像..."
echo "这可能需要一些时间(5-15分钟)..."
docker build -t pandoc-chinese-mermaid .
if [ $? -eq 0 ]; then
echo ""
echo "✅ 构建成功!"
echo ""
echo "镜像名称: pandoc-chinese-mermaid"
echo ""
echo "测试命令:"
echo " docker run --rm pandoc-chinese-mermaid pandoc --version"
echo ""
echo "转换示例:"
echo " ./test-convert.sh input.md"
echo ""
echo "或者手动运行:"
echo " docker run --rm -v \$(pwd):/workspace -v \$(pwd)/scripts:/usr/local/bin pandoc-chinese-mermaid pandoc-pdf input.md"
echo ""
else
echo ""
echo "❌ 构建失败!"
echo "请检查错误信息并重新构建"
exit 1
fi
|
test-convert.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
|
#!/bin/bash
# 一键转换脚本
# 支持 Mermaid 图表和中文
set -e
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
# 使用当前目录下的 scripts 文件夹
SCRIPTS_DIR="$SCRIPT_DIR/scripts"
# 检查 scripts 目录是否存在
if [ ! -d "$SCRIPTS_DIR" ]; then
echo "错误: 找不到 scripts 目录"
echo "请确保在脚本所在目录下有 scripts/ 文件夹"
echo "当前目录: $SCRIPT_DIR"
echo "期望的路径: $SCRIPTS_DIR"
exit 1
fi
echo "=========================================="
echo "Pandoc Markdown 转 PDF 转换工具"
echo "支持: 中文、数学公式、Mermaid 图表"
echo "=========================================="
# 检查参数
if [ $# -lt 1 ]; then
echo "用法: $0 <input.md> [output.pdf]"
echo "示例:"
echo " $0 document.md"
echo " $0 document.pdf mydocument.pdf"
exit 1
fi
INPUT_FILE="$1"
OUTPUT_FILE="${2:-${INPUT_FILE%.md}.pdf}"
# 检查输入文件
if [ ! -f "$INPUT_FILE" ]; then
echo "错误: 输入文件 '$INPUT_FILE' 不存在"
exit 1
fi
# 检查镜像是否存在
if ! docker images pandoc-chinese-mermaid &> /dev/null; then
echo "错误: Docker 镜像 'pandoc-chinese-mermaid' 不存在"
echo "请先运行: ./build.sh"
exit 1
fi
echo "输入文件: $INPUT_FILE"
echo "输出文件: $OUTPUT_FILE"
echo ""
# 使用 scripts 文件夹中的 pandoc-pdf 脚本
echo "使用脚本目录: $SCRIPTS_DIR"
docker run --rm \
-v "$(pwd)":/workspace \
-v "$SCRIPTS_DIR":/scripts \
pandoc-chinese-mermaid \
bash -c "
# 在容器内创建无后缀的软链接
ln -sf /scripts/pandoc-pdf.sh /usr/local/bin/pandoc-pdf
ln -sf /scripts/mermaid-process.sh /usr/local/bin/mermaid-process
ln -sf /scripts/convert-md-to-pdf.sh /usr/local/bin/convert-md-to-pdf
# 执行转换
pandoc-pdf \"$INPUT_FILE\" \"$OUTPUT_FILE\"
"
echo ""
echo "✅ 转换完成!"
echo "输出文件: $OUTPUT_FILE"
|
mermaid-process.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
|
#!/bin/bash
set -e
INPUT_FILE="$1"
OUTPUT_FILE="$2"
if [ -z "$INPUT_FILE" ] || [ -z "$OUTPUT_FILE" ]; then
echo "usage: mermaid-process input.md output.md"
exit 1
fi
# 如果没有 mermaid 块,直接拷贝
if ! grep -q '^```mermaid' "$INPUT_FILE"; then
cp "$INPUT_FILE" "$OUTPUT_FILE"
exit 0
fi
TEMP_MD="${INPUT_FILE%.md}_temp.md"
awk '
BEGIN {
in_mermaid = 0
count = 0
}
{
# 进入 mermaid 块
if ($0 ~ /^```mermaid/) {
in_mermaid = 1
count++
mmd = "mermaid_" count ".mmd"
png = "mermaid_" count ".png"
print "::: {.center}\n\n:::"
next
}
# 退出 mermaid 块
if ($0 ~ /^```/ && in_mermaid) {
in_mermaid = 0
close(mmd)
# ⚠️ 关键点:不要传 --no-sandbox
cmd = "mmdc -i " mmd " -o " png " --width 1200 --scale 2 -p /tmp/puppeteer-config.json > /dev/null 2>&1"
ret = system(cmd)
if (ret != 0) {
print "Mermaid render failed: " mmd > "/dev/stderr"
exit 1
}
next
}
# mermaid 内容写入 .mmd 文件
if (in_mermaid) {
print > mmd
next
}
# 普通文本
print
}
' "$INPUT_FILE" > "$TEMP_MD"
mv "$TEMP_MD" "$OUTPUT_FILE"
|
pandoc-pdf.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
|
#!/bin/bash
# Pandoc PDF 转换脚本(支持中文、数学公式、Mermaid)
set -e
# 颜色输出
RED="\033[31m"
GREEN="\033[32m"
YELLOW="\033[33m"
BLUE="\033[34m"
RESET="\033[0m"
# 检查参数
if [ $# -lt 1 ]; then
echo -e "${RED}用法: $0 <input.md> [output.pdf]${RESET}"
echo ""
echo -e "${BLUE}支持的特性:${RESET}"
echo " ✅ 中文显示和排版"
echo " ✅ 数学公式 (LaTeX)"
echo " ✅ 化学公式"
echo " ✅ Mermaid 图表"
echo " ✅ Markdown 表格"
echo " ✅ 代码高亮"
echo " ✅ 目录生成"
exit 1
fi
INPUT_FILE="$1"
OUTPUT_FILE="${2:-${INPUT_FILE%.md}.pdf}"
TEMP_DIR="/tmp/pandoc_convert_$$"
# 检查输入文件
if [ ! -f "$INPUT_FILE" ]; then
echo -e "${RED}错误: 输入文件 '$INPUT_FILE' 不存在${RESET}"
exit 1
fi
echo -e "${GREEN}==========================================${RESET}"
echo -e "${GREEN}📄 输入: $INPUT_FILE${RESET}"
echo -e "${GREEN}📄 输出: $OUTPUT_FILE${RESET}"
echo -e "${GREEN}==========================================${RESET}"
echo ""
# 创建临时目录
mkdir -p "$TEMP_DIR"
cd "$TEMP_DIR"
# 复制输入文件
cp "$OLDPWD/$INPUT_FILE" .
# 步骤 1: 处理 Mermaid 图表
echo -e "${YELLOW}🔄 步骤 1: 处理 Mermaid 图表...${RESET}"
mermaid-process "$INPUT_FILE" "${INPUT_FILE%.md}_processed.md"
# 步骤 2: 转换为 PDF
echo -e "${YELLOW}🔄 步骤 2: 转换为 PDF...${RESET}"
# 使用 XeLaTeX 转换
pandoc "${INPUT_FILE%.md}_processed.md" -o "$OUTPUT_FILE" \
--pdf-engine=xelatex \
-V CJKmainfont="Noto Sans CJK SC" \
-V CJKoptions="BoldFont=Noto Sans CJK SC Bold" \
-V mainfont="Noto Sans CJK SC" \
-V sansfont="Noto Sans CJK SC" \
-V monofont="Noto Sans Mono CJK SC" \
-V geometry:margin=2.5cm \
-V papersize=a4 \
-V fontsize=11pt \
--highlight-style=tango \
--toc \
--toc-depth=3 \
--pdf-engine-opt=-shell-escape \
--pdf-engine-opt=-8bit \
2>&1 | (grep -E "(Error|Warning|错误|警告)" || true)
# 检查并复制输出文件
if [ -f "$OUTPUT_FILE" ]; then
cp "$OUTPUT_FILE" "$OLDPWD/"
echo ""
echo -e "${GREEN}==========================================${RESET}"
echo -e "${GREEN}✅ 转换成功!${RESET}"
echo -e "${GREEN}📂 输出文件: $OLDPWD/$OUTPUT_FILE${RESET}"
echo -e "${GREEN}==========================================${RESET}"
else
echo -e "${RED}❌ 转换失败!${RESET}"
exit 1
fi
# 清理
cd "$OLDPWD"
rm -rf "$TEMP_DIR"
|
convert-md-to-pdf.sh
1
2
3
4
5
6
7
8
9
10
11
|
#!/bin/bash
# 简化版 Pandoc 转换脚本
if [ $# -lt 1 ]; then
echo "用法: $0 <input.md> [output.pdf]"
exit 1
fi
INPUT_FILE="$1"
OUTPUT_FILE="${2:-${INPUT_FILE%.md}.pdf}"
pandoc-pdf "$INPUT_FILE" "$OUTPUT_FILE"
|
执行步骤
1
2
3
4
5
|
# 构建镜像
./build.sh
# 转换 md 文件
./test-convert.sh your-document.md
|