feat: Add pdf-creator skill for markdown to PDF conversion
- Add pdf-creator skill with Chinese font support (weasyprint) - Include md_to_pdf.py for single file conversion - Include batch_convert.py for multiple files - Support formal documents: legal filings, reports, trademark applications - Update marketplace to v1.14.0 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
78
pdf-creator/scripts/batch_convert.py
Normal file
78
pdf-creator/scripts/batch_convert.py
Normal file
@@ -0,0 +1,78 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Batch convert multiple markdown files to PDF.
|
||||
|
||||
Usage:
|
||||
python batch_convert.py file1.md file2.md file3.md
|
||||
python batch_convert.py *.md
|
||||
python batch_convert.py --output-dir ./pdfs file1.md file2.md
|
||||
|
||||
Requirements:
|
||||
pip install weasyprint markdown
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from md_to_pdf import markdown_to_pdf
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Batch convert markdown files to PDF with Chinese font support'
|
||||
)
|
||||
parser.add_argument(
|
||||
'files',
|
||||
nargs='+',
|
||||
help='Markdown files to convert'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--output-dir', '-o',
|
||||
type=str,
|
||||
default=None,
|
||||
help='Output directory for PDFs (default: same as input)'
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
output_dir = Path(args.output_dir) if args.output_dir else None
|
||||
if output_dir:
|
||||
output_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
success = 0
|
||||
failed = 0
|
||||
|
||||
for md_file in args.files:
|
||||
md_path = Path(md_file)
|
||||
|
||||
if not md_path.exists():
|
||||
print(f"[SKIP] File not found: {md_file}")
|
||||
failed += 1
|
||||
continue
|
||||
|
||||
if not md_path.suffix.lower() == '.md':
|
||||
print(f"[SKIP] Not a markdown file: {md_file}")
|
||||
failed += 1
|
||||
continue
|
||||
|
||||
# Determine output path
|
||||
if output_dir:
|
||||
pdf_file = str(output_dir / md_path.with_suffix('.pdf').name)
|
||||
else:
|
||||
pdf_file = str(md_path.with_suffix('.pdf'))
|
||||
|
||||
try:
|
||||
print(f"Converting: {md_file} -> {pdf_file}")
|
||||
markdown_to_pdf(str(md_path), pdf_file)
|
||||
success += 1
|
||||
except Exception as e:
|
||||
print(f"[ERROR] Failed to convert {md_file}: {e}")
|
||||
failed += 1
|
||||
|
||||
print(f"\nCompleted: {success} succeeded, {failed} failed")
|
||||
sys.exit(0 if failed == 0 else 1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
198
pdf-creator/scripts/md_to_pdf.py
Normal file
198
pdf-creator/scripts/md_to_pdf.py
Normal file
@@ -0,0 +1,198 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Markdown to PDF converter with Chinese font support.
|
||||
|
||||
Converts markdown files to PDF using weasyprint, with proper Chinese typography.
|
||||
Designed for formal documents (trademark filings, legal documents, reports).
|
||||
|
||||
Usage:
|
||||
python md_to_pdf.py input.md output.pdf
|
||||
python md_to_pdf.py input.md # outputs input.pdf
|
||||
|
||||
Requirements:
|
||||
pip install weasyprint markdown
|
||||
|
||||
macOS environment setup (if needed):
|
||||
export DYLD_LIBRARY_PATH="/opt/homebrew/lib:$DYLD_LIBRARY_PATH"
|
||||
"""
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import markdown
|
||||
from weasyprint import CSS, HTML
|
||||
|
||||
|
||||
# CSS with Chinese font support
|
||||
CSS_STYLES = """
|
||||
@page {
|
||||
size: A4;
|
||||
margin: 2.5cm 2cm;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Songti SC', 'SimSun', 'STSong', 'Noto Serif CJK SC', serif;
|
||||
font-size: 12pt;
|
||||
line-height: 1.8;
|
||||
color: #000;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-family: 'Heiti SC', 'SimHei', 'STHeiti', 'Noto Sans CJK SC', sans-serif;
|
||||
font-size: 18pt;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
margin-top: 0;
|
||||
margin-bottom: 1.5em;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-family: 'Heiti SC', 'SimHei', 'STHeiti', 'Noto Sans CJK SC', sans-serif;
|
||||
font-size: 14pt;
|
||||
font-weight: bold;
|
||||
margin-top: 1.5em;
|
||||
margin-bottom: 0.8em;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-family: 'Heiti SC', 'SimHei', 'STHeiti', 'Noto Sans CJK SC', sans-serif;
|
||||
font-size: 12pt;
|
||||
font-weight: bold;
|
||||
margin-top: 1em;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0.8em 0;
|
||||
text-align: justify;
|
||||
}
|
||||
|
||||
ul, ol {
|
||||
margin: 0.8em 0;
|
||||
padding-left: 2em;
|
||||
}
|
||||
|
||||
li {
|
||||
margin: 0.4em 0;
|
||||
}
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
margin: 1em 0;
|
||||
font-size: 10pt;
|
||||
table-layout: fixed;
|
||||
}
|
||||
|
||||
th, td {
|
||||
border: 1px solid #666;
|
||||
padding: 8px 6px;
|
||||
text-align: left;
|
||||
word-wrap: break-word;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
th {
|
||||
background-color: #f0f0f0;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
hr {
|
||||
border: none;
|
||||
border-top: 1px solid #ccc;
|
||||
margin: 1.5em 0;
|
||||
}
|
||||
|
||||
strong {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
code {
|
||||
font-family: 'SF Mono', 'Monaco', 'Menlo', monospace;
|
||||
font-size: 10pt;
|
||||
background-color: #f5f5f5;
|
||||
padding: 0.2em 0.4em;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
pre {
|
||||
background-color: #f5f5f5;
|
||||
padding: 1em;
|
||||
overflow-x: auto;
|
||||
font-size: 10pt;
|
||||
line-height: 1.4;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
border-left: 3px solid #ccc;
|
||||
margin: 1em 0;
|
||||
padding-left: 1em;
|
||||
color: #555;
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
def markdown_to_pdf(md_file: str, pdf_file: str | None = None) -> str:
|
||||
"""
|
||||
Convert markdown file to PDF with Chinese font support.
|
||||
|
||||
Args:
|
||||
md_file: Path to input markdown file
|
||||
pdf_file: Path to output PDF file (optional, defaults to same name as input)
|
||||
|
||||
Returns:
|
||||
Path to generated PDF file
|
||||
"""
|
||||
md_path = Path(md_file)
|
||||
|
||||
if pdf_file is None:
|
||||
pdf_file = str(md_path.with_suffix('.pdf'))
|
||||
|
||||
# Read markdown content
|
||||
md_content = md_path.read_text(encoding='utf-8')
|
||||
|
||||
# Convert to HTML
|
||||
html_content = markdown.markdown(
|
||||
md_content,
|
||||
extensions=['tables', 'fenced_code', 'codehilite', 'toc']
|
||||
)
|
||||
|
||||
# Create full HTML document
|
||||
full_html = f"""<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>{md_path.stem}</title>
|
||||
</head>
|
||||
<body>
|
||||
{html_content}
|
||||
</body>
|
||||
</html>"""
|
||||
|
||||
# Generate PDF
|
||||
HTML(string=full_html).write_pdf(pdf_file, stylesheets=[CSS(string=CSS_STYLES)])
|
||||
|
||||
return pdf_file
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage: python md_to_pdf.py <input.md> [output.pdf]")
|
||||
print("\nConverts markdown to PDF with Chinese font support.")
|
||||
sys.exit(1)
|
||||
|
||||
md_file = sys.argv[1]
|
||||
pdf_file = sys.argv[2] if len(sys.argv) > 2 else None
|
||||
|
||||
if not Path(md_file).exists():
|
||||
print(f"Error: File not found: {md_file}")
|
||||
sys.exit(1)
|
||||
|
||||
output = markdown_to_pdf(md_file, pdf_file)
|
||||
print(f"Generated: {output}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user