Skip to content

Tutorial

Documentación completa de los métodos: Documentación de la API de fpdf.FPDF

Tutorial 1 - Ejemplo básico

Empecemos con el ejemplo clásico:

from fpdf import FPDF

pdf = FPDF()
pdf.add_page()
pdf.set_font("helvetica", "B", 16)
pdf.cell(40, 10, "Hello World!")
pdf.output("tuto1.pdf")

PDF resultante

Luego de incluir la biblioteca, creamos un objeto FPDF. El constructor FPDF es usado aquí con los valores predeterminados: Las páginas están en A4 vertical y la unidad de medida es milímetros. Podría haberse especificado explícitamente con:

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

Es posible configurar el PDF en modo horizontal (L) o usar otros formatos de página como carta (Letter) y oficio (Legal) y unidades de medida (pt, cm, in).

Por el momento no hay una página, entonces tenemos que agregar una con add_page. El origen es la esquina superior izquierda y la posición actual está ubicada por defecto a 1 cm de los bordes; los márgenes pueden ser cambiados con set_margins.

Antes de que podamos imprimir texto, es obligatorio seleccionar una fuente con set_font, de lo contrario, el documento sería inválido. Elegimos helvetica en negrita 16:

pdf.set_font('helvetica', 'B', 16)

Podríamos haber especificado cursiva con I, subrayado con U o fuente regular con una cadena de texto vacía (o cualquier combinación). Nota que el tamaño de la fuente es dado en puntos, no en milímetros (u otra unidad de medida del usuario); ésta es la única excepción. Las otras fuentes estándar son Times, Courier, Symbol y ZapfDingbats.

Podemos ahora imprimir una celda con cell. Una celda es un área rectangular, posiblemente enmarcada, que contiene algún texto. Se imprime en la posición actual. Especificamos sus dimensiones, su texto (centrado o alineado), si los bordes deberían ser dibujados, y a donde la posición actual se mueve después (a la derecha, abajo o al principio de la próxima linea). Para agregar un marco, haremos esto:

pdf.cell(40, 10, '¡Hola mundo!', 1)

Para agregar una nueva celda próxima a él, con texto centrado y luego ir a la siguiente línea, haríamos:

pdf.cell(60, 10, 'Hecho con FPDF.', new_x="LMARGIN", new_y="NEXT", align='C')

Nota: el salto de línea puede hacerse también con ln. Este método permite especificar adicionalmente la altura del salto.

Finalmente, el documento es cerrado y guardado en la ruta provista usando output. Sin ningún parámetro provisto, output() devuelve el búfer bytearray del PDF.

Tutorial 2 - Encabezado, pie de página, salto de página e imagen

Aquí hay un ejemplo de dos páginas con encabezado, pie de página y logo:

from fpdf import FPDF


class PDF(FPDF):
    def header(self):
        # Rendering logo:
        self.image("../docs/fpdf2-logo.png", 10, 8, 33)
        # Setting font: helvetica bold 15
        self.set_font("helvetica", "B", 15)
        # Moving cursor to the right:
        self.cell(80)
        # Printing title:
        self.cell(30, 10, "Title", border=1, align="C")
        # Performing a line break:
        self.ln(20)

    def footer(self):
        # Position cursor at 1.5 cm from bottom:
        self.set_y(-15)
        # Setting font: helvetica italic 8
        self.set_font("helvetica", "I", 8)
        # Printing page number:
        self.cell(0, 10, f"Page {self.page_no()}/{{nb}}", align="C")


# Instantiation of inherited class
pdf = PDF()
pdf.add_page()
pdf.set_font("Times", size=12)
for i in range(1, 41):
    pdf.cell(0, 10, f"Printing line number {i}", new_x="LMARGIN", new_y="NEXT")
pdf.output("new-tuto2.pdf")

PDF resultante

Este ejemplo hace uso de los métodos header y footer para procesar encabezados y pies de página. Estos son invocados automáticamente. Ellos ya existen en la clase FPDF pero no hacen nada, por lo tanto tenemos que extender la clase y sobreescribirlos.

