Generación de informes PDF en Java: descripción general de las bibliotecas iText y Apache PDFBox
La creación de documentos PDF es una de las tareas más comunes en aplicaciones Java empresariales. Informes, facturas, albaranes, certificados: todo esto se puede generar fácilmente mediante programación. En el ecosistema Java existen dos bibliotecas principales para trabajar con PDF: iText (estándar industrial, pero con licencia comercial para versiones nuevas) y Apache PDFBox (completamente gratuita y de código abierto). En este artículo analizaremos ambas, mostraremos ejemplos de código y le ayudaremos a elegir la herramienta adecuada para su proyecto.
1. Apache PDFBox: una alternativa gratuita con amplias capacidades
Apache PDFBox es una biblioteca de código abierto (licencia Apache 2.0). Permite crear PDF desde cero, editar archivos existentes, extraer texto y metadatos. PDFBox no requiere licencia comercial, lo que la convierte en la opción ideal para startups y proyectos de código abierto.
Características principales:
- Creación de documentos con texto, imágenes y tablas.
- Trabajo con fuentes (incluyendo cirílico).
- Adición de marcadores, hipervínculos y marcas de agua.
- Cifrado y protección con contraseña.
- Extracción de texto e imágenes de PDF existentes.
Ejemplo: creación de un informe PDF simple con tabla
import org.apache.pdfbox.pdmodel.PDDocument;import org.apache.pdfbox.pdmodel.PDPage;import org.apache.pdfbox.pdmodel.PDPageContentStream;import org.apache.pdfbox.pdmodel.font.PDType0Font;import org.apache.pdfbox.pdmodel.common.PDRectangle;import java.io.File;import java.io.IOException;
public class PdfBoxReport { public static void main(String[] args) throws IOException { try (PDDocument document = new PDDocument()) { PDPage page = new PDPage(PDRectangle.A4); document.addPage(page);
// Cargamos la fuente con soporte para cirílico PDType0Font font = PDType0Font.load(document, new File("fonts/arial.ttf"));
try (PDPageContentStream cs = new PDPageContentStream(document, page)) { // Título cs.beginText(); cs.setFont(font, 18); cs.newLineAtOffset(50, 750); cs.showText("Informe de ventas Q1 2025"); cs.endText();
// Tabla (implementación simple mediante líneas y texto) cs.setFont(font, 12); // Dibujamos los encabezados de las columnas float margin = 50; float yStart = 700; float tableWidth = 500; float rowHeight = 25; String[] headers = {"Producto", "Cantidad", "Precio, RUB"}; String[][] data = {{"Portátil", "10", "85000"}, {"Ratón", "50", "1500"}, {"Teclado", "30", "3500"}};
// Encabezado de la tabla cs.setLineWidth(1f); for (int i = 0; i < headers.length; i++) { cs.addRect(margin + i * (tableWidth / 3), yStart - rowHeight, tableWidth / 3, rowHeight); cs.stroke(); cs.beginText(); cs.newLineAtOffset(margin + i * (tableWidth / 3) + 5, yStart - rowHeight + 5); cs.showText(headers[i]); cs.endText(); }
// Datos float yPos = yStart - rowHeight; for (String[] row : data) { yPos -= rowHeight; for (int i = 0; i < row.length; i++) { cs.addRect(margin + i * (tableWidth / 3), yPos, tableWidth / 3, rowHeight); cs.stroke(); cs.beginText(); cs.newLineAtOffset(margin + i * (tableWidth / 3) + 5, yPos + 5); cs.showText(row[i]); cs.endText();