Cambiar la altura de las celdas de una Tabla en iText 7

Altura de celdas
Altura de celdas

Cuando pone una tabla en su documento iText 7 puede llegar a pensar que seria bueno aumentar o reducir la altura de las filas en una tabla ya sea para ahorrar espacio al imprimir o mejorar la legibilidad del documento, aquí esta como.

Método .setHeight(altura)

No hay una forma de cambiar la altura de todas las celdas de una tabla de golpe por lo que si queremos especificar la altura lo tenemos que hacer celda por celda, esto es crear un objeto Cell, agregar el contenido, indicar la altura que deseamos con .setHeight(altura) y agrega esa celda a la tabla, un ejemplo de como se ve a continuación.

// Creamos una celda
Cell celda1 = new Cell();

// Agregamos el contenido de la celda
celda1.add(new Paragraph("Celda 1"));

// indicamos la altura para la celda
celda1.setHeight(altura);

// agregamos esa celda a la tabla
tabla.addCell(celda1);

Hay una observación que hacer, aunque uno podria pensar que se podria crear una tabla donde cada celda tenga una altura diferente este no es el caso, en iText la celda mas alta de una fila es la que determinara la altura de toda esa fila por lo que debe tomar eso en consideración al diseñar su tabla.

Ejemplo

Ahora pasemos a un ejemplo, via un método crearemos una tabla y especificaremos la altura de las tablas, llamaremos ese método varias veces para generar varias tablas con celdas de diferente altura y las agregaremos al documento, el resultado sera como en la figura al inicio, una serie de tablas con celdas de altura incremental.

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package mx.hash.fontsize.tablecellheight;

import com.itextpdf.kernel.geom.PageSize;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.Cell;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.layout.element.Table;
import java.io.FileNotFoundException;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author david
 */
public class CellHeight {

    private static Logger LOGGER = Logger.getLogger("mx.hash.fontsize.tablecellheight.CellHeight");

    public Table crearTablaConAtura(float altura) {
        // Creamos la tabla
        float[] anchos = {150f, 150f, 150f};
        Table tabla = new Table(anchos);
        
        // Creamos las celdas
        Cell celda1 = new Cell();
        Cell celda2 = new Cell();
        Cell celda3 = new Cell();

        celda1.add(new Paragraph("Celda 1"));
        // Indicamos la altura para la celda 1
        celda1.setHeight(altura);

        celda2.add(new Paragraph("Celda 2"));
        // Indicamos la altura para la celda 2
        celda2.setHeight(altura);

        celda3.add(new Paragraph("Celda 3"));
        // Indicamos la altura para la celda 3
        celda3.setHeight(altura);
        
        // Agregamos las celdas a la tabla
        tabla.addCell(celda1);
        tabla.addCell(celda2);
        tabla.addCell(celda3);

        return tabla;
    }

    static public void main(String[] args) {
        PdfWriter pdfWriter;
        try {
            // Creamos un documento pdf con iText
            pdfWriter = new PdfWriter("./fontSize.pdf");
            PdfDocument pdfDoc = new PdfDocument(pdfWriter);
            Document doc = new Document(pdfDoc, PageSize.LETTER);
            
            CellHeight generadorTablas = new CellHeight();
            
            doc.add( new Paragraph("Altura 12f, demasiado chico para el tamaño de texto, por lo que no se vera, tenga cuidado con esto y redusca el tamaño de fuente acordemente") );
            doc.add( generadorTablas.crearTablaConAtura(12f) );
            
            Table tablaChica = generadorTablas.crearTablaConAtura(12f);
            // Cambiamos el tamaño de texto
            tablaChica.setFontSize(8f);
            
            doc.add( new Paragraph("Con un tamaño de texto acorde ya se ve mejor") );
            doc.add(tablaChica);
            
            doc.add( new Paragraph("Altura 22f") );
            doc.add( generadorTablas.crearTablaConAtura(22f) );
            
            doc.add( new Paragraph("Altura 32f") );
            doc.add( generadorTablas.crearTablaConAtura(32f) );
            
            doc.add( new Paragraph("Altura 42f") );
            doc.add( generadorTablas.crearTablaConAtura(42f) );
            
            doc.add( new Paragraph("Altura 52f") );
            doc.add( generadorTablas.crearTablaConAtura(52f) );
            
            doc.add( new Paragraph("El tamaño se respeta por *fila*, al cambiar de fila usa la altura de la celda mas alta de esa fila") );
            
            Table tablaExtendida =  generadorTablas.crearTablaConAtura(52f);
            tablaExtendida.addCell( new Paragraph("Esta celda deberia ser de tamaño normal!") );
            
            Cell celdaGrande = new Cell();
            
            celdaGrande.setHeight(100f);
            celdaGrande.add( new Paragraph("Esta celda cambia el tamaño de toda la fila"));
            tablaExtendida.addCell(celdaGrande);
            
            doc.add(tablaExtendida);

            doc.close();

        } catch (FileNotFoundException ex) {
            LOGGER.log(Level.SEVERE, null, ex);
        }
    }

}

Hay dos casos extra que se presentan en el ejemplo.

El primero es que pasa si indica un altura demasiado pequeña para que el texto aparesca completamente, en ese caso el texto simplemente no aparecera, esto no genera ningun mensaje de error por lo que debe de verificarlo con cuidado al reducir la altura de las celdas, una correción simple es reducir el tamaño del texto como se vio en una entrada anterior.

