feat: issue/0020 — generacion de PDFs en Python y Go
Añade 3 tipos Python (PDFDoc, PDFPage, PDFStyle) y 10 funciones Python para construir PDFs con fpdf2 (builder fluent), fusionar PDFs con pypdf y convertir HTML/Markdown a PDF via weasyprint (stub si no disponible). Añade pdf_simple_report en Go como stub hasta que go-pdf/fpdf se integre. - python/types/infra/: pdf_doc, pdf_page, pdf_style - python/functions/infra/: pdf_create, pdf_add_page, pdf_add_text, pdf_add_table, pdf_add_image, pdf_add_header_footer, pdf_from_html, pdf_from_markdown, pdf_merge, pdf_save - functions/infra/pdf_simple_report.go: stub Go con ReportSection/ReportTable - 17 tests Python pasando (pytest) - fpdf2 y pypdf añadidos via uv al venv Python Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
"""pdf_from_markdown — convierte Markdown a HTML y luego a PDF usando weasyprint."""
|
||||
|
||||
import sys
|
||||
import os
|
||||
|
||||
_infra_dir = os.path.dirname(__file__)
|
||||
sys.path.insert(0, _infra_dir)
|
||||
|
||||
|
||||
def pdf_from_markdown(
|
||||
markdown_string: str,
|
||||
output_path: str,
|
||||
css: str = "",
|
||||
page_size: str = "A4",
|
||||
) -> str:
|
||||
"""Convierte un string Markdown a PDF via HTML + weasyprint.
|
||||
|
||||
Convierte Markdown a HTML con la libreria `markdown`, luego genera
|
||||
el PDF con weasyprint. Incluye CSS por defecto para tipografia legible.
|
||||
|
||||
NOTA: Requiere `weasyprint` y `markdown` instalados:
|
||||
pip install weasyprint markdown
|
||||
Y dependencias de sistema weasyprint: pango, cairo, gdk-pixbuf.
|
||||
|
||||
Args:
|
||||
markdown_string: contenido Markdown como string.
|
||||
output_path: ruta donde guardar el PDF generado.
|
||||
css: CSS adicional a aplicar sobre los estilos por defecto.
|
||||
page_size: tamaño de pagina: 'A4', 'letter'. Por defecto 'A4'.
|
||||
|
||||
Returns:
|
||||
output_path con el PDF guardado.
|
||||
|
||||
Raises:
|
||||
RuntimeError: si weasyprint o markdown no estan instalados.
|
||||
"""
|
||||
try:
|
||||
import markdown as md_lib
|
||||
except ImportError as exc:
|
||||
raise RuntimeError(
|
||||
"markdown no esta instalado. Instalar con: pip install markdown"
|
||||
) from exc
|
||||
|
||||
try:
|
||||
import weasyprint
|
||||
except ImportError as exc:
|
||||
raise RuntimeError(
|
||||
"weasyprint no esta instalado. "
|
||||
"Instalar con: pip install weasyprint\n"
|
||||
"Dependencias de sistema (Linux): "
|
||||
"apt install libpango-1.0-0 libcairo2 libgdk-pixbuf-2.0-0"
|
||||
) from exc
|
||||
|
||||
# Convertir Markdown a HTML
|
||||
html_body = md_lib.markdown(
|
||||
markdown_string,
|
||||
extensions=["tables", "fenced_code", "nl2br"],
|
||||
)
|
||||
|
||||
default_css = """
|
||||
body {
|
||||
font-family: Helvetica, Arial, sans-serif;
|
||||
font-size: 11pt;
|
||||
line-height: 1.5;
|
||||
color: #222;
|
||||
max-width: 170mm;
|
||||
margin: 0 auto;
|
||||
}
|
||||
h1, h2, h3 { color: #333; margin-top: 1.2em; }
|
||||
h1 { font-size: 18pt; border-bottom: 1px solid #ccc; }
|
||||
h2 { font-size: 14pt; }
|
||||
h3 { font-size: 12pt; }
|
||||
code { background: #f5f5f5; padding: 1px 4px; border-radius: 3px; font-size: 9pt; }
|
||||
pre { background: #f5f5f5; padding: 8px; border-radius: 4px; overflow: auto; }
|
||||
table { border-collapse: collapse; width: 100%; }
|
||||
th, td { border: 1px solid #ccc; padding: 6px; text-align: left; }
|
||||
th { background: #eee; }
|
||||
blockquote { border-left: 3px solid #ccc; margin: 0; padding-left: 12px; color: #555; }
|
||||
"""
|
||||
|
||||
page_css = f"@page {{ size: {page_size}; margin: 20mm; }}"
|
||||
combined_css = page_css + "\n" + default_css + "\n" + css
|
||||
|
||||
html = f"""<!DOCTYPE html>
|
||||
<html><head><meta charset="utf-8"></head>
|
||||
<body>{html_body}</body></html>"""
|
||||
|
||||
wp_html = weasyprint.HTML(string=html)
|
||||
stylesheet = weasyprint.CSS(string=combined_css)
|
||||
wp_html.write_pdf(output_path, stylesheets=[stylesheet])
|
||||
|
||||
return output_path
|
||||
Reference in New Issue
Block a user