Skip to main content

markdown-to-pdf

Converting Markdown to professional PDFs using Pandoc, WeasyPrint, ReportLab, and related tools

Quellinformationen

Repository
cosmicstack-labs/mercury-agent-skills
Letzte Quellaktivität
12. Mai 2026 um 09:02
Erkannte Sprache von SKILL.md
Englisch
Sterne
476
Forks
63

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
name
markdown-to-pdf
description
Converting Markdown to professional PDFs using Pandoc, WeasyPrint, ReportLab, and related tools
metadata
{"author":"cosmicstack-labs","version":"1.0.0","category":"pdf-generation","tags":["markdown","pdf","pandoc","weasyprint","reportlab","conversion"]}
# Markdown to PDF Conversion Convert Markdown documents into polished, production-ready PDFs. This skill covers the major toolchains — Pandoc, WeasyPrint, ReportLab — plus CSS print styling, template systems, and batch conversion workflows. --- ## Toolchain Overview | Tool | Approach | Best For | Output Quality | |------|----------|----------|----------------| | **Pandoc** | Markdown → PDF via LaTeX/Context/Wkhtmltopdf | Books, papers, reports | High | | **WeasyPrint** | Markdown → HTML → PDF via CSS print | Web-like documents, branded PDFs | High | | **ReportLab** | Programmatic PDF generation via Python | Dynamic, data-driven PDFs | Very High | | **md-to-pdf** | Node.js CLI for quick markdown → PDF | Simple documents, quick output | Medium | | **Puppeteer/Playwright** | Markdown → HTML → Headless browser → PDF | Pixel-perfect web-to-PDF | Very High | --- ## 1. Pandoc Workflows Pandoc is the Swiss Army knife of document conversion. It reads Markdown and outputs PDF via an intermediate engine (default: LaTeX). ### Basic Conversion ```bash # Simple markdown to PDF (uses pdflatex) pandoc input.md -o output.pdf # With metadata file pandoc input.md --metadata-file=metadata.yaml -o output.pdf # Specify output engine pandoc input.md --pdf-engine=xelatex -o output.pdf # Using wkhtmltopdf instead of LaTeX pandoc input.md --pdf-engine=wkhtmltopdf -o output.pdf ``` ### Advanced Pandoc with Templates ```bash # Custom LaTeX template pandoc input.md \ --template=custom-template.tex \ --pdf-engine=xelatex \ --toc \ --number-sections \ -o output.pdf # With bibliography pandoc input.md \ --bibliography=references.bib \ --csl=ieee.csl \ --citeproc \ -o output.pdf # Custom font and margins pandoc input.md \ -V geometry:"top=2cm, bottom=2cm, left=2.5cm, right=2.5cm" \ -V mainfont="Times New Roman" \ -V fontsize=12pt \ -o output.pdf ``` ### Metadata YAML for Pandoc ```yaml # metadata.yaml --- title: "Technical Report on Distributed Systems" author: - "Jane Doe" - "John Smith" date: "2025-01-15" subtitle: "Performance Analysis of Event-Driven Architectures" abstract: | This report analyzes the performance characteristics of event-driven architectures in distributed systems, comparing Apache Kafka, RabbitMQ, and AWS SQS across latency, throughput, and fault tolerance metrics. keywords: [distributed-systems, event-driven, kafka, rabbitmq, performance] lang: en-US geometry: - top=25mm - bottom=25mm - left=30mm - right=25mm fontsize: 11pt mainfont: "DejaVu Serif" monofont: "DejaVu Sans Mono" toc: true toc-depth: 3 numbersections: true linestretch: 1.5 --- ``` ### Pandoc Filter: Custom Transformations ```python #!/usr/bin/env python3 """Pandoc filter to add custom styling to code blocks.""" import pandocfilters as pf def code_blocks(key, value, format, meta): """Wrap code blocks in a styled container.""" if key == 'CodeBlock': [[ident, classes, keyvals], code] = value if 'python' in classes: # Add a custom div wrapper for Python code return pf.Div( ([ident, ['python-block'], keyvals], [pf.CodeBlock([ident, classes, keyvals], code)]) ) if __name__ == '__main__': pf.toJSONFilter(code_blocks) ``` ```bash # Use the filter pandoc input.md --filter=./code_styler.py -o output.pdf ``` --- ## 2. WeasyPrint: HTML/CSS to PDF WeasyPrint renders HTML with CSS print styles into PDFs. It's ideal for documents that need pixel-perfect branding, colors, and web-like layouts. ### Basic WeasyPrint Workflow ```python """Convert HTML to PDF using WeasyPrint.""" from weasyprint import HTML # Basic conversion HTML('document.html').write_pdf('output.pdf') # From a URL HTML('https://example.com/report').write_pdf('webpage.pdf') # From a string html_content = """ <html> <body> <h1>Hello World</h1> <p>This is a PDF generated from an HTML string.</p> </body> </html> """ HTML(string=html_content).write_pdf('from_string.pdf') ``` ### Markdown → HTML → PDF Pipeline ```python """Full pipeline: Markdown to HTML to PDF with CSS styling.""" import markdown from weasyprint import HTML def markdown_to_pdf(md_path, css_path, output_path): """Convert markdown to PDF through HTML intermediate.""" with open(md_path, 'r') as f: md_content = f.read() # Convert markdown to HTML html_content = markdown.markdown( md_content, extensions=['tables', 'fenced_code', 'codehilite', 'toc', 'sane_lists', 'attr_list'] ) # Wrap in full HTML document full_html = f""" <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <link rel="stylesheet" href="{css_path}"> </head> <body> {html_content} </body> </html> """ # Generate PDF HTML(string=full_html).write_pdf(output_path) print(f"PDF generated: {output_path}") # Usage markdown_to_pdf('report.md', 'print.css', 'report.pdf') ``` ### CSS Print Stylesheet Template ```css /* print.css — Professional print stylesheet for PDF generation */ /* Page setup */ @page { size: A4; margin: 2.5cm 2cm 2.5cm 2cm; @top-center { content: element(pageHeader); font-size: 9pt; color: #666; } @bottom-center { content: counter(page) " / " counter(pages); font-size: 9pt; color: #666; } @bottom-left { content: "Confidential"; font-size: 8pt; color: #999; font-style: italic; } } /* First page — no header, different margins */ @page:first { margin-top: 4cm; @top-center { content: none; } } /* Section start — reset page counter */ @page chapter { @top-center { content: "Chapter " counter(chapter); } } /* Base typography */ body { font-family: "DejaVu Serif", Georgia, "Times New Roman", serif; font-size: 11pt; line-height: 1.6; color: #1a1a1a; counter-reset: h2 h3 figure table; } /* Heading styles */ h1 { font-size: 24pt; font-weight: bold; color: #1a1a1a; page-break-before: always; page-break-after: avoid; margin-top: 2cm; border-bottom: 2px solid #333; padding-bottom: 8pt; } h1:first-of-type { page-break-before: avoid; } h2 { font-size: 18pt; font-weight: bold; color: #333; page-break-after: avoid; margin-top: 1.5cm; counter-increment: h2; } h2::before { content: counter(h2) ". "; } h3 { font-size: 14pt; font-weight: bold; color: #555; page-break-after: avoid; margin-top: 1cm; counter-increment: h3; } h3::before { content: counter(h2) "." counter(h3) " "; } /* Paragraphs */ p { text-align: justify; orphans: 3; widows: 3; } /* Code blocks */ pre { font-family: "DejaVu Sans Mono", "Courier New", monospace; font-size: 9pt; background: #f5f5f5; border: 1px solid #ddd; border-left: 3px solid #007acc; padding: 12px; page-break-inside: avoid; white-space: pre-wrap; word-wrap: break-word; } code { font-family: "DejaVu Sans Mono", "Courier New", monospace; font-size: 9pt; background: #f0f0f0; padding: 1px 4px; border-radius: 2px; } pre code { background: none; padding: 0; } /* Tables */ table { width: 100%; border-collapse: collapse; margin: 1em 0; font-size: 10pt; page-break-inside: auto; } thead { display: table-header-group; } tr { page-break-inside: avoid; page-break-after: auto; } th { background: #2c3e50; color: white; font-weight: bold; padding: 8px 12px; text-align: left; } td { padding: 6px 12px; border-bottom: 1px solid #ddd; } tr:nth-child(even) { background: #f9f9f9; } /* Images */ img { max-width: 100%; height: auto; page-break-inside: avoid; } figure { margin: 1em 0; text-align: center; page-break-inside: avoid; } figcaption { font-size: 10pt; font-style: italic; color: #666; margin-top: 4px; } /* Links */ a { color: #0066cc; text-decoration: none; } /* Lists */ ul, ol { margin: 0.5em 0; padding-left: 2em; } li { margin: 0.3em 0; } /* Blockquotes */ blockquote { border-left: 4px solid #2c3e50; margin: 1em 0; padding: 0.5em 1em; background: #f9f9f9; font-style: italic; } /* Cover page */ .cover-page { page-break-after: always; text-align: center; padding-top: 6cm; } .cover-page h1 { font-size: 32pt; border: none; margin-bottom: 0.5cm; } .cover-page .subtitle { font-size: 18pt; color: #666; margin-bottom: 2cm; } .cover-page .author { font-size: 14pt; color: #333; } .cover-page .date { font-size: 12pt; color: #999; margin-top: 1cm; } /* Table of contents */ .toc { page-break-after: always; } .toc h2 { border: none; font-size: 20pt; } .toc ul { list-style: none; padding: 0; } .toc li { padding: 4px 0; border-bottom: 1px dotted #ccc; } .toc a { color: #333; text-decoration: none; } .toc .toc-h2 { font-weight: bold; padding-left: 0; } .toc .toc-h3 { padding-left: 2em; font-size: 10pt; } ``` --- ## 3. ReportLab: Programmatic PDF Generation ReportLab gives you complete control over PDF layout programmatically from Python. ### Basic ReportLab Document ```python """Create a basic PDF with ReportLab.""" from reportlab.lib.pagesizes import A4 from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle from reportlab.lib.units import cm, mm from reportlab.lib import colors from reportlab.platypus import ( SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle, Image, PageBreak, ListFlowable, ListItem ) from reportlab.lib.enums import TA_CENTER, TA_JUSTIFY def create_report(output_path): """Generate a professional report PDF.""" doc = SimpleDocTemplate( output_path, pagesize=A4, rightMargin=2*cm, leftMargin=2*cm, topMargin=2*cm, bottomMargin=2*cm, title="Annual Report 2025", author="Data Analytics Team", ) styles = getSampleStyleSheet() story = [] # Title page title_style = ParagraphStyle( 'CustomTitle', parent=styles['Title'], fontSize=28, leading=34, spaceAfter=20, alignment=TA_CENTER, textColor=colors.HexColor('#1a1a2e'), ) story.append(Spacer(1, 5*cm)) story.append(Paragraph("Annual Report 2025", title_style))
Auf GitHub ansehen
Diese SKILL.md ist sehr gross, daher zeigt SkillsMP hier nur den ersten Abschnitt. Auf GitHub ansehen