Lo segundo y mas importante es lo que mencionamos previamente, la altura de toda la fila es controlada por la celda mas alta de la fila, independientemente de lo que indiquen las demas tablas y ese tamaño se resetea cada cambio de fila, por lo que si se quiere poner creativo con eso debe tomar muy en cuenta cuantas celdas van en cada fila.

El código completo de este ejemplo puede ser encontrado en https://gitlab.com/ticomWebcomic/TableCellHeight

Espero que esta entrada les fuera de utilidad y desean cooperar, me pueden invitar una cerveza: https://www.paypal.me/hashRaygoza/20mxn Gracias y nos vemos en la próxima :).

 

Anuncios

Cambiar el tamaño de fuente en iText 7

Diferentes tamaños de fuente en iText7
Diferentes tamaños de fuente en iText7

Si esta utilizando iText 7 para generar reportes o documentos que vayan a ser impresos hay que ser considerados con el tamaño de texto, puede ser que se quiera ahorrar papel y que todo el reporte quepa en una sola pagina o que recuerde que en papel no hay función zoom así que debe ser legible, estas situaciones suelen implicar cambiar el tamaño del texto, ya sea reducirlo o aumentarlo y no se ustedes pero la documentación oficial de iText 7 es un poco críptica al respecto (o al menos Google tiene problemas en hallar donde estaba) asi que veamos como aumentar y reducir el tamaño del texto en iText 7 (Si se pregunta por que estoy repitiendo tanto el numero de versión es por que lo que lea de iText 5 NO funciona en iText 7).

El Método .setFontSize

Por fortuna esta vez iText 7 va a estar muy a nuestra favor ya que con la mayoría de los elementos que utilizan texto, como Paragraph y Table, basta con llamar el método

.setFontSize(tamaño)

donde tamaño es un valor float que indica el tamaño de la fuente que deseamos usar y con eso el tamaño cambia.

Ejemplo

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package mx.hash.fontsize.fontsizeitext;

import com.itextpdf.kernel.geom.PageSize;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.layout.element.Table;
import java.io.FileNotFoundException;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author david
 */
public class FontSizeExample {
    private static Logger LOGGER = Logger.getLogger("mx.hash.fontsize.fontsizeitext.FontSizeExample");
    
    static public void main(String[] args) {
        try {
            // Creamos un documento pdf con iText
            PdfWriter pdfWriter = new PdfWriter("./fontSize.pdf");
            PdfDocument pdfDoc = new PdfDocument(pdfWriter);
            Document doc = new Document(pdfDoc, PageSize.LETTER);
            
            // Creamos unos parrafos
            Paragraph parrafo1 = new Paragraph("Prueba con el tamaño por default Prueba con el tamaño por default Prueba con el tamaño por default Prueba con el tamaño por default Prueba con el tamaño por default Prueba con el tamaño por default Prueba con el tamaño por default Prueba con el tamaño por default Prueba con el tamaño por default Prueba con el tamaño por default Prueba con el tamaño por default Prueba con el tamaño por default Prueba con el tamaño por default");
            Paragraph parrafo2 = new Paragraph("Demostracion de letra mas pequeña Demostracion de letra mas pequeña Demostracion de letra mas pequeña Demostracion de letra mas pequeña Demostracion de letra mas pequeña Demostracion de letra mas pequeña Demostracion de letra mas pequeña Demostracion de letra mas pequeña Demostracion de letra mas pequeña Demostracion de letra mas pequeña Demostracion de letra mas pequeña Demostracion de letra mas pequeña Demostracion de letra mas pequeña");
            Paragraph parrafo3 = new Paragraph("Ejemplo con una letra mas grande Ejemplo con una letra mas grande Ejemplo con una letra mas grande Ejemplo con una letra mas grande Ejemplo con una letra mas grande Ejemplo con una letra mas grande Ejemplo con una letra mas grande Ejemplo con una letra mas grande Ejemplo con una letra mas grande Ejemplo con una letra mas grande Ejemplo con una letra mas grande Ejemplo con una letra mas grande Ejemplo con una letra mas grande ");
            
            // Creamos unas tablas
            float[] anchos = {150f, 150f, 150f};
            Table tabla1 = new Table(anchos);
            Table tabla2 = new Table(anchos);
            Table tabla3 = new Table(anchos);
            
            // Agregamos contenido a las tablas
            tabla1.addCell("Ejemplo con");
            tabla1.addCell("Con tamaño");
            tabla1.addCell("default");
            
            tabla2.addCell("Ejemplo con");
            tabla2.addCell("Con tamaño");
            tabla2.addCell("mas pequeño");
            
            tabla3.addCell("Ejemplo con");
            tabla3.addCell("Con tamaño");
            tabla3.addCell("mas grande");            
            
            // Cambiamos el tamaño de fuente del parrafo 2 lo hacemos mas pequeño
            parrafo2.setFontSize(8f);
            
            // Cambiamos el tamaño de fuente del parrafo 3 lo hacemos mas grande
            parrafo3.setFontSize(20f);
            
            // Cambiamos el tamaño de fuente de la tabla 1, lo hacemos mas pequeño
            tabla2.setFontSize(8f);
            
            // Cambiamos el tamaño de fiente de la tabla 2, lo hacemos mas grande
            tabla3.setFontSize(20f);            
            
            doc.add(parrafo1);
            doc.add(parrafo2);
            doc.add(parrafo3);
            doc.add(tabla1);
            doc.add(tabla2);
            doc.add(tabla3);
            
            doc.close();
        } catch (FileNotFoundException ex) {
            LOGGER.log(Level.SEVERE, null, ex);
        }
    }
    
}

