Initial commit
This commit is contained in:
215
marp_to_pdf.py
Executable file
215
marp_to_pdf.py
Executable file
@@ -0,0 +1,215 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Marp Markdown to PDF Converter
|
||||
Converts Markdown files to beautiful presentation PDFs using Marp CLI.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
import subprocess
|
||||
import shutil
|
||||
from pathlib import Path
|
||||
import argparse
|
||||
|
||||
def check_marp_cli():
|
||||
"""Check if Marp CLI is installed."""
|
||||
# Try marp-cli
|
||||
if shutil.which('marp'):
|
||||
return 'marp'
|
||||
|
||||
# Try npx
|
||||
if shutil.which('npx'):
|
||||
try:
|
||||
result = subprocess.run(
|
||||
['npx', '@marp-team/marp-cli', '--version'],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=10
|
||||
)
|
||||
if result.returncode == 0:
|
||||
return 'npx'
|
||||
except:
|
||||
pass
|
||||
|
||||
return None
|
||||
|
||||
def install_instructions():
|
||||
"""Print installation instructions."""
|
||||
print("\n❌ Marp CLI not found!")
|
||||
print("\n请安装Marp CLI:")
|
||||
print("\n方法1: 使用npm全局安装")
|
||||
print(" npm install -g @marp-team/marp-cli")
|
||||
print("\n方法2: 使用npx (无需安装)")
|
||||
print(" npx @marp-team/marp-cli --version")
|
||||
print("\n方法3: 使用Homebrew (macOS)")
|
||||
print(" brew install marp-cli")
|
||||
print()
|
||||
|
||||
def convert_markdown_to_pdf(input_file, output_file=None, theme='default', html_output=False):
|
||||
"""Convert Markdown to PDF using Marp."""
|
||||
|
||||
# Validate input file
|
||||
if not os.path.exists(input_file):
|
||||
print(f"❌ 错误: 输入文件 '{input_file}' 不存在!")
|
||||
return False
|
||||
|
||||
# Check Marp CLI
|
||||
marp_cmd = check_marp_cli()
|
||||
if not marp_cmd:
|
||||
install_instructions()
|
||||
return False
|
||||
|
||||
# Determine output file
|
||||
if output_file is None:
|
||||
output_file = Path(input_file).with_suffix('.pdf')
|
||||
|
||||
print("=" * 70)
|
||||
print("Marp Markdown转PDF工具")
|
||||
print("=" * 70)
|
||||
print(f"\n📄 转换Markdown为演示文稿PDF")
|
||||
print(f" 输入: {input_file}")
|
||||
print(f" 输出: {output_file}")
|
||||
print(f" 主题: {theme}\n")
|
||||
|
||||
try:
|
||||
# Build Marp command
|
||||
if marp_cmd == 'marp':
|
||||
cmd = ['marp']
|
||||
else: # npx
|
||||
cmd = ['npx', '@marp-team/marp-cli']
|
||||
|
||||
cmd.extend([
|
||||
input_file,
|
||||
'--pdf',
|
||||
'--allow-local-files',
|
||||
'--theme', theme,
|
||||
'-o', str(output_file)
|
||||
])
|
||||
|
||||
# Run Marp conversion
|
||||
print("⏳ 生成PDF...")
|
||||
result = subprocess.run(
|
||||
cmd,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=60
|
||||
)
|
||||
|
||||
if result.returncode != 0:
|
||||
print(f"❌ 转换失败!")
|
||||
print(f"错误信息: {result.stderr}")
|
||||
return False
|
||||
|
||||
# Get file size
|
||||
if os.path.exists(output_file):
|
||||
size_kb = os.path.getsize(output_file) / 1024
|
||||
print(f"\n✅ 成功生成PDF!")
|
||||
print(f" 大小: {size_kb:.1f} KB")
|
||||
|
||||
# Generate HTML if requested
|
||||
if html_output:
|
||||
html_file = Path(output_file).with_suffix('.html')
|
||||
print(f"\n📄 生成HTML版本...")
|
||||
|
||||
html_cmd = cmd.copy()
|
||||
# Remove --pdf and change output
|
||||
html_cmd = [c for c in html_cmd if c != '--pdf']
|
||||
html_cmd[-1] = str(html_file)
|
||||
|
||||
result = subprocess.run(
|
||||
html_cmd,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=60
|
||||
)
|
||||
|
||||
if result.returncode == 0 and os.path.exists(html_file):
|
||||
html_size_kb = os.path.getsize(html_file) / 1024
|
||||
print(f"✅ HTML生成成功!")
|
||||
print(f" 大小: {html_size_kb:.1f} KB")
|
||||
print(f"\n💡 打开查看:")
|
||||
print(f" PDF: open {output_file}")
|
||||
print(f" HTML: open {html_file}")
|
||||
else:
|
||||
print(f"\n💡 打开查看:")
|
||||
print(f" PDF: open {output_file}")
|
||||
else:
|
||||
print(f"\n💡 打开查看:")
|
||||
print(f" open {output_file}")
|
||||
|
||||
return True
|
||||
|
||||
except subprocess.TimeoutExpired:
|
||||
print("\n❌ 转换超时!")
|
||||
return False
|
||||
except Exception as e:
|
||||
print(f"\n❌ 转换失败: {str(e)}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
def ensure_marp_frontmatter(input_file):
|
||||
"""Check if Markdown has Marp frontmatter, add if missing."""
|
||||
with open(input_file, 'r', encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
|
||||
# Check if already has marp frontmatter
|
||||
if content.startswith('---\nmarp:') or 'marp: true' in content[:100]:
|
||||
return False # Already has frontmatter
|
||||
|
||||
# Add Marp frontmatter
|
||||
frontmatter = """---
|
||||
marp: true
|
||||
theme: default
|
||||
paginate: true
|
||||
---
|
||||
|
||||
"""
|
||||
|
||||
with open(input_file, 'w', encoding='utf-8') as f:
|
||||
f.write(frontmatter + content)
|
||||
|
||||
return True # Added frontmatter
|
||||
|
||||
def main():
|
||||
"""Main entry point."""
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Convert Markdown to PDF presentation using Marp'
|
||||
)
|
||||
parser.add_argument('input', help='Input Markdown file')
|
||||
parser.add_argument('output', nargs='?', help='Output PDF file (optional)')
|
||||
parser.add_argument(
|
||||
'--theme',
|
||||
choices=['default', 'gaia', 'uncover'],
|
||||
default='default',
|
||||
help='Marp theme to use'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--html',
|
||||
action='store_true',
|
||||
help='Also generate HTML output'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--add-frontmatter',
|
||||
action='store_true',
|
||||
help='Add Marp frontmatter if missing'
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# Add frontmatter if requested
|
||||
if args.add_frontmatter:
|
||||
if ensure_marp_frontmatter(args.input):
|
||||
print("✅ 已添加Marp前置元数据\n")
|
||||
|
||||
success = convert_markdown_to_pdf(
|
||||
args.input,
|
||||
args.output,
|
||||
args.theme,
|
||||
args.html
|
||||
)
|
||||
|
||||
sys.exit(0 if success else 1)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user