
文章目录
- [Python 将 Markdown 文档转换为 PDF 的多种方法](#Python 将 Markdown 文档转换为 PDF 的多种方法)
-
- [一、使用 markdown + weasyprint(推荐)](#一、使用 markdown + weasyprint(推荐))
-
- [1. 安装依赖](#1. 安装依赖)
- [2. 基础转换](#2. 基础转换)
- [2. 基础使用](#2. 基础使用)
- [三、使用 python-markdown-pdf(命令行工具)](#三、使用 python-markdown-pdf(命令行工具))
-
- [1. 安装](#1. 安装)
- [2. Python调用](#2. Python调用)
- [四、使用 pypandoc(通用文档转换)](#四、使用 pypandoc(通用文档转换))
-
- [1. 安装](#1. 安装)
- [2. Python代码](#2. Python代码)
- [3. 创建自定义LaTeX模板](#3. 创建自定义LaTeX模板)
- [五、使用 ReportLab(完全自定义PDF)](#五、使用 ReportLab(完全自定义PDF))
-
- [1. 安装](#1. 安装)
- [2. 自定义PDF生成器](#2. 自定义PDF生成器)
- 六、完整的命令行工具
- 七、批量转换工具
- 八、Web服务版本(Flask)
- 九、选择建议
- 十、快速开始(最简方案)
Python 将 Markdown 文档转换为 PDF 的多种方法
一、使用 markdown + weasyprint(推荐)
1. 安装依赖
bash
pip install markdown weasyprint jinja2
2. 基础转换
python
import markdown
from weasyprint import HTML
import tempfile
def md_to_pdf_weasyprint(md_content, output_pdf):
"""将Markdown转换为PDF - 基础版本"""
# 将Markdown转换为HTML
html_content = markdown.markdown(md_content)
# 添加基本CSS样式
full_html = f"""
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
body {{ font-family: Arial, sans-serif; line-height: 1.6; margin: 40px; }}
h1, h2, h3 {{ color: #333; }}
code {{ background-color: #f4f4f4; padding: 2px 4px; border-radius: 3px; }}
pre {{ background-color: #f4f4f4; padding: 10px; border-radius: 5px; overflow: auto; }}
blockquote {{ border-left: 4px solid #ccc; margin-left: 0; padding-left: 20px; color: #666; }}
table {{ border-collapse: collapse; width: 100%; }}
th, td {{ border: 1px solid #ddd; padding: 8px; text-align: left; }}
th {{ background-color: #f4f4f4; }}
img {{ max-width: 100%; height: auto; }}
</style>
</head>
<body>
{html_content}
</body>
</html>
"""
# 生成PDF
HTML(string=full_html).write_pdf(output_pdf)
print(f"PDF已生成: {output_pdf}")
# 使用示例
md_content = """
# 标题
这是一个段落。
## 子标题
- 列表项1
- 列表项2
```python
print("Hello World")
这是一个引用
粗体 和斜体
"""
md_to_pdf_weasyprint(md_content, "output.pdf")
### 3. 增强版(支持更多特性)
```python
import markdown
from weasyprint import HTML
import os
from pathlib import Path
class MarkdownToPDF:
def __init__(self, style="default"):
"""初始化转换器"""
self.styles = {
"default": self._default_style(),
"academic": self._academic_style(),
"modern": self._modern_style(),
"minimal": self._minimal_style()
}
self.style = self.styles.get(style, self.styles["default"])
def _default_style(self):
"""默认样式"""
return """
body {
font-family: 'Helvetica Neue', Arial, sans-serif;
line-height: 1.8;
margin: 50px;
color: #333;
font-size: 12pt;
}
h1 {
color: #2c3e50;
border-bottom: 3px solid #3498db;
padding-bottom: 10px;
margin-top: 40px;
}
h2 {
color: #34495e;
border-left: 5px solid #3498db;
padding-left: 15px;
margin-top: 30px;
}
h3 {
color: #7f8c8d;
margin-top: 25px;
}
p {
margin: 15px 0;
text-align: justify;
}
ul, ol {
margin: 15px 0;
padding-left: 30px;
}
li {
margin: 8px 0;
}
code {
font-family: 'Courier New', monospace;
background-color: #ecf0f1;
padding: 2px 6px;
border-radius: 3px;
font-size: 0.9em;
}
pre {
background-color: #2c3e50;
color: #ecf0f1;
padding: 15px;
border-radius: 5px;
overflow: auto;
margin: 20px 0;
}
pre code {
background-color: transparent;
padding: 0;
}
blockquote {
background-color: #f8f9fa;
border-left: 5px solid #95a5a6;
margin: 20px 0;
padding: 15px 25px;
font-style: italic;
}
table {
width: 100%;
border-collapse: collapse;
margin: 20px 0;
}
th {
background-color: #3498db;
color: white;
padding: 12px;
text-align: left;
}
td {
padding: 10px;
border-bottom: 1px solid #ddd;
}
tr:nth-child(even) {
background-color: #f2f2f2;
}
img {
max-width: 100%;
height: auto;
margin: 20px 0;
border-radius: 5px;
}
hr {
border: none;
height: 1px;
background-color: #ddd;
margin: 30px 0;
}
a {
color: #2980b9;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
.page-break {
page-break-after: always;
}
.header {
text-align: center;
margin-bottom: 40px;
border-bottom: 2px solid #3498db;
padding-bottom: 20px;
}
.footer {
text-align: center;
margin-top: 40px;
color: #7f8c8d;
font-size: 0.9em;
}
"""
def _academic_style(self):
"""学术风格"""
return self._default_style() + """
body {
font-family: 'Times New Roman', serif;
line-height: 1.5;
}
h1, h2, h3 {
font-family: 'Georgia', serif;
}
"""
def convert_file(self, md_file_path, pdf_file_path=None,
title=None, author=None, date=None):
"""转换Markdown文件为PDF"""
if not pdf_file_path:
pdf_file_path = Path(md_file_path).with_suffix('.pdf')
# 读取Markdown文件
with open(md_file_path, 'r', encoding='utf-8') as f:
md_content = f.read()
return self.convert_text(md_content, pdf_file_path, title, author, date)
def convert_text(self, md_text, pdf_file_path,
title=None, author=None, date=None):
"""转换Markdown文本为PDF"""
# 使用扩展支持更多Markdown语法
md_extensions = [
'extra', # 支持表格、缩写等
'codehilite', # 代码高亮
'toc', # 目录
'tables', # 表格
'fenced_code', # 围栏代码块
'footnotes', # 脚注
'attr_list', # 属性列表
'def_list', # 定义列表
'meta', # 元数据
]
# 转换Markdown为HTML
html_body = markdown.markdown(md_text, extensions=md_extensions)
# 构建完整的HTML文档
full_html = self._build_html_document(html_body, title, author, date)
# 生成PDF
HTML(string=full_html).write_pdf(pdf_file_path)
print(f"✅ PDF已生成: {pdf_file_path}")
return pdf_file_path
def _build_html_document(self, body_content, title, author, date):
"""构建完整的HTML文档"""
header_html = ""
if title:
header_html = f"""
<div class="header">
<h1>{title}</h1>
{f'<p class="author">作者: {author}</p>' if author else ''}
{f'<p class="date">日期: {date}</p>' if date else ''}
</div>
<hr>
"""
footer_html = """
<div class="footer">
<p>第 <span class="page-number"></span> 页</p>
</div>
"""
full_html = f"""
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
@page {{
size: A4;
margin: 2cm;
@top-center {{
content: "{title if title else '文档'}";
font-size: 10pt;
color: #666;
}}
@bottom-center {{
content: "第 " counter(page) " 页";
font-size: 10pt;
color: #666;
}}
}}
{self.style}
/* 打印样式 */
@media print {{
.page-break {{
page-break-after: always;
}}
}}
</style>
</head>
<body>
{header_html}
{body_content}
{footer_html}
<script>
// 更新页码
document.addEventListener('DOMContentLoaded', function() {{
const pageNumbers = document.querySelectorAll('.page-number');
pageNumbers.forEach(el => {{
el.textContent = document.querySelectorAll('.page').length || 1;
}});
}});
</script>
</body>
</html>
"""
return full_html
# 使用示例
converter = MarkdownToPDF(style="modern")
# 从文件转换
converter.convert_file(
"document.md",
"output.pdf",
title="技术文档",
author="张三",
date="2024-01-20"
)
# 从文本转换
md_text = """
# 项目报告
## 概述
这是一个示例文档...
### 特性
1. 功能一
2. 功能二
3. 功能三
```python
def hello():
print("Hello, World!")
| 姓名 | 年龄 | 职位 |
|---|---|---|
| 张三 | 30 | 工程师 |
| 李四 | 28 | 设计师 |
| """ |
converter.convert_text(md_text, "report.pdf", title="项目报告")
## 二、使用 md2pdf 库
### 1. 安装
```bash
pip install md2pdf
2. 基础使用
python
from md2pdf.core import md2pdf
def convert_md_to_pdf(md_file, pdf_file):
"""使用md2pdf库转换"""
# 读取Markdown文件
with open(md_file, 'r', encoding='utf-8') as f:
md_content = f.read()
# 自定义CSS样式
css = """
body {
font-family: 'Arial', sans-serif;
line-height: 1.6;
margin: 40px;
}
h1 {
color: #2c3e50;
border-bottom: 2px solid #3498db;
}
code {
background-color: #f8f9fa;
padding: 2px 4px;
border-radius: 3px;
}
"""
# 转换PDF
md2pdf(
pdf_file,
md_content=md_content,
css_file_path=None,
base_url=None,
css=css
)
print(f"PDF已生成: {pdf_file}")
# 使用
convert_md_to_pdf("input.md", "output.pdf")
三、使用 python-markdown-pdf(命令行工具)
1. 安装
bash
pip install markdown-pdf
2. Python调用
python
import subprocess
import os
def convert_with_markdown_pdf(md_file, pdf_file, options=None):
"""
使用markdown-pdf命令行工具转换
可选参数:
--paper-format A4
--paper-orientation portrait
--css styles.css
"""
cmd = ["markdown-pdf", md_file, "-o", pdf_file]
if options:
cmd.extend(options)
try:
result = subprocess.run(cmd, capture_output=True, text=True, check=True)
print(f"转换成功: {pdf_file}")
return True
except subprocess.CalledProcessError as e:
print(f"转换失败: {e.stderr}")
return False
# 使用示例
convert_with_markdown_pdf(
"document.md",
"document.pdf",
["--paper-format", "A4", "--paper-orientation", "portrait"]
)
四、使用 pypandoc(通用文档转换)
1. 安装
bash
# 安装pypandoc
pip install pypandoc
# Windows还需要安装pandoc
# 从 https://github.com/jgm/pandoc/releases 下载安装
# Linux安装pandoc
# sudo apt-get install pandoc # Ubuntu/Debian
# sudo yum install pandoc # CentOS/RHEL
2. Python代码
python
import pypandoc
import os
def convert_with_pandoc(md_file, pdf_file, template=None):
"""使用pandoc转换(功能最强大)"""
# 可选的模板文件
extra_args = []
if template and os.path.exists(template):
extra_args = ['--template', template]
# 转换参数
output = pypandoc.convert_file(
md_file,
'pdf',
outputfile=pdf_file,
extra_args=extra_args + [
'--pdf-engine=xelatex', # 使用xelatex引擎,支持中文
'--variable', 'mainfont="Microsoft YaHei"', # 中文字体
'--variable', 'fontsize=12pt',
'--variable', 'papersize=a4',
'--variable', 'geometry:margin=2cm',
'--table-of-contents', # 生成目录
'--number-sections', # 章节编号
]
)
print(f"PDF已生成: {pdf_file}")
return output
# 使用示例
convert_with_pandoc("input.md", "output.pdf")
# 使用自定义模板
convert_with_pandoc("input.md", "output.pdf", template="template.tex")
3. 创建自定义LaTeX模板
latex
% template.tex
\documentclass[12pt,a4paper]{article}
\usepackage{xeCJK}
\usepackage[margin=2cm]{geometry}
\usepackage{hyperref}
\usepackage{listings}
\usepackage{xcolor}
% 中文字体设置
\setCJKmainfont{Microsoft YaHei}
\setCJKsansfont{SimHei}
\setCJKmonofont{FangSong}
% 代码高亮设置
\lstset{
basicstyle=\ttfamily\small,
keywordstyle=\color{blue},
commentstyle=\color{green},
stringstyle=\color{red},
breaklines=true,
frame=single,
numbers=left,
numberstyle=\tiny\color{gray}
}
\title{$title$}
\author{$author$}
\date{$date$}
\begin{document}
\maketitle
\tableofcontents
\newpage
$body$
\end{document}
五、使用 ReportLab(完全自定义PDF)
1. 安装
bash
pip install reportlab markdown
2. 自定义PDF生成器
python
from reportlab.lib.pagesizes import A4
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, PageBreak
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import inch
from reportlab.lib import colors
import markdown
from html.parser import HTMLParser
import re
class MarkdownToPDFReportLab:
"""使用ReportLab完全自定义PDF生成"""
def __init__(self):
self.styles = getSampleStyleSheet()
self._customize_styles()
def _customize_styles(self):
"""自定义样式"""
# 标题样式
self.styles.add(ParagraphStyle(
name='CustomHeading1',
parent=self.styles['Heading1'],
fontSize=24,
spaceAfter=30,
textColor=colors.HexColor('#2c3e50'),
fontName='Helvetica-Bold'
))
self.styles.add(ParagraphStyle(
name='CustomHeading2',
parent=self.styles['Heading2'],
fontSize=18,
spaceAfter=20,
textColor=colors.HexColor('#34495e')
))
# 代码样式
self.styles.add(ParagraphStyle(
name='Code',
parent=self.styles['Code'],
fontName='Courier',
fontSize=10,
backColor=colors.HexColor('#f8f9fa'),
borderColor=colors.gray,
borderWidth=1,
borderPadding=5,
leftIndent=20,
spaceBefore=10,
spaceAfter=10
))
# 正文样式
self.styles.add(ParagraphStyle(
name='NormalCustom',
parent=self.styles['Normal'],
fontSize=12,
leading=16,
spaceAfter=12
))
# 引用样式
self.styles.add(ParagraphStyle(
name='Blockquote',
parent=self.styles['Normal'],
leftIndent=20,
fontName='Helvetica-Oblique',
textColor=colors.gray,
borderLeftColor=colors.gray,
borderLeftWidth=3,
borderLeftPadding=10,
spaceBefore=10,
spaceAfter=10
))
def convert(self, md_file, pdf_file):
"""转换Markdown文件"""
# 读取Markdown
with open(md_file, 'r', encoding='utf-8') as f:
md_content = f.read()
# 转换为HTML
html_content = markdown.markdown(md_content)
# 解析HTML并构建PDF元素
elements = self._parse_html(html_content)
# 创建PDF文档
doc = SimpleDocTemplate(
pdf_file,
pagesize=A4,
rightMargin=72,
leftMargin=72,
topMargin=72,
bottomMargin=72
)
# 构建PDF
doc.build(elements)
print(f"PDF已生成: {pdf_file}")
def _parse_html(self, html_content):
"""解析HTML并转换为ReportLab元素"""
elements = []
# 简单的HTML解析(实际项目应使用BeautifulSoup)
lines = html_content.split('\n')
for line in lines:
line = line.strip()
if not line:
continue
# 处理标题
if line.startswith('<h1>'):
text = line[4:-5]
elements.append(Paragraph(text, self.styles['CustomHeading1']))
elif line.startswith('<h2>'):
text = line[4:-5]
elements.append(Paragraph(text, self.styles['CustomHeading2']))
# 处理段落
elif line.startswith('<p>'):
text = line[3:-4]
elements.append(Paragraph(text, self.styles['NormalCustom']))
elements.append(Spacer(1, 12))
# 处理代码块
elif line.startswith('<pre><code>'):
text = line[11:-12]
elements.append(Paragraph(text, self.styles['Code']))
# 处理引用
elif line.startswith('<blockquote>'):
text = line[12:-13]
elements.append(Paragraph(text, self.styles['Blockquote']))
# 处理水平线
elif line == '<hr/>':
elements.append(Spacer(1, 24))
# 处理列表(简化版)
elif line.startswith('<li>'):
text = line[4:-5]
elements.append(Paragraph(f"• {text}", self.styles['NormalCustom']))
return elements
# 使用
converter = MarkdownToPDFReportLab()
converter.convert("input.md", "output.pdf")
六、完整的命令行工具
python
#!/usr/bin/env python3
"""
Markdown转PDF命令行工具
用法: python md2pdf.py input.md [output.pdf] [选项]
"""
import argparse
import sys
from pathlib import Path
from datetime import datetime
def main():
parser = argparse.ArgumentParser(
description='将Markdown文件转换为PDF',
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
示例:
%(prog)s document.md # 转换单个文件
%(prog)s document.md -o output.pdf # 指定输出文件
%(prog)s *.md # 批量转换
%(prog)s input.md -t "我的文档" -a "作者" # 添加标题和作者
"""
)
parser.add_argument('input', nargs='+', help='输入的Markdown文件')
parser.add_argument('-o', '--output', help='输出PDF文件路径')
parser.add_argument('-t', '--title', help='文档标题')
parser.add_argument('-a', '--author', help='作者')
parser.add_argument('-d', '--date', help='日期')
parser.add_argument('-s', '--style',
choices=['default', 'academic', 'modern', 'minimal'],
default='default',
help='样式主题')
parser.add_argument('--toc', action='store_true', help='生成目录')
parser.add_argument('--page-numbers', action='store_true',
help='添加页码')
parser.add_argument('--verbose', action='store_true', help='显示详细信息')
args = parser.parse_args()
# 导入转换器(确保已安装依赖)
try:
from markdown_to_pdf import MarkdownToPDF # 假设这是我们的转换器类
except ImportError:
print("错误: 请先安装依赖")
print("pip install markdown weasyprint jinja2")
sys.exit(1)
# 处理每个输入文件
for input_file in args.input:
if not Path(input_file).exists():
print(f"警告: 文件不存在 - {input_file}")
continue
# 确定输出文件名
if args.output:
if len(args.input) > 1:
print("警告: 批量转换时不能使用--output参数")
output_file = Path(input_file).with_suffix('.pdf')
else:
output_file = args.output
else:
output_file = Path(input_file).with_suffix('.pdf')
# 执行转换
try:
if args.verbose:
print(f"正在转换: {input_file} -> {output_file}")
converter = MarkdownToPDF(style=args.style)
# 如果没有指定标题,使用文件名
title = args.title or Path(input_file).stem
# 如果没有指定日期,使用当前日期
date = args.date or datetime.now().strftime('%Y-%m-%d')
converter.convert_file(
input_file,
output_file,
title=title,
author=args.author,
date=date
)
if args.verbose:
print(f"✅ 转换完成: {output_file}")
except Exception as e:
print(f"❌ 转换失败 {input_file}: {e}")
if args.verbose:
import traceback
traceback.print_exc()
if __name__ == '__main__':
main()
七、批量转换工具
python
import os
from pathlib import Path
from concurrent.futures import ThreadPoolExecutor
import time
class BatchMarkdownToPDF:
"""批量转换工具"""
def __init__(self, input_dir, output_dir=None, style='default', max_workers=4):
self.input_dir = Path(input_dir)
if output_dir:
self.output_dir = Path(output_dir)
self.output_dir.mkdir(parents=True, exist_ok=True)
else:
self.output_dir = self.input_dir / 'pdf_output'
self.output_dir.mkdir(exist_ok=True)
self.style = style
self.max_workers = max_workers
def find_markdown_files(self):
"""查找所有Markdown文件"""
patterns = ['*.md', '*.markdown', '*.mdown']
files = []
for pattern in patterns:
files.extend(self.input_dir.rglob(pattern))
return files
def convert_single(self, md_file):
"""转换单个文件"""
try:
relative_path = md_file.relative_to(self.input_dir)
output_path = self.output_dir / relative_path.with_suffix('.pdf')
# 创建输出目录结构
output_path.parent.mkdir(parents=True, exist_ok=True)
# 导入转换器
from markdown_to_pdf import MarkdownToPDF
converter = MarkdownToPDF(style=self.style)
converter.convert_file(
str(md_file),
str(output_path),
title=md_file.stem
)
return (True, md_file, output_path)
except Exception as e:
return (False, md_file, str(e))
def convert_all(self):
"""批量转换所有文件"""
md_files = self.find_markdown_files()
if not md_files:
print(f"在 {self.input_dir} 中没有找到Markdown文件")
return
print(f"找到 {len(md_files)} 个Markdown文件")
print(f"输出目录: {self.output_dir}")
start_time = time.time()
success_count = 0
# 使用多线程加速
with ThreadPoolExecutor(max_workers=self.max_workers) as executor:
results = list(executor.map(self.convert_single, md_files))
# 统计结果
for success, input_file, result in results:
if success:
print(f"✅ 成功: {input_file} -> {result}")
success_count += 1
else:
print(f"❌ 失败: {input_file} - {result}")
elapsed_time = time.time() - start_time
print(f"\n转换完成!")
print(f"成功: {success_count}/{len(md_files)}")
print(f"耗时: {elapsed_time:.2f}秒")
return success_count
# 使用示例
if __name__ == '__main__':
# 批量转换整个目录
batch_converter = BatchMarkdownToPDF(
input_dir='./docs',
output_dir='./pdf_docs',
style='modern',
max_workers=4
)
batch_converter.convert_all()
八、Web服务版本(Flask)
python
from flask import Flask, request, send_file, render_template_string
import tempfile
import os
from markdown_to_pdf import MarkdownToPDF # 使用前面的转换器类
app = Flask(__name__)
HTML_TEMPLATE = """
<!DOCTYPE html>
<html>
<head>
<title>Markdown转PDF在线工具</title>
<style>
body { font-family: Arial; max-width: 800px; margin: 0 auto; padding: 20px; }
.container { display: flex; gap: 20px; }
.editor { flex: 1; }
.preview { flex: 1; }
textarea { width: 100%; height: 400px; font-family: monospace; }
button { padding: 10px 20px; margin: 10px 0; }
.options { margin: 20px 0; }
label { display: block; margin: 5px 0; }
</style>
</head>
<body>
<h1>Markdown转PDF在线工具</h1>
<form method="post">
<div class="container">
<div class="editor">
<h3>编辑Markdown</h3>
<textarea name="markdown" placeholder="输入Markdown内容...">{{ markdown }}</textarea>
</div>
<div class="preview">
<h3>实时预览</h3>
<div id="preview">{{ preview|safe }}</div>
</div>
</div>
<div class="options">
<label>标题: <input type="text" name="title" value="{{ title }}"></label>
<label>作者: <input type="text" name="author" value="{{ author }}"></label>
<label>样式:
<select name="style">
<option value="default" {{ 'selected' if style=='default' }}>默认</option>
<option value="modern" {{ 'selected' if style=='modern' }}>现代</option>
<option value="academic" {{ 'selected' if style=='academic' }}>学术</option>
</select>
</label>
</div>
<button type="submit" name="action" value="preview">预览</button>
<button type="submit" name="action" value="download">下载PDF</button>
</form>
<script>
// 实时预览
document.querySelector('textarea').addEventListener('input', function() {
// 这里可以添加实时预览的JavaScript代码
});
</script>
</body>
</html>
"""
@app.route('/', methods=['GET', 'POST'])
def index():
if request.method == 'POST':
markdown = request.form.get('markdown', '')
title = request.form.get('title', '文档')
author = request.form.get('author', '')
style = request.form.get('style', 'default')
action = request.form.get('action', 'preview')
if action == 'preview':
# 预览模式
import markdown as md
preview_html = md.markdown(markdown)
return render_template_string(
HTML_TEMPLATE,
markdown=markdown,
preview=preview_html,
title=title,
author=author,
style=style
)
elif action == 'download':
# 生成PDF
try:
with tempfile.NamedTemporaryFile(
suffix='.pdf',
delete=False
) as tmp_file:
pdf_path = tmp_file.name
converter = MarkdownToPDF(style=style)
converter.convert_text(
markdown,
pdf_path,
title=title,
author=author
)
return send_file(
pdf_path,
as_attachment=True,
download_name=f'{title}.pdf'
)
except Exception as e:
return f"错误: {e}"
# GET请求显示空表单
return render_template_string(
HTML_TEMPLATE,
markdown='# 标题\n\n这里是内容...',
preview='<h1>标题</h1><p>这里是内容...</p>',
title='文档',
author='',
style='default'
)
if __name__ == '__main__':
app.run(debug=True, port=5000)
九、选择建议
| 方法 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| weasyprint + markdown | 简单易用,样式灵活,支持CSS | 需要安装依赖较多 | 大多数场景,推荐 |
| pypandoc | 功能最强大,支持多种格式 | 需要安装pandoc,配置复杂 | 需要高级格式控制 |
| md2pdf库 | 专门为此设计,简单 | 功能相对简单 | 快速简单转换 |
| ReportLab | 完全控制PDF生成 | 代码复杂,需要手动解析 | 需要高度自定义PDF |
| markdown-pdf | 命令行工具,方便集成 | 需要在系统安装 | 脚本或CI/CD环境 |
十、快速开始(最简方案)
python
# requirements.txt
markdown
weasyprint
# simple_converter.py
import markdown
from weasyprint import HTML
def quick_convert(md_text, output_file):
"""最简单快速的转换"""
html = markdown.markdown(md_text)
full_html = f"<html><body>{html}</body></html>"
HTML(string=full_html).write_pdf(output_file)
print(f"PDF已保存: {output_file}")
# 使用
with open("README.md", "r", encoding="utf-8") as f:
quick_convert(f.read(), "README.pdf")
推荐方案 :使用 weasyprint + markdown,功能完善,样式灵活,社区活跃,适合大多数需求。
结束语
Flutter是一个由Google开发的开源UI工具包,它可以让您在不同平台上创建高质量、美观的应用程序,而无需编写大量平台特定的代码。我将学习和深入研究Flutter的方方面面。从基础知识到高级技巧,从UI设计到性能优化,欢饮关注一起讨论学习,共同进入Flutter的精彩世界!