El logo es impreso con el método image especificando su esquina superior izquierda y su ancho. La altura es calculada automáticamente para respetar las proporciones de la imagen.

Para imprimir el número de página, un valor nulo es pasado como ancho de celda. Esto significa que la celda deberá ser extendida hasta el margen derecho de la página; es útil para centrar texto. El número de página actual es devuelto por el método page_no; respecto al número total de páginas, éste es obtenido mediante el valor especial {nb} que será sustituido al cerrar el documento (este valor especial puede ser cambiado con alias_nb_pages()). Nota el uso del método set_y que permite establecer la posición en una ubicación absoluta en la página, empezando desde arriba o desde abajo.

Otra característica interesante es usada aquí: el salto de página automático. Tan pronto como una celda cruzaría el límite de la página (por defecto a 2 centímetros del borde inferior), un salto es realizado y la fuente es restaurada. Aunque el encabezado y pie de página tienen su propia fuente (helvetica), el cuerpo continúa en Times. Este mecanismo de restauración automática también se aplica a los colores y al ancho de la línea. El límite que dispara los saltos de página puede establecerse con set_auto_page_break.

Tutorial 3 - Saltos de línea y colores

Continuemos con un ejemplo que imprime párrafos justificados. También ilustra el uso de colores.

from fpdf import FPDF


class PDF(FPDF):
    def header(self):
        # Setting font: helvetica bold 15
        self.set_font("helvetica", "B", 15)
        # Calculating width of title and setting cursor position:
        width = self.get_string_width(self.title) + 6
        self.set_x((210 - width) / 2)
        # Setting colors for frame, background and text:
        self.set_draw_color(0, 80, 180)
        self.set_fill_color(230, 230, 0)
        self.set_text_color(220, 50, 50)
        # Setting thickness of the frame (1 mm)
        self.set_line_width(1)
        # Printing title:
        self.cell(
            width,
            9,
            self.title,
            border=1,
            new_x="LMARGIN",
            new_y="NEXT",
            align="C",
            fill=True,
        )
        # Performing a line break:
        self.ln(10)

    def footer(self):
        # Setting position at 1.5 cm from bottom:
        self.set_y(-15)
        # Setting font: helvetica italic 8
        self.set_font("helvetica", "I", 8)
        # Setting text color to gray:
        self.set_text_color(128)
        # Printing page number
        self.cell(0, 10, f"Page {self.page_no()}", align="C")

    def chapter_title(self, num, label):
        # Setting font: helvetica 12
        self.set_font("helvetica", "", 12)
        # Setting background color
        self.set_fill_color(200, 220, 255)
        # Printing chapter name:
        self.cell(
            0,
            6,
            f"Chapter {num} : {label}",
            new_x="LMARGIN",
            new_y="NEXT",
            align="L",
            fill=True,
        )
        # Performing a line break:
        self.ln(4)

    def chapter_body(self, filepath):
        # Reading text file:
        with open(filepath, "rb") as fh:
            txt = fh.read().decode("latin-1")
        # Setting font: Times 12
        self.set_font("Times", size=12)
        # Printing justified text:
        self.multi_cell(0, 5, txt)
        # Performing a line break:
        self.ln()
        # Final mention in italics:
        self.set_font(style="I")
        self.cell(0, 5, "(end of excerpt)")

    def print_chapter(self, num, title, filepath):
        self.add_page()
        self.chapter_title(num, title)
        self.chapter_body(filepath)


pdf = PDF()
pdf.set_title("20000 Leagues Under the Seas")
pdf.set_author("Jules Verne")
pdf.print_chapter(1, "A RUNAWAY REEF", "20k_c1.txt")
pdf.print_chapter(2, "THE PROS AND CONS", "20k_c1.txt")
pdf.output("tuto3.pdf")

PDF resultante

Texto de Julio Verne

El método get_string_width permite determinar la longitud de una cadena de texto en la fuente actual, usada aquí para calcular la posición y el ancho del marco que rodea al título. Los colores son establecidos (vía set_draw_color, set_fill_color y set_text_color) y el grosor de la línea es establecido a 1 mm (contra 0.2 por defecto) con set_line_width. Finalmente, emitimos la celda (el último parámetro en True para indicar que el fondo debe ser rellenado).

