Cómo crear archivos PDF con Python y FPDF

Publicado el: 11/07/2026
Tempo de leitura: 4 minutos
Geração de arquivos PDF usando biblioteca FPDF em Python

Crear archivos PDF con Python es útil para automatizar facturas, certificados, informes, recibos, etiquetas y documentos personalizados. La biblioteca fpdf2 permite construir un PDF página por página, controlar fuentes, márgenes, imágenes, tablas, encabezados y saltos de página sin depender de una aplicación de escritorio.

En esta guía aprenderás a instalar la biblioteca, generar un primer documento, añadir párrafos, imágenes y tablas, trabajar con Unicode, reutilizar funciones y manejar errores de rutas y permisos. Para mantener las dependencias aisladas, comienza con la guía de entornos virtuales en Python.

Qué biblioteca instalar

Para proyectos nuevos instala fpdf2. El nombre del paquete y el nombre importado son diferentes:

python -m pip install fpdf2
from fpdf import FPDF

print("FPDF está disponible")

La documentación oficial de fpdf2 contiene tutoriales y la referencia completa. Aunque existen paquetes antiguos con nombres parecidos, evita instalar varias implementaciones en el mismo entorno.

Crear el primer PDF

from fpdf import FPDF

pdf = FPDF()
pdf.add_page()
pdf.set_font("Helvetica", size=16)
pdf.cell(text="Hola desde Python")
pdf.output("primer-documento.pdf")

La secuencia básica es siempre parecida: crear el objeto, añadir una página, elegir una fuente, insertar contenido y guardar el archivo. Sin una página o una fuente seleccionada, las llamadas de texto pueden fallar.

Elegir formato y orientación

pdf = FPDF(
    orientation="P",
    unit="mm",
    format="A4",
)
pdf.add_page()

P representa orientación vertical y L horizontal. Utilizar milímetros facilita trabajar con medidas de impresión. Configura los márgenes antes de añadir contenido:

pdf.set_margins(left=18, top=18, right=18)
pdf.set_auto_page_break(auto=True, margin=18)

Títulos y párrafos

cell() funciona bien con textos cortos. multi_cell() envuelve párrafos automáticamente.

from fpdf import FPDF

pdf = FPDF()
pdf.set_auto_page_break(auto=True, margin=15)
pdf.add_page()

pdf.set_font("Helvetica", style="B", size=20)
pdf.cell(
    0,
    12,
    "Informe mensual",
    new_x="LMARGIN",
    new_y="NEXT",
    align="C",
)

pdf.ln(6)
pdf.set_font("Helvetica", size=11)
pdf.multi_cell(
    0,
    6,
    "Este documento fue generado automáticamente con Python. "
    "El texto largo se divide en varias líneas.",
)

pdf.output("informe.pdf")

Los saltos automáticos evitan que el texto continúe fuera del área imprimible. No posiciones todos los elementos con coordenadas fijas cuando la longitud del contenido puede cambiar.

Encabezados y pies de página

Para repetir elementos en todas las páginas, crea una subclase:

from fpdf import FPDF


class InformePDF(FPDF):
    def header(self):
        self.set_font("Helvetica", style="B", size=10)
        self.cell(0, 8, "Informe de ventas", align="C")
        self.ln(12)

    def footer(self):
        self.set_y(-15)
        self.set_font("Helvetica", style="I", size=9)
        self.cell(0, 10, f"Página {self.page_no()}", align="C")

FPDF ejecuta estos métodos automáticamente. Mantén el encabezado y el pie pequeños para no reducir demasiado el área útil.

Añadir imágenes

from pathlib import Path
from fpdf import FPDF

logo = Path("recursos") / "logo.png"

pdf = FPDF()
pdf.add_page()

if logo.exists():
    pdf.image(str(logo), x=15, y=12, w=35)

pdf.set_y(55)
pdf.set_font("Helvetica", size=12)
pdf.cell(0, 8, "Documento con imagen")
pdf.output("documento-imagen.pdf")

Comprueba la existencia del archivo antes de insertarlo. La guía de pathlib en Python explica rutas portables y directorios. La documentación oficial de pathlib sirve como referencia para sus métodos.

Crear una tabla sencilla

from fpdf import FPDF

filas = [
    ("Producto", "Cantidad", "Precio"),
    ("Teclado", "2", "90,00"),
    ("Ratón", "3", "60,00"),
    ("Monitor", "1", "240,00"),
]

anchos = [80, 40, 50]
pdf = FPDF()
pdf.add_page()

for indice, fila in enumerate(filas):
    estilo = "B" if indice == 0 else ""
    pdf.set_font("Helvetica", style=estilo, size=10)

    for valor, ancho in zip(fila, anchos):
        pdf.cell(ancho, 9, valor, border=1)
    pdf.ln()

pdf.output("productos.pdf")

Las tablas simples pueden construirse con celdas y anchos calculados. Cuando el contenido puede ocupar varias líneas, necesitarás medir alturas y controlar los saltos de página.

Generar un informe desde datos

ventas = [
    {"cliente": "Ana", "total": 120.50},
    {"cliente": "Luis", "total": 89.90},
    {"cliente": "Sara", "total": 215.00},
]

pdf = FPDF()
pdf.set_auto_page_break(auto=True, margin=15)
pdf.add_page()
pdf.set_font("Helvetica", style="B", size=18)
pdf.cell(0, 12, "Resumen de ventas", new_x="LMARGIN", new_y="NEXT")

