Add md-to-pdf.sh: convert Markdown to PDF via python-markdown + weasyprint

Companion to docs/md-to-html.sh, for cases needing a standalone PDF
rather than a themed HTML page.
main
Amir Alexander Abdelbaki 2026-07-21 13:32:10 +02:00
parent c1e54f4f75
commit fa78fc9a66
1 changed files with 86 additions and 0 deletions

86
docs/md-to-pdf.sh Executable file
View File

@ -0,0 +1,86 @@
#!/usr/bin/env bash
# md-to-pdf.sh — Convert a Markdown file to PDF.
#
# Usage:
# md-to-pdf.sh input.md [output.pdf]
#
# output.pdf defaults to input's basename with a .pdf extension, written
# next to input.md.
#
# Requires: python3 with the 'markdown' and 'weasyprint' packages
# sudo pacman -S python-markdown python-weasyprint
set -euo pipefail
if [[ $# -lt 1 ]]; then
echo "Usage: $0 input.md [output.pdf]" >&2
exit 1
fi
src="$1"
[[ -f "$src" ]] || { echo "md-to-pdf: file not found: $src" >&2; exit 1; }
out="${2:-${src%.*}.pdf}"
for mod in markdown weasyprint; do
python3 -c "import $mod" 2>/dev/null || {
echo "md-to-pdf: missing python module '$mod' — install with:" >&2
echo " sudo pacman -S python-markdown python-weasyprint" >&2
exit 1
}
done
title=$(grep -m1 '^# ' "$src" | sed 's/^# //' || true)
[[ -z "$title" ]] && title="$(basename "${src%.*}")"
python3 - "$src" "$out" "$title" <<'PYEOF'
import sys
import markdown
from weasyprint import HTML
src, out, title = sys.argv[1], sys.argv[2], sys.argv[3]
with open(src, encoding="utf-8") as fh:
text = fh.read()
body_html = markdown.markdown(
text,
extensions=["tables", "fenced_code", "toc", "def_list"],
)
css = """
@page { size: A4; margin: 2cm; }
body {
font-family: 'DejaVu Sans', sans-serif;
font-size: 11pt;
line-height: 1.5;
color: #1a1a1a;
}
h1, h2, h3, h4 { font-weight: 700; line-height: 1.25; margin: 1.4em 0 0.5em; }
h1 { font-size: 1.9em; border-bottom: 2px solid #333; padding-bottom: 0.2em; }
h2 { font-size: 1.4em; border-bottom: 1px solid #999; padding-bottom: 0.15em; }
h3 { font-size: 1.15em; }
p, li { margin: 0.4em 0; }
code, pre {
font-family: 'DejaVu Sans Mono', monospace;
font-size: 0.85em;
background: #f2f2f2;
border-radius: 3px;
}
code { padding: 0.1em 0.35em; }
pre { padding: 0.8em 1em; overflow-x: auto; white-space: pre-wrap; }
pre code { padding: 0; background: none; }
table { width: 100%; border-collapse: collapse; margin: 1em 0; font-size: 0.85em; }
th, td { border: 1px solid #999; padding: 0.4em 0.6em; text-align: left; vertical-align: top; }
th { background: #e5e5e5; }
tr:nth-child(even) td { background: #fafafa; }
blockquote { border-left: 4px solid #999; margin: 1em 0; padding: 0.3em 1em; color: #444; }
a { color: #1a4fa0; }
"""
html = f"<!DOCTYPE html><html><head><meta charset='utf-8'><title>{title}</title>" \
f"<style>{css}</style></head><body>{body_html}</body></html>"
HTML(string=html, base_url=src).write_pdf(out)
print(f"Wrote {out}")
PYEOF