El método usado para imprimir párrafos es multi_cell. El texto es justificado por defecto. Cada vez que una línea alcanza el extremo derecho de la celda o un caracter de retorno de línea (\n) es encontrado, un salto de línea es emitido y una nueva celda es automáticamente creada bajo la actual. Un salto automático es realizado en la ubicación del espacio o guión suave (\u00ad) más cercano antes del límite derecho. Un guión suave será reemplazado por un guión normal cuando un salto de línea se dispara, e ignorado en cualquier otro caso.

Dos propiedades del documento son definidas: el título (set_title) y el autor (set_author). Las propiedades pueden ser vistas de dos formas. La primera es abrir el documento directamente con Acrobat Reader, ir al menú Archivo y elegir la opción Propiedades del Documento. La segunda, también disponible desde el complemento, es hacer clic derecho y seleccionar Propiedades del documento.

Tutorial 4 - Múltiples columnas

Este ejemplo es una variante del anterior, mostrando cómo poner el texto en múltiples columnas.

from fpdf import FPDF


class PDF(FPDF):
    def header(self):
        self.set_font("helvetica", "B", 15)
        width = self.get_string_width(self.title) + 6
        self.set_x((210 - width) / 2)
        self.set_draw_color(0, 80, 180)
        self.set_fill_color(230, 230, 0)
        self.set_text_color(220, 50, 50)
        self.set_line_width(1)
        self.cell(
            width,
            9,
            self.title,
            border=1,
            new_x="LMARGIN",
            new_y="NEXT",
            align="C",
            fill=True,
        )
        self.ln(10)

    def footer(self):
        self.set_y(-15)
        self.set_font("helvetica", "I", 8)
        self.set_text_color(128)
        self.cell(0, 10, f"Page {self.page_no()}", align="C")

    def chapter_title(self, num, label):
        self.set_font("helvetica", "", 12)
        self.set_fill_color(200, 220, 255)
        self.cell(
            0,
            6,
            f"Chapter {num} : {label}",
            new_x="LMARGIN",
            new_y="NEXT",
            border="L",
            fill=True,
        )
        self.ln(4)

    def chapter_body(self, fname):
        # Reading text file:
        with open(fname, "rb") as fh:
            txt = fh.read().decode("latin-1")
        with self.text_columns(
            ncols=3, gutter=5, text_align="J", line_height=1.19
        ) as cols:
            # Setting font: Times 12
            self.set_font("Times", size=12)
            cols.write(txt)
            cols.ln()
            # Final mention in italics:
            self.set_font(style="I")
            cols.write("(end of excerpt)")

    def print_chapter(self, num, title, fname):
        self.add_page()
        self.chapter_title(num, title)
        self.chapter_body(fname)


pdf = PDF()
pdf.set_title("20000 Leagues Under the Seas")
pdf.set_author("Jules Verne")
pdf.print_chapter(1, "A RUNAWAY REEF", "20k_c1.txt")
pdf.print_chapter(2, "THE PROS AND CONS", "20k_c1.txt")
pdf.output("tuto4.pdf")

PDF resultante

Texto de Julio Verne

La diferencia clave respecto al tutorial anterior es el uso del método text_columns. Este recoge todo el texto, posiblemente en incrementos, y lo distribuye entre el número de columnas solicitadas, insertando automáticamente saltos de página según sea necesario. Nota que mientras la instancia de TextColumns está activa como gestor de contexto, los estilos de texto y otras propiedades de la fuente pueden cambiarse. Estos cambios estarán contenidos en el contexto. Una vez se cierre, la configuración previa será reestablecida.

Tutorial 5 - Creando tablas

Este tutorial explicará cómo crear dos tablas diferentes, para demostrar lo que se puede lograr con algunos ajustes simples.

import csv
from fpdf import FPDF
from fpdf.fonts import FontFace
from fpdf.enums import TableCellFillMode


with open("countries.txt", encoding="utf8") as csv_file:
    data = list(csv.reader(csv_file, delimiter=","))

pdf = FPDF()
pdf.set_font("helvetica", size=14)

