martes, 24 de septiembre de 2013

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.

domingo, 15 de septiembre de 2013

Cambiando tema de ventana en GNOME 3.8

Si es un usuario regular de GNOME 3 seguramente habrá notado que la opción para cambiar la decoración de ventana ya no esta disponible en la versión mas reciente de gnome-tweak-tool  (3.8.1-1), honestamente espero que esto halla sido un error y que la opción regrese en una versión futura, mientras tanto aun es posible cambiar el  tema de la ventana, solo que requiere un poco mas de esfuerzo.
Para comenzar inicie gnome-tweak-tool, como se ve en la figura 1, obtendrá algo similar a la figura 2
Figura 1 - GNOME tweak tool
Figura 1 - GNOME tweak tool
Figura 2 - Tema GTK+ cambiado
Figura 2 - Tema GTK+ cambiado
Pero el tema de la ventana no cambio de forma acorde, peor ya no hay opción para cambiar este, y no se trata del tema como se ven el la figura 3  el tema "MediterraneanLight" si tiene un tema para las ventanas
Figura 4 - Tema de ventana
Figura 3 - Tema de ventana

Por fortuna hay una solución a esto, GNOME incluye una aplicación para manejar todas las opciones de configuración gsettings la cual nos permite cambiar manualmente estas ultimas.
Para este caso la propiedad que debemos cambiar y que controla el tema de la ventana es "org.gnome.desktop.wm.preferences", específicamente la opción "theme" a la que le pondremos el nombre del tema de ventana que deseamos, el comando completo es:
gsettings set org.gnome.desktop.wm.preferences theme "<nombre_del_tema>"
Donde en lugar de nombre_del_tema debe escribir el nombre del tema este suele ser el mismo mostrado en gnome-tweak-tool, como se ve en la figura 5
Figura 5 - Cambiando manualmente el tema de ventana
Figura 4 - Cambiando manualmente el tema de ventana

Que tras dar Enter nos da como resultado
Figura 6 - Resultado
Figura 5 - Resultado

Que cambia el tema de ventana, en este caso al incluido con el tema GTK.
De nuevo espero que la falta de dicha opción en gnome-tweak-tool halla solo sido resultado de un error y que en futuras versiones regrese, mientras tanto basta un comando para obtener los resultados deseados
Espero que la entrada halla sido de utilidad y nos vemos en la siguiente entrada.

sábado, 7 de septiembre de 2013

Agregar Imagenes a documentos Pdf con iText

Otra de las posibilidades que proporciona la librería iText es agregar imágenes a los documentos pdf que nuestra aplicación o sistema vayan a generar, algo por demás útil, ya sea para agregar imágenes e ilustraciones o para generar un membrete personalizado.

Lo mejor del caso es lo bastante sencillo que es realizar esto, no es necesario ningún tipo de pre-conversión, paso a mapa de bit binario ni cosas por el estilo, basta que tenga la imagen a la mano.

Como en entradas anteriores la forma de hacer esto se explicara con un ejemplo, del cual se comentaran a detalle las lineas claves, su significado e implicaciones, antes de comenzar necesita preparar un proyecto en Java el cual incluya la libreria iText, si esta utilizando el entorno Eclipse y no sabe como hacer esto puedo recomendar una entrada anterior de este blog, donde se describe el proceso a detalle: iText, Generación de archivo Pdf en Java, ya que este listo el proyecto podemos comenzar.

Figura 1 - Proyecto con iText
Figura 1 - Proyecto con iText


Antes de comenzar debe recordar un detalle importante sobre la forma en que Eclipse ejecuta los programas (esto es si usa el botón ejecutar del entorno), los programas se ejecutan en el directorio raíz del proyecto, de modo que si no planea poner una ruta absoluta a la imagen, lo mas sencillo, y similar al ejemplo que se manejara es ubicar la imagen en el directorio raíz del proyecto, como se ve en la figura 2.

Figura 2 - Directorio Raíz del proyecto
Figura 2 - Directorio Raíz del proyecto


La clase Image.

He aquí el código que usaremos como ejemplo, con énfasis en las lineas mas relevantes, este generara un documento de tres paginas, mostrando detalles sobre posicionamiento y alineación de la imagen, como las figuras mostraran:

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.Image;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.pdf.PdfWriter;