Como puede ver cambiar el tamaño es tan sencillo como llamar un solo método, notara que al poner el tamaño puse una f después de los números esto es para que el compilador de Java sepa que es un numero de tipo float.

El código completo del proyecto puede localizarlo en https://gitlab.com/ticomWebcomic/FontSizeiText


Espero que esta entrada les fuera de utilidad y desean cooperar, me pueden invitar una cerveza: https://www.paypal.me/hashRaygoza/20mxn Gracias y nos vemos en la próxima :).

 

Encabezados, pie de pagina y conteo de paginas en iText 7

Recientemente la librería iText ha liberado su nueva versión la 7.0.2 y en algo que honestamente espero no se haga costumbre (aunque hay mal precedente si recuerda el cambio de la versión 4 a la 5…) las clases y varios de los métodos han sido re escritos desde cero, ¿Como le afecta esto? pues si quiere hacer uso de la versión mas reciente toca hacer una reescritura significativa ya que la versión 5 y 7 no son compatibles entre si y no espere que los ejemplos previos le ayuden.

Esto es particularmente latoso si ya estaba creando encabezado y conteos de pagina como se había descrito en este blog previamente (para la versión 5 de iText), pero no desespere, aquí esta como hacerlo en iText 7

Documento pdf con encabezado y pie de pagina
Documento pdf con encabezado y pie de pagina

En esta entrada veremos como usar iText 7 y el nuevo modelo de eventos para crear un encabezado con un mensaje personalizable y un pie de pagina con el numero de pagina actual, para evitar confundirlo si no a usado iText antes y que esta entrada sea demasiado larga, no se haran comparaciones con la versión anterior y nos enfocaremos en como hacerlo en iText 7.

Agregando iText 7 a su proyecto

Configuración Maven de iText 7
Configuración Maven de iText 7

Para este ejemplo usaremos Maven para agregar las librerias al proyecto, puede usar ya sea el pom.xml o agregar la dependencia itext7-core via NetBeans en este ejemplo usaremos la versión 7.0.2.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>mx.hashSoft</groupId>
    <artifactId>iText7</artifactId>
    <version>1.0</version>
    <packaging>jar</packaging>
    <dependencies>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itext7-core</artifactId>
            <version>7.0.2</version>
            <type>pom</type>
        </dependency>
    </dependencies>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.7</maven.compiler.source>
        <maven.compiler.target>1.7</maven.compiler.target>
    </properties>
</project>

Eventos de documento

El ejemplo que usaremos para explicar el uso de iText 7 es bastante sencillo, crea un documento pdf el cual solo contendrá lineas y lineas de “Hola Mundo!” y que tendrá un encabezado con el mensaje “Departamento de Recursos Humanos” y un pie de pagina con el numero de pagina actual.

El pie de pagina y encabezado son creados por una clase que implementa la interfaz IEventHandler esta clase se agrega como manejador de evento al objecto documento y se indica cual evento manejara, de modo que se pueden tener múltiples clases manejando diferentes eventos en el mismo documento.

En este caso particular manejaremos el evento PdfDocumentEvent.END_PAGE el cual se activa cuando se llega al final de la pagina, en este punto agregamos el encabezado, pie de pagina y obtendremos el numero de pagina en el que vamos.

Canvas y rectángulos

Al ver el código de la clase EventoPagina seguramente notara que aparte de las tablas que contienen el texto que deseamos mostrar notara que se crean varios objectos Canvas y Rectangle estos cumplen una función muy simple ya que nos permiten colocar los objectos Table donde queramos, sin mover los demás elementos, el objeto Rectangle indica el área donde colocaremos la tabla y con el objecto Canvas lo dibujaremos en ese lugar.

Código

Ahora si vamos a lo bueno, para este ejemplo usaremos dos clases la ya mencionada EventoPagina la cual manejara el evento PdfDocumentEvent.END_PAGE e iText7 esta clase crea el documento Pdf y su contenido, ambas clases tienen comentarios que espero sean suficientes para hacer comprensible su función.

package mx.hashsoft.itext7;

import com.itextpdf.kernel.events.PdfDocumentEvent;
import com.itextpdf.kernel.geom.PageSize;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.Paragraph;
import java.io.FileNotFoundException;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author david
 */
public class iText7 {