pdf.set_font("Helvetica", size=11)
for venta in ventas:
    linea = f"Cliente: {venta['cliente']} | Total: {venta['total']:.2f}"
    pdf.cell(0, 8, linea, new_x="LMARGIN", new_y="NEXT")

pdf.output("resumen-ventas.pdf")

Los datos pueden proceder de un CSV, una base de datos, una API o un DataFrame. La guía de archivos CSV en Python y la de Pandas para principiantes muestran dos fuentes comunes.

Separar cálculos y presentación

No mezcles todas las reglas de negocio con el diseño del PDF. Calcula y valida los datos antes de renderizarlos.

def calcular_total(items):
    return sum(
        item["cantidad"] * item["precio_unitario"]
        for item in items
    )

Una función pequeña es más fácil de probar. Consulta la guía de funciones en Python para organizar responsabilidades y retornos.

Crear una función reutilizable

from pathlib import Path
from fpdf import FPDF


def crear_informe(titulo, lineas, destino):
    destino = Path(destino)
    destino.parent.mkdir(parents=True, exist_ok=True)

    pdf = FPDF()
    pdf.set_auto_page_break(auto=True, margin=15)
    pdf.add_page()
    pdf.set_font("Helvetica", style="B", size=18)
    pdf.cell(0, 12, titulo, new_x="LMARGIN", new_y="NEXT")
    pdf.ln(4)

    pdf.set_font("Helvetica", size=11)
    for linea in lineas:
        pdf.multi_cell(0, 6, linea)
        pdf.ln(2)

    pdf.output(str(destino))
    return destino

Unicode y fuentes personalizadas

Las fuentes básicas del PDF no incluyen todos los caracteres. Para textos multilingües registra una fuente Unicode que tu proyecto tenga permiso para distribuir.

pdf = FPDF()
pdf.add_page()
pdf.add_font("DejaVu", fname="fuentes/DejaVuSans.ttf")
pdf.set_font("DejaVu", size=12)
pdf.multi_cell(0, 7, "Texto internacional: café, acción, español")
pdf.output("unicode.pdf")

No supongas que una fuente instalada en tu ordenador existe en el servidor. Incluye el archivo dentro de una ruta controlada y revisa su licencia.

Manejar errores de escritura

from pathlib import Path

salida = Path("informes") / "resultado.pdf"

try:
    salida.parent.mkdir(parents=True, exist_ok=True)
    pdf.output(str(salida))
except PermissionError:
    print("No hay permiso para escribir en esta carpeta")
except OSError as error:
    print(f"No fue posible crear el PDF: {error}")

Los fallos comunes incluyen imágenes inexistentes, fuentes ausentes, rutas inválidas, permisos y caracteres no cubiertos por la fuente.

Errores frecuentes

  • Olvidar add_page().
  • Escribir texto antes de seleccionar una fuente.
  • No activar los saltos de página automáticos.
  • Usar coordenadas rígidas para contenido variable.
  • Confiar en rutas relativas sin comprobar el directorio actual.
  • Mezclar cálculos y diseño en una única función enorme.
  • Sobrescribir un archivo existente sin validación.
  • Usar una fuente sin los caracteres necesarios.

Probar la generación

Las pruebas no necesitan comprobar visualmente cada píxel. Puedes verificar que el archivo se crea, tiene tamaño mayor que cero y se escribe en el directorio esperado. Para cálculos de facturas, prueba los totales por separado con Pytest.

Conclusión

FPDF ofrece una forma directa de crear PDF con Python. Empieza con páginas, fuentes y párrafos, y después añade imágenes, tablas, encabezados, pies y fuentes Unicode. Mantén las rutas controladas, valida los recursos externos y activa saltos automáticos.

La solución será más fácil de mantener cuando los cálculos estén separados del diseño y la generación se concentre en funciones pequeñas. Así, un script inicial puede convertirse en un sistema reutilizable de facturas, certificados e informes.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Contenido del artículo

    Artículos relacionados

    Logos do Python e Excel lado a lado representando a importação de dados do Excel para Python.
    Automatización y Scripts
    Foto de perfil de Leandro Hirt da Academify

    Cómo importar archivos Excel en Python con Pandas

    Importa archivos Excel en Python con Pandas y openpyxl: hojas, columnas, tipos, fechas, valores ausentes, limpieza y exportación.

    Ler mais

    Tempo de leitura: 3 minutos
    11/07/2026
    Python e ícone de e-mail sobre teclado de notebook
    Automatización y Scripts
    Foto de perfil de Leandro Hirt da Academify

    Cómo automatizar correos electrónicos con Python

    Automatiza correos con Python usando EmailMessage y smtplib, variables de entorno, HTML, adjuntos, destinatarios múltiples y manejo de errores.

    Ler mais

    Tempo de leitura: 3 minutos
    11/07/2026
    Logo do Python com o texto 'Python argparse CLI' abaixo
    Automatización y Scripts
    Foto de perfil de Leandro Hirt da Academify

    Cómo crear una CLI en Python con argparse

    Crea una CLI en Python con argparse: argumentos, banderas, tipos, choices, subcomandos, validación, pruebas y empaquetado moderno.

    Ler mais

    Tempo de leitura: 3 minutos
    11/07/2026