# Basic table:
pdf.add_page()
with pdf.table() as table:
    for data_row in data:
        row = table.row()
        for datum in data_row:
            row.cell(datum)

# Styled table:
pdf.add_page()
pdf.set_draw_color(255, 0, 0)
pdf.set_line_width(0.3)
headings_style = FontFace(emphasis="BOLD", color=255, fill_color=(255, 100, 0))
with pdf.table(
    borders_layout="NO_HORIZONTAL_LINES",
    cell_fill_color=(224, 235, 255),
    cell_fill_mode=TableCellFillMode.ROWS,
    col_widths=(42, 39, 35, 42),
    headings_style=headings_style,
    line_height=6,
    text_align=("LEFT", "CENTER", "RIGHT", "RIGHT"),
    width=160,
) as table:
    for data_row in data:
        row = table.row()
        for datum in data_row:
            row.cell(datum)

pdf.output("tuto5.pdf")

PDF resultante - Archivo de texto con países

El primer ejemplo es alcanzado de la forma más básica posible, alimentando datos a FPDF.table(). El resultado es rudimentario pero muy rápido de obtener.

La segunda tabla trae algunas mejoras: colores, ancho de tabla limitado, altura de línea reducida, títulos centrados, columnas con anchos personalizados, figuras alineadas a la derecha... Aún más, las líneas horizontales han sido removidas. Esto se hizo escogiendo un borders_layout entre los valores disponibles: TableBordersLayout.

Tutorial 6 - Creando enlaces y combinando estilos de texto

Este tutorial explicará varias formas de insertar enlaces dentro de un documento pdf, al igual que cómo agregar enlaces a recursos externos.

También mostrará muchas formas en que podemos usar los diferentes estilos de texto (negrita, cursiva, subrayado) dentro del mismo texto.

from fpdf import FPDF


pdf = FPDF()

# First page:
pdf.add_page()
pdf.set_font("helvetica", size=20)
pdf.write(5, "To find out what's new in self tutorial, click ")
pdf.set_font(style="U")
link = pdf.add_link(page=2)
pdf.write(5, "here", link)
pdf.set_font()

# Second page:
pdf.add_page()
pdf.image(
    "../docs/fpdf2-logo.png", 10, 10, 50, 0, "", "https://py-pdf.github.io/fpdf2/"
)
pdf.set_left_margin(60)
pdf.set_font_size(18)
pdf.write_html(
    """You can print text mixing different styles using HTML tags: <b>bold</b>, <i>italic</i>,
<u>underlined</u>, or <b><i><u>all at once</u></i></b>!
<br><br>You can also insert links on text, such as <a href="https://py-pdf.github.io/fpdf2/">https://py-pdf.github.io/fpdf2/</a>,
or on an image: the logo is clickable!"""
)
pdf.output("tuto6.pdf")

PDF resultante - Logo de fpdf2

El nuevo método mostrado aquí para imprimir texto es write() . Es muy similar a multi_cell() , siendo las diferencias clave:

  • El final de línea está en el margen derecho y la siguiente línea comienza en el margen izquierdo.
  • La posición actual se desplaza al final del texto.

El método por tanto nos permite escribir un trozo de texto, alterar el estilo de la fuente, y continuar desde el lugar exacto donde quedamos. Por otro lado, su principal desventaja es que no podemos justificar el texto como hacemos con el método multi_cell().

En la primera página del ejemplo usamos write() para este propósito. El comienzo de la oración está escrito usando texto en estilo regular, luego usando el método set_font() cambiamos a subrayado y terminamos la oración.

Para agregar un enlace interno apuntando a la segunda página, usamos el método add_link() , el cual crea un área clicable a la que nombramos "link" que redirige a otro lugar dentro del documento.

Para crear un enlace externo usando una imagen, usamos image() . El método tiene la opción de recibir un enlace como uno de sus argumentos. El enlace puede ser tanto interno como externo.

Como alternativa, otra opción para cambiar el estilo de fuente y agregar enlaces es usar el método write_html(). Este es un analizador de html que permite agregar texto, cambiar el estilo de fuente y agregar enlaces usando html.