    static public void main(String[] args) {
        try {
            // Creamos el escritor del archivo pdf
            PdfWriter pdfWriter = new PdfWriter("./ejemplo_itext7.pdf");
            // Creamos el documento PDF que se almacenara via el escritor
            PdfDocument pdfDoc = new PdfDocument(pdfWriter);
            // Creamos el documento pdf en si, con pagina tamaño letra
            Document doc = new Document(pdfDoc, PageSize.LETTER);
            // Creamos el manejador de evento de pagina, el cual agregara
            // el encabezado y pie de pagina
            EventoPagina evento = new EventoPagina(doc);

            // Indicamos que el manejador se encargara del evento END_PAGE
            pdfDoc.addEventHandler(PdfDocumentEvent.END_PAGE, evento);
            
            // Establecemos los margenes
            doc.setMargins(75, 36, 75, 36);

            // Creamos el contenido, por motivos de ejemplo es solo Hola Mundo!
            // una y otra vez
            for (int i = 0; i < 450; i++) {
                doc.add(new Paragraph("Hola Mundo!"));
            }

            // Cerramos el documento
            doc.close();

        } catch (FileNotFoundException ex) {
            Logger.getLogger(iText7.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}
package mx.hashsoft.itext7;

import com.itextpdf.kernel.events.Event;
import com.itextpdf.kernel.events.IEventHandler;
import com.itextpdf.kernel.events.PdfDocumentEvent;
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfPage;
import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
import com.itextpdf.layout.Canvas;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.Table;

/**
 *
 * @author david
 */
public class EventoPagina implements IEventHandler {

    private final Document documento;

    public EventoPagina(Document doc) {
        documento = doc;
    }
    
    /**
     * Crea el rectangulo donde pondremos el encabezado
     * @param docEvent Evento de documento
     * @return Area donde colocaremos el encabezado
     */
    private Rectangle crearRectanguloEncabezado(PdfDocumentEvent docEvent) {
        PdfDocument pdfDoc = docEvent.getDocument();
        PdfPage page = docEvent.getPage();        
        
        float xEncabezado = pdfDoc.getDefaultPageSize().getX() + documento.getLeftMargin();
        float yEncabezado = pdfDoc.getDefaultPageSize().getTop() - documento.getTopMargin();
        float anchoEncabezado = page.getPageSize().getWidth() - 72;
        float altoEncabezado = 50F;

        Rectangle rectanguloEncabezado = new Rectangle(xEncabezado, yEncabezado, anchoEncabezado, altoEncabezado);
        
        return rectanguloEncabezado;        
    }
    
    /**
     * Crea el rectangulo donde pondremos el pie de pagina
     * @param docEvent Evento del documento
     * @return Area donde colocaremos el pie de pagina
     */
    private Rectangle crearRectanguloPie(PdfDocumentEvent docEvent) {
        PdfDocument pdfDoc = docEvent.getDocument();
        PdfPage page = docEvent.getPage();
        
        float xPie = pdfDoc.getDefaultPageSize().getX() + documento.getLeftMargin();
        float yPie = pdfDoc.getDefaultPageSize().getBottom() ;
        float anchoPie = page.getPageSize().getWidth() - 72;
        float altoPie = 50F;

        Rectangle rectanguloPie = new Rectangle(xPie, yPie, anchoPie, altoPie);
        
        return rectanguloPie;
    }
    
    /**
     * Crea la tabla que contendra el mensaje del encabezado
     * @param mensaje Mensaje que desplegaremos
     * @return Tabla con el mensaje de encabezado
     */
    private Table crearTablaEncabezado(String mensaje) {
        float[] anchos = {1F};
        Table tablaEncabezado = new Table(anchos);
        tablaEncabezado.setWidth(527F);

        tablaEncabezado.addCell(mensaje);
        
        return tablaEncabezado;
    }
    
    /**
     * Crea la tabla de pie de pagina, con el numero de pagina
     * @param docEvent Evento del documento
     * @return Pie de pagina con el numero de pagina
     */
    private Table crearTablaPie(PdfDocumentEvent docEvent) {
        PdfPage page = docEvent.getPage();
        float[] anchos = {1F};
        Table tablaPie = new Table(anchos);
        tablaPie.setWidth(527F);
        Integer pageNum = docEvent.getDocument().getPageNumber(page);
        
        tablaPie.addCell("Pagina " + pageNum);
        
        return tablaPie;
    }
    

    /**
     * Manejador del evento de cambio de pagina, agrega el encabezado y pie de pagina
     * @param event Evento de pagina
     */
    @Override
    public void handleEvent(Event event) {
        PdfDocumentEvent docEvent = (PdfDocumentEvent) event;
        PdfDocument pdfDoc = docEvent.getDocument();
        PdfPage page = docEvent.getPage();
        PdfCanvas canvas = new PdfCanvas(page.newContentStreamBefore(), page.getResources(), pdfDoc);        
        
        Table tablaEncabezado = this.crearTablaEncabezado("Departamento de Recursos Humanos");
        Rectangle rectanguloEncabezado = this.crearRectanguloEncabezado(docEvent);        
        Canvas canvasEncabezado = new Canvas(canvas, pdfDoc, rectanguloEncabezado);        
        canvasEncabezado.add(tablaEncabezado);      

        Table tablaNumeracion = this.crearTablaPie(docEvent);
        Rectangle rectanguloPie = this.crearRectanguloPie(docEvent);
        Canvas canvasPie = new Canvas(canvas, pdfDoc, rectanguloPie);        
        canvasPie.add(tablaNumeracion);
    }
}

Espero que esta entrada halla sido de utilidad y nos vemos en la próxima :).

Organización del código de un proyecto iText

En uno de los comentarios de la entrada iText, Generación de archivo Pdf en Java se me pregunto si había una forma de no poner todo el código de generación de archivo en un solo método y separarlo en métodos mas concisos y que sigan mejor las practicas y convenciones de Java, esto es perfectamente posible y aquí presentare un ejemplo de como hacerlo aunque cabe mencionar que este es un ejemplo bastante simple, pero tiene como objeto dar una idea de como hacerlo.

Figura 1 - Proyecto iText
Figura 1 – Proyecto iText

Antes de comenzar, como vemos en la Figura 1, es necesario que cree un proyecto en Eclipse que contenga las librerías iText, en entradas anteriores del blog puede encontrar como configurar el proyecto , a su vez necesitara agregar una imagen en la raíz del proyecto, como se ve en la figura 2, con el fin de que el programa pueda agregarla al documento final.

Figura 2 - Archivos del proyecto
Figura 2 – Archivos del proyecto

Ya que tenga la imagen y las librerías listas procederemos con el código, el cual puede ver en la siguiente sección, en este caso el proyecto contiene dos clases, una que se contiene los métodos de creación del documento pdf y otra con el método principal.

Codigo

// Modular.java

package mx.com.hashSoft.iTextModular;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.Image;
/**
* Clase de ejemplo de como organizar el uso de la libreria iText
* Generando el archivo desde un punto del programa y agregando los
* elementos desde metodos especializados
*
* Esta clase esta pensada como un ejemplo de como organizar el codigo de un proyecto de iText
* @author david
*/

public class Modular {
      private Document documento;

      /**
      * Incializa el documento iText para agregar elementos, abre el documento por default
      * @param nombreArchivo Ruta del archivo pdf que se creara
      * @throws FileNotFoundException
      * @throws DocumentException
      */
      public Modular(String nombreArchivo) throws FileNotFoundException, DocumentException {
            setDocumento(new Document());

            PdfWriter.getInstance(documento, new FileOutputStream(nombreArchivo));
            documento.open();
      }

      /**
      * Agrega la cadena de texto indicada como un parrafo
      * @param parrafo Texto del parafo
      * @throws DocumentException
      */
      public void agregarParrafo(String parrafo) throws DocumentException {
            Paragraph par = new Paragraph(parrafo);
            documento.add(par);
      }

      /**
      * Agrega una imagen al documento
      * @param rutaImagen Ruta de la imagen a agregar
      * @throws MalformedURLException
      * @throws IOException
      * @throws DocumentException
      */
      public void agregarImagen(String rutaImagen) throws MalformedURLException, IOException, DocumentException {
            Image imagen = Image.getInstance(rutaImagen);
            documento.add(imagen);
      }

      /**
      * Cierra el documento
      */
      public void cerrarDocumento() {
            documento.close();
      }

      public Document getDocumento() {
            return documento;
      }

      public void setDocumento(Document documento) {
            this.documento = documento;
      }

}

/// Main.java

package mx.com.hashSoft.iTextModular;

import java.io.IOException;
import com.itextpdf.text.DocumentException;

public class Main {
      static public void main(String[] args) {
            Modular test;

            // Dentro del bloque try-catch creamos el archivo

            try {
                  test = new Modular(“archivo.pdf”);

                  // Agremaos un parrafo
                  test.agregarParrafo(“Parrafo de ejemplo del documento, despues de este agregaremos una imagen con el metodo agregarImagen”);

                  // una imagen, recuerde cambiar el nombre de la imagen por la que halla puesto en el directorio del proyecto
                  test.agregarImagen(“mickey_mouse.png”);

                  // Otro parrafo
                  test.agregarParrafo(“Segundo parrafo, ambos agregados con una llamada al metodo agregarParrafo”);

                  // Y finalmente cerramos el documento
                  test.cerrarDocumento();

            } catch (DocumentException | IOException e) {
                  System.out.println(“Error generando el archivo pdf.”);
                  e.printStackTrace();
            }
      }
}

Al ejecutar el programa debería aparecer un nuevo archivo pdf con el nombre indicado con el código en el directorio, como se ve en la figura 3

Figura 3 - Resultado del programa
Figura 3 – Resultado del programa

Y al abrir el archivo pdf veremos lo que hallamos escrito en los párrafos, como se ve en la figura 4

Figura 4 - Salida
Figura 4 – Salida

En este caso contare que la documentación agregada en el propio código detalla que hacen cada método, pero como puede observar los diferentes métodos que la librería iText pueden ser puestos en metodos separados, lo que nos da un código mas limpio y ordenado y dándonos la posibilidad de pasarles argumentos haciéndolos mas reusables, como vemos en el método main.

Espero que esta entrada halla sido de utilidad y nos vemos en la proxima :D.

Acceder a imagenes desde el .JAR con iText

Al momento de crear un programa en java, es posible que desee hacerlo lo mas auto contenido posible, de modo que la instalación sea tan sencilla como copiar el archivo de una computadora a otra.

Una de las cosas que tienden a evitar que se pueda hacer esto son las imágenes que se usan para los documentos que el programa vaya a generar, usualmente el logotipo de la empresa, sin embargo es perfectamente posible almacenar el archivo *dentro* de nuestro archivo .JAR y que los documentos creados con iText puedan acceder a dicha imagen y presentarla en el documento.

Estructura del proyecto.

Para este ejemplo necesitara crear un proyecto en Eclipse donde agregue las librerías iText, puede tomar el proyecto como ejemplo, ya que halla agregado las librerias al proyecto cree el paquete mx.hashSoft.inJar como se ve la figura 1, no cree ninguna clase aun.

Figura 1 - Proyecto
Figura 1 – Proyecto

Ubicación de la imagen en el proyecto.

Como seguramente ya sabrá, un paquete de Java es una representación de una estructura de carpetas las cuales contienen el código del programa, pero también pueden contener cualquier tipo de archivos, como recursos, imágenes o archivos de propiedades.

Con este conocimiento en mano vaya a la carpeta inJar y copie ahi la imagen que desea usar en su documento, como puede ver en la figura 2

Figura 2 - Imagen
Figura 2 – Imagen

 Accediendo a recursos dentro del proyecto.

Si a tenido oportunidad de leer la documentación de la clase Image de iText, posiblemente halla notado que el constructor toma como argumento una cadena de texto que contenga el URL (Localizador de recurso uniforme) de la imagen que desea mostrar, bueno este lo podemos obtener gracias a la clase URL del paquete java.net lo cual nos da la información necesaria para acceder a la imagen.

Código.

Ya habiendo tocado la teoría, procederemos al ejemplo practico, en su proyecto de “Actualizar” al proyecto (lo que hará que el archivo de la imagen aparezca en el paquete inJar) y cree una nueva clase llamada InJar en la cual debe poner el código mostrado a continuación:

Figura 3 - Contenido del proyecto
Figura 3 – Contenido del proyecto

package mx.org.hashSoft.inJAR;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import com.itextpdf.text.Image;
import java.io.FileOutputStream;
import com.itextpdf.text.Element;
import com.itextpdf.text.Document;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.text.DocumentException;

public class InJar {
    
    public void crearPdf(String filename) throws MalformedURLException, IOException, DocumentException {
        Document document = new Document(PageSize.LETTER, 36, 36, 54, 36);
        Paragraph parrafo;
        String nombreLogo = “logo.png”;
        Image imagen;
        
        URL resUrl = this.getClass().getResource(nombreLogo);
        
        imagen = Image.getInstance(resUrl);
        
        PdfWriter.getInstance(document, new FileOutputStream(filename));

        document.open();

        parrafo = new Paragraph(“La imagen esta contenida en el archivo .JAR”);
        parrafo.setAlignment(Element.ALIGN_CENTER);
        imagen.setAlignment(Element.ALIGN_CENTER);

        document.add(parrafo);
        document.add(imagen);
        
        document.close();
    }
    
    static public void main(String[] args) {
        InJar doc = new InJar();

        try {
            // Creamos el documento Pdf
            doc.crearPdf(“documento.pdf”);

        } catch (DocumentException ed) {
            System.err.println(“Error al crear el documento Pdf”);
        } catch (IOException ex) {
            System.err.println(“Error General de Entrada/Salida”);
        }
    }
}

Como ya es costumbre, las lineas en rojo son las principales y su función se describirá a continuación.

import java.net.MalformedURLException;
import java.net.URL;   Importamos los paquetes necesarios para hacer uso de la clase URL

String nombreLogo = “logo.png”; Indicamos el nombre de la imagen que deseamos cargar, puede especificar la ruta relativa o absoluta desde la raiz del proyecto

URL resUrl = this.getClass().getResource(nombreLogo); Obtenemos el URL de la imagen con relación a la clase en la que estamos

imagen = Image.getInstance(resUrl); Abrimos la imagen y creamos el objecto que la referencia

doc.crearPdf(“documento.pdf”); Llamamos a los metodos para crear el documento y lo almacenamos en el directorio donde ejecutemos el programa

Ahora para demostrar todo exportamos el proyecto como un archivo Jar Ejecutable, como se ve en la figura 4

Figura 4 - Exportar
Figura 4 – Exportar

Recuerde exportar las librerías junto con el resto del proyecto, ahora mueva el archivo a la ubicación que desee en el sistema, como se ve en la figura 5 y ejecutelo, si esta en windows bastara un doble click, en linux necesitara la linea de comando, vera que se crea un nuevo archivo llamado “documento.pdf”, Figura 6

Figura 5 - Archivo .jar
Figura 5 – Archivo .jar
Figura 6 - Documento creado
Figura 6 – Documento creado

Y al abrir el documento vera que la imagen como se ve en la figura 7

Figura 7 - Resultado
Figura 7 – Resultado

Espero que esta entrada haya sido de ayuda y nos vemos en la próxima

Agregando enlaces a paginas Web a archivos Pdf con iText

Al momento de crear un archivo Pdf con iText puede darse el caso que necesite o desee agregar un enlace a una pagina web, por ejemplo la pagina web de su empresa, esto es perfectamente realizable desde iText y es bastante sencillo.

Preparando el proyecto.

Si ya a leído entradas previas de este blog ya sabrá como agregar la liberia iText a un proyecto en Eclipse, en caso de no conocer el procedimiento puede consultarlo a detalle en esta entrada: https://hashblogeando.wordpress.com/2013/07/14/itext-generacion-de-archivo-pdf-en-java/ en la que se detalla como configurar el proyecto y donde descargar la libreria iText, una vez que tenga generado el proyecto podemos proseguir.

Proyecto en Eclipse

Como puede ver en la figura 1, el proyecto de ejemplo consiste en una sola clase en el paquete mx.com.hashSoft.

Figura 1 - Proyecto en Eclipse
Figura 1 – Proyecto en Eclipse

El código de la clase Hiperenlace se presenta a continuación, las partes importantes para generar el enlace aparecen resaltadas en rojo.

package mx.com.hashSoft;

import com.itextpdf.text.Anchor;
import com.itextpdf.text.BaseColor;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Font;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.Phrase;
import com.itextpdf.text.pdf.PdfWriter;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;

/**
 * Crea un documento Pdf con hiperenlaces a Internet, estos enlaces
 * aparecen con letras azules y subrayados
 *
 * Referencias:
 * http://tutorials.jenkov.com/java-itext/anchor.html
 * http://geek-tutorials.com/java/itext/itext_bookmark_anchor.php
 * @author david
 */

public class HiperEnlace {
    
    static public void main(String[] args) {
        
        Document documento = new Document();
        Font fuente = new Font();
        Paragraph parrafo = new Paragraph();
        Anchor enlace = null;
        
        // Creamos el documento
        
        try{
            
            PdfWriter.getInstance(documento, new FileOutputStream(“HyperEnlace.pdf”));
            
            documento.open();
            
            // Usaremos esta fuente para los enlaces
            // Se establece el color azul
            fuente.setColor( BaseColor.BLUE);
            // Y el subrayado
            fuente.setStyle(Font.UNDERLINE);            
            
            // Agregamos un parrefo
            parrafo.add(new Phrase(
                    “Este es un ejemplo de como generar hiperenlaces, los cuales al darles click abren “
                    + “una pagina en el navegador. Como puede observar dando click al siguiente\n”));
            
            // Texto que se mostrara en el documento
            enlace = new Anchor(“http://tutorials.jenkov.com/java-itext/anchor.html&#8221;, fuente);
            
            // direccion URL a la que apunta el enlace
            enlace.setReference(“http://tutorials.jenkov.com/java-itext/anchor.html&#8221;);
            
            // Agregamos el enlace
            parrafo.add(enlace);            
            
            // Agregamos otro parrafo
            parrafo.add(new Phrase(“\nNotara que el pulsar el enlace abrio la pagina de una de las ” +
            “Referencias de la entrada”));
            
            documento.add(parrafo);           
            documento.close();           
            
        }catch(DocumentException e) {
            System.err.println(“*********** Error al crear Documento”);
            e.printStackTrace();
        }catch(FileNotFoundException d) {
            System.err.println(“*********** Error al abrir archivo”);
            d.printStackTrace();
        }        
    }
}

Font fuente = new Font(); Creamos un objecto Font, de modo que podamos crear una fuente personalizada, esto es necesario ya que por defecto los enlaces lucirán igual que el resto del texto, algo que seguramente no desea

Anchor enlace = null; Creamos un objecto que representa un enlace en el documento, por el momento no esta inicializado, pero eso cambiara en corto.

fuente.setColor( BaseColor.BLUE);  Indicamos al nuestro objecto Font que deseamos el texto que use esta fuente sea del color indicado, en este caso Azul, indicado por la constante BaseColor.BLUE

fuente.setStyle(Font.UNDERLINE); Indicamos a nuestro objecto Font que el texto que use esta fuente debe de esta subrayado, esto junto a la instrucción anterior le dará a los enlaces el look clasico de texto azul subrayado

enlace = new Anchor(“http://tutorials.jenkov.com/java-itext/anchor.html&#8221;, fuente); Creamos el objecto Anchor el cual se presentara como un enlace en el documento, en esta versión en particular del constructor indicamos el texto que deseamos aparezca y la fuente con la que deseamos se escriba, aquí viene a la mano la fuente que definimos de modo que los enlaces resalten en el documento.

 enlace.setReference(“http://tutorials.jenkov.com/java-itext/anchor.html&#8221;); La linea principal del enlace, con el método setReference indicamos a que URL nos debe dirigir el enlace al momento de pulsarlo

 parrafo.add(enlace); Agrega el enlace al parrafo indicado.

Salida del programa

Una vez que ejecute el programa, en el directorio raiz del proyecto encontrara un archivo HyperEnlace.pdf que lucirá como la figura 2

Figura 2 - Salida
Figura 2 – Salida

Y si pulsa el enlace lo llevara a una de las referencias que me ayudaron a crear esta entrada.

Figura 3 - Destino
Figura 3 – Destino

Espero que esta entrada halla sido de utilidad y nos vemos en la próxima.

Agregando un membrete a un documento Pdf con iText

Ya en entradas anteriores se mostraron dos capacidades proporcionadas por la libreria
iText, la posibilidad de agregar imagenes y generar encabezados de pagina en documentos Pdf.

No deberia de extrañar que sea posible combinar ambas capacidades y agregar un membrete de tipo procesional a los documentos Pdf que necesite generar.

Sobre los margenes y el posicionamiento absoluto.

Antes de comenzar hay dos aspectos sobre iText que es necesario comprender para poder generar este membrete, que es la posibilidad que nos da iText de colocar imágenes y tablas en la posición que nos plazca, esto es importante puesto que el método add del objecto Document normalmente colocaría estos elementos después de los que ya estén en uso lo que obviamente no deseamos pase con el membrete de la pagina.

Ya para comenzar hay un par de conocimientos previos con los que necesitara estar familiarizado que son:

En dichas entradas previas puede encontrar información mas detallada de lo que se necesitara para generar el membrete.

Dicho esto podemos comenzar.

Creando manejador de eventos de pagina.

Para comenzar debe de crear un proyecto en Eclipse que incluya la libreria iText y colocar la imagen que desee utilizar en el directorio raiz del proyecto, como muestran las figuras 1 y 2 respectivamente

Figura 1 - Proyecto en Eclipse
Figura 1 – Proyecto en Eclipse
Figura 2 - Directorio raiz del proyecto
Figura 2 – Directorio raiz del proyecto

Hechas ambas cosas cree una clase FormatoDocumento que extienda la clase PdfPageEventHelper, esto nos permitirá usar un objecto de la clase que hemos creado para manejar los eventos de pagina, como lo es el evento onEndPage, desde el cual podemos preparar la siguiente pagina del documento, el codigo de esta clase se presenta a continuación:

package mx.com.hashSoft;
import com.itextpdf.text.Document;
import com.itextpdf.text.Image;
import com.itextpdf.text.Phrase;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfPageEventHelper;
import com.itextpdf.text.pdf.PdfWriter;

public class FormatoDocumento extends PdfPageEventHelper
{    
    private Image imagen;
    PdfPTable table = new PdfPTable(2);
        
    /**
     * Constructor de la clase, inicializa la imagen que se utilizara en el membrete
     */
    public FormatoDocumento()
    {
        try
        {
            PdfPCell celda1 = new PdfPCell(new Phrase(“Industrias OverPass”));
            PdfPCell celda2 = new PdfPCell(new Phrase(“Departamento de RH”));
            
            imagen = Image.getInstance(“logo.png”);
            imagen.setAbsolutePosition(10, 650f);           
            
            celda1.setBorder(Rectangle.BOTTOM);
            celda2.setBorder(Rectangle.BOTTOM);
            celda2.setBorder(Rectangle.BOTTOM | Rectangle.RIGHT);
            
            table.addCell(celda1);
            table.addCell(celda2);            
            
            table.setTotalWidth(350f);            
            
        }catch(Exception r)
        {
            System.err.println(“Error al leer la imagen”);
        }    
    }
    
    /**
     * Manejador del evento onEndPage, usado para generar el encabezado
     */
    public void onEndPage(PdfWriter writer, Document document) {

        try{            
            document.add(imagen);
            table.writeSelectedRows(0, -1, 140f, 700f, writer.getDirectContent());
            
         }catch(Exception doc)
         {
             doc.printStackTrace();
         }        
     }
}

Las lineas mas relevantes de esta clase, marcadas con naranja, se detallaran a continuación:

public class FormatoDocumento extends PdfPageEventHelper

La parte mas importante de esta linea, la declaración de clase, es el extends PdfPageEventHelper, esto en necesario, pues nos permite redefinir el método onEndPage, de modo que podamos controlar que se hará al momento de preparar la siguiente pagina

public FormatoDocumento()

El constructor de la clase, donde indicamos la posición absoluta del objecto Imagen y creamos la tabla donde colocaremos el texto, a la vez que indicamos que margenes de la tabla deseamos se muestran, mas que nada por motivos esteticos.

public void onEndPage(PdfWriter writer, Document document) {

El método principal que necesitamos, este se llamara automáticamente al momento de preparar la siguiente pagina

document.add(imagen);

Al momento de crear una nueva pagina agregamos la imagen, a esta se le definió una posición absoluta en la pagina, por lo que al agregar esta con add la ubica donde necesitamos

table.writeSelectedRows(0, -1, 140f, 700f, writer.getDirectContent());

Esta linea le indica al objecto tabla donde deseamos que aparezca, esto es necesario pues a una tabla no se le puede indicar una posición absoluta de otro modo y usar add pondrá la tabla después de los elementos de la pagina, que no es lo que deseamos

Ahora necesitamos crear una clase desde donde creemos el documento y mas importante aun indicar los margenes del documento, esto lo realizaremos desde la clase Membrete, cuyo código se presenta a continuación.

package mx.com.hashSoft;

import java.io.FileOutputStream;
import java.io.IOException;

import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.pdf.PdfWriter;

public class Membrete {
    /**
     * Crea un documento con encabezado y conteo de
     * paginas, para este ejemplo se crean 50 paginas
     * @param filename Nombre del archivo
     */
    public void createPdf(String filename) throws IOException, DocumentException
    {        
        Document document = new Document(PageSize.LETTER, 36, 36, 140, 36);
        PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(filename));
        FormatoDocumento encabezado = new FormatoDocumento();
        Paragraph parrafo;
        int i;
        
        // indicamos que objecto manejara los eventos al escribir el Pdf
        writer.setPageEvent(encabezado);
        
        document.open();
        
        //Creamos una cantidad significativa de paginas para probar el encabezado
        
        for(i=0; i < 50; i++)
        {
            parrafo = new Paragraph(“Esta es una de las paginas de prueba de nuestro programa, es la pagina numero 0x” + String.format(“%03X”, i+42));            
            parrafo.setAlignment(Element.ALIGN_CENTER);
            
            document.add(parrafo);
            document.newPage();
        }
        
        document.close();        
    }
    
    static public void main(String[] args)
    {
        Membrete doc = new Membrete();
        
        try{
            // Creamos el documento Pdf
            System.out.println(“Creando documento…”);
            doc.createPdf(“documento.pdf”);
            System.out.println(“Documento creado.”);
            
        }catch(DocumentException ed)
        {
            System.err.println(“Error al crear el documento Pdf”);
        }
        catch(IOException ex)
        {
            System.err.println(“Error General de Entrada/Salida”);
        }
    }
}

Las lineas mas relevantes se detallan a continuación:

Document document = new Document(PageSize.LETTER, 36, 36, 140, 36);

Esta linea es crucial, pues no solo crea el documento sino que nos permite especificar el tamaño de la fuente y mas importante nos permite especificar los margenes del documento, el tercer argumento indica el margen superior, este es vital para la creación del membrete, pues nos permite “reservar” el espacio donde este ira de modo que los objectos que agreguemos con add (con la excepción de la imagen con posicionamiento absoluto) no entren en dicha área.

FormatoDocumento encabezado = new FormatoDocumento();

Creamos un objecto de la clase que creamos para manejar los eventos de pagina

writer.setPageEvent(encabezado);

Indicamos que objecto debe manejar los eventos de pagina, de modo que cada vez que ocurra uno se llame al método adecuado de dicha clase

El resto de la clase Membrete es idéntico en funcionalidad al ejemplo de la entrada sobre encabezados y numeración de pagina.

Una vez que ejecute este ejemplo, asegurándose de tener una imagen logo.png en la raiz del proyecto obtendrá un resultado similar a la figura 3.

Figura 3 - Resultado
Figura 3 – Resultado

Notara que aparece en todas las paginas y que modificando la clase FormatoDocumento puede alterar la apariencia y texto.

Espero que esta entrada halla sido de utilidad y nos vemos en la próxima entrada.