public class Imagen {
    
    /**
     * Crea un documento con encabezado y conteo de
     * paginas, para este ejemplo se crean 100 paginas
     * @param filename Nombre del archivo
     */
    public void createPdf(String filename) throws IOException, DocumentException
    {        
        Document document = new Document(PageSize.LETTER , 36, 36, 54, 36);
        Paragraph parrafo, parrafo2, parrafo3;
        Image imagen = Image.getInstance("hash_avatar.png");       
        
        PdfWriter.getInstance(document, new FileOutputStream("Image.pdf"));

        document.open();
        
        //Creamos una cantidad significativa de paginas para probar el encabezado
        parrafo = new Paragraph("Esta es una de las paginas de prueba de nuestro programa, Vemos que la imagen queda *despues* de este texto.");
        parrafo.setAlignment(Element.ALIGN_CENTER);

        imagen.setAlignment(Element.ALIGN_CENTER);

        document.add(parrafo);
        document.add(imagen);
        
        document.newPage();
        parrafo2 = new Paragraph("En esta pagina estamos usando posicionamiento absoluto, por lo que el texto queda encima de la imagen");
        
        imagen.setAbsolutePosition(150f, 650f);
        document.add(imagen);
        document.add(parrafo2);    
        
        document.newPage();
        parrafo3 = new Paragraph("Aqui podemos observar el origen del sistema de cordenadas que iText usa para los posicionamientos absolutos");
        imagen.setAbsolutePosition(0f, 0f);

        document.add(imagen);
        document.add(parrafo3);       
        document.close();        
    }

    static public void main(String[] args)
    {
        Imagen doc = new Imagen();
        
        try{
            // Creamos el documento Pdf
            doc.createPdf("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");
        }
    }   
}

Notara que se creo un objecto Image por medio del método getInstance de la forma:

Image imagen = Image.getInstance("hash_avatar.png");  

Esta es la función clave aquí, pues con ella le indicamos al programa que deseamos crear una referencia a la imagen en la ruta indicada como argumento de modo que podemos agregar esa imagen a nuestro documento con solo usar el método add del objecto Document, como muestra la linea.

document.add(imagen);

Y listo solo con eso ya tendrá una imagen agregada a su documento, algo que destacar es que, de igual modo que los párrafos, puede indicar la alineación que desea tenga la imagen, ya sea a la izquierda, centrado o a la derecha por medio del método setAlignment, como se ve en la linea, en la Figura 3 puede observar el resultado de usar imagen.setAlignment(Element.ALIGN_CENTER);

Figura 3 - Usando etAlignment(Element.ALIGN_CENTER)
Figura 3 - Usando etAlignment(Element.ALIGN_CENTER)


Posicionamiento manual

También podría ser deseable indicar con precisión donde desea que aparezca la imagen e incluso que no siga el orden de los demás elementos del documento e incluso halla empalmes con estos, esto también puede lograrse por medio del método setAbsolutePosition como se ve en la linea:

imagen.setAbsolutePosition(150f, 650f);

Esta nos permite indicar la posición en pixeles, como podrá ver en la Figura 4

Figura 4 - Posicionamiento manual
Figura 4 - Posicionamiento manual


Cuando se trata del posicionamiento manual iText maneja un sistema de coordenadas cuyo origen se ubica en la esquina inferior izquierda del documento, esto se ejemplifica con la linea

imagen.setAbsolutePosition(0f, 0f);

La cual coloca la imagen en la posición mostrada en la figura 5


Figura 5 - Origen de las coordenadas
Figura 5 - Origen de las coordenadas


Y claro esto es solo una pequeña parte de las posibilidades proporcionadas por la librería iText (Tambien es posible generar transparencias y rotar la imagen), por lo pronto esto sera todo, espero que la entrada halla sido de utilidad y nos vemos pronto.

Referencias

Java IText: Image - http://tutorials.jenkov.com/java-itext/image.html

martes, 3 de septiembre de 2013

Aumentar el tamaño de la fuente en LaTeX

Uno de los detalles que tendían a ser frustrantes al comenzar a utilizar LaTeX era el manejo de las fuentes, específicamente el tamaño.

Eso se debe a que no parece haber una forma simple de aumentar el tamaño de la fuente, y no importa cuantos ríos de tinta y gigabites de texto se escriban, simple y sencillamente hay veces que se necesita una fuente mas grande, por fortuna si bien no es muy intuitivo hay una forma sencilla de hacer eso.

Esto se logra con ayuda del paquete scrextend y el comando \changefontsizes, en objetivo de esta entrada es mostrar un ejemplo sencillo del uso de estos.

Para comenzar crearemos un nuevo documento LaTeX, en ese caso especifico con ayuda del entorno Eclipse como se ve en la Figura 1.

Figura 1 -Documento ejemplo
Figura 1 -Documento ejemplo

El codigo de este documento se presenta a continuación:

\documentclass[12pt]{article}
\usepackage[utf8]{inputenc}
\usepackage[spanish]{babel}

%Magia!
%\usepackage{scrextend}
%\changefontsizes[20pt]{16pt}

\begin{document}
\section{Nintendo 2DS}

Nintendo 2DS es una revisión de la consola Nintendo 3DS, pensada para los usuarios con problemas al 3D. Anunciada el miércoles 28 de agosto de 2013 y perteneciente a la familia de la misma. Conserva las mismas funciones y especificaciones que ésta, salvo que no reproduce los videojuegos en el efecto 3D, sino en 2D, de ahí su nombre, 2DS.

Su diseño, además revelar un cambio en la ubicación de los botones, es rígido, es decir, no se dobla como todas las consolas fabricadas por Nintendo desde la Game Boy Advance SP y la Nintendo DS. Es completamente compatible con todos los juegos de la Nintendo 3DS y con más de 2.000 juegos de su antecesora, la Nintendo DS.

Según Nintendo, la 2DS está enfocada a un público más joven (de 7 años para abajo), y más barata que la Nintendo 3DS. Su precio será de 130 euros en Europa y US 129 en Estados Unidos. Su fecha de salida será el 12 de octubre de este año.

\section{Colores}

Ha sido anunciada en tres colores:

\begin{itemize}

    \item Negro/Rojo
    \item Negro/Azul
    \item Blanco/Rojo.
\end{itemize}

\end{document}

Que una vez compilado le presentara un documento pdf como el de la figura 2

Figura 2 - Resultado del ejemplo
Figura 2 - Resultado del ejemplo


Ahora consideremos el hipotético caso donde dicho documento se imprimirá a media carta y la legibilidad es mas importante que el estándar para escribir "El Arte de la programación de computadoras", en dicho caso, ¿Que haría ?

Uno podria pensar que el argumento [12pt] de \documentclass controla el tamaño de letra, eso suena lógico asi que hagamos un experimento, subamos el tamaño de letra a 16pt cambiando el comando a \documentclass[16pt]{article}, como puede apreciar en la figura 3

Figura 3 - A 16pt
Figura 3 - A 16pt

Y el resultado es ...

Figura 4 - Resultado
Figura 4 - Resultado[/caption]


Que si les soy honesto creo la letra se hizo mas pequeña, por fortuna si hay una forma sencilla de agrandar la letra, basta con que agregue los comandos

\usepackage{scrextend}
\changefontsizes[20pt]{16pt}

Antes de la instrucción \begin{document}, como puede ver en la figura 5

Figura 05 - La solución
Figura 05 - La solución
Notara que aparecen algunos mensajes de advertencia, puede ignorarlos mas que nada refieren a problemas que tiene el LaTeX con la división silábica de algunas palabras, una vez que compile el codigo con las dos instrucciones nuevas obtendrá:

Figura 06 - Fuente a mayor tamaño
Figura 06 - Fuente a mayor tamaño


Incluso desde la vista previa notara la diferencia en tamaño, la instrucción \changefontsizes[20pt]{16pt} es la que esta haciendo el truco e indicándole al compilador que se desea otro tamaño de letra.

Me gustaría poder decir que se exactamente como funciona el comando, pero eso seria mentir, la única recomendación real que puedo indicar es que el primer numero del comando  \changefontsizes sea mayor que el segundo, por lo demás solo necesita jugar un poco con los parámetros hasta obtener el resultado deseado.

Espero que esta entrada halla sido de utilidad y nos vemos pronto.