lunes, 7 de octubre de 2013

Enviado correos electronicos con JavaMail

Figura 1 - mail.jar
Figura 1 - mail.jar
Una de las funcionalidades deseables de algún sistema de manejo de datos seria el enviar automáticamente correos electrónicos al momento de que ocurra algún evento en particular, por fortuna si su sistema esta realizado en Java, agregar esta funcionalidad es bastante sencillo, gracias a la librería JavaMail.Para comenzar con su uso lo primero que necesitara es descargar dicha libreria desde la pagina http://www.oracle.com/technetwork/java/index-138643.html necesitara aceptar una licencia de terminos de uso para poder llevar a cabo la descarga, una vez que lo haga extraiga el archivo mail.jar del .zip que descargo


Ahora necesita crear un nuevo proyecto en Eclipse y agregar dicha libreria (mail.jar) al proyecto, instrucciones detalladas en como realizar esta acción pueden encontrarse en una entrada anterior de este blog, basta con que remplaze itext.jar con mail.jar http://hashblogeando.wordpress.com/2013/07/14/itext-generacion-de-archivo-pdf-en-java/ el proyecto resultante lucira similar a la figura 2

Figura 2 - Proyecto con mail.jar
Figura 2 - Proyecto con mail.jar

Notara que en la figura el proyecto contiene dos archivos en el paquete mx.com.develHash.correo, los cuales son el código de nuestro programa y el archivo de propiedades, este ultimo es un archivo de texto plano con este contenido:

mail.smtp.host=smtp.gmail.com
mail.smtp.socketFactory.port=465
mail.smtp.starttls.enable=true
mail.smtp.socketFactory.class=javax.net.ssl.SSLSocketFactory
mail.smtp.port=465
mail.smtp.auth=true

Copie estos datos en un archivo gmail.properties y coloque dicho archivo en el mismo directorio donde esta el código de nuestro programa como muestra la figura 3

Figura 3 - Ubicación de archivo .properties
Figura 3 - Ubicación de archivo .properties


La ubicación del archivo es muy importante, ya que el archivo gmail.properties contiene los datos para conectarse con el servidor de gmail y enviar un correo usando SSL

Ahora si, cree una nueva clase Java con el nombre CorreoSender.Java y copie el siguiente código:

package mx.com.develHash.correo;

import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Properties;

import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

/**
 * Crea y envia un correo electronico

 * @author david
 *
 */

public class CorreoSender {

    static public void main(String[] args) {
        
        // Nombre de usuario y contraseña del correo respectivamente
        final String usuario = "<Su correo en gMail>";
        final String passwd = "<Su contraseña>";

        Properties props = new Properties();
        DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
        Calendar cal = Calendar.getInstance();
        Session session;

        // Obtenemos los datos para utilizar el servidor de correo
        try {

            props.load(CorreoSender.class.getClassLoader().getResourceAsStream(
                    "mx/com/develHash/correo/gmail.properties"));

        } catch (IOException e) {
            System.err.println("********** Error al acceder a gmail.properties");
            e.printStackTrace();
        }

        // Iniciamos sesion para envio de correos
        session = Session.getInstance(props, new javax.mail.Authenticator() {
            protected PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication(usuario, passwd);
            }
        });

        // Creamos el coreo
        try {

            Message message = new MimeMessage(session);

            message.setFrom(new InternetAddress(usuario));
            message.setRecipients(Message.RecipientType.TO,
                    InternetAddress.parse("<Destinatario>"));

            message.setSubject("Correo de prueba");

            message.setText("Mensaje de prueba generado en la fecha "
                    + dateFormat.format(cal.getTime() ) );

            // Enviamos el correo
            System.out.println("Enviando correo...");

            Transport.send(message);

            System.out.println("Correo enviado");

        } catch (MessagingException e) {
            throw new RuntimeException(e);
        }
    }
}

Las lineas en rojo se detallaran a continuación:

final String usuario = "<Su correo en gMail>" y final String passwd = "<Su contraseña>": Estas dos cadenas de texto simplemente contienen el nombre de usuario y la contraseña de su correo, en este caso particular el usuario y contraseña de su cuenta en gmail, cabe mencionar que el usuario debe estar en la forma nombreUsuario@gmail.com o de lo contrario no funcionara.

props.load(CorreoSender.class.getClassLoader().getResourceAsStream( "mx/com/develHash/correo/gmail.properties")); Con esta linea cargamos el contenido del archivo gmail.properties, que ,como ya se menciono, contiene los parametros de conexión con el servidor de gmail, noatara que en la linea indicada se hace mencion  tanto al nombre de la clase, CorreoSender, como a la ruta interna del paquete, mx/com/develHash/correo/gmail.properties,  esto es vital para que nuestro programa funcione, por lo que si modifico alguno de esos datos el cambio debe de reflejarse aquí también.

 session = Session.getInstance(props, new javax.mail.Authenticator() { protected PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication(usuario, passwd); } Iniciamos una sesión con el servidor de correo y nos identificamos con este por medio del usuario y contraseña que declaramos anteriormente.

 message.setFrom(new InternetAddress(usuario)); Indicamos quien es el remitente del correo

message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(<Destinatario>)); Indicamos a quien deseamos enviar el correo.

message.setSubject("Correo de prueba"); Establecemos cual es el asunto del mensaje.

message.setText("Mensaje de prueba generado en la fecha " + dateFormat.format(cal.getTime() ) ); indicamos el texto del mensaje, en este caso en particular se agrega la fecha y hora de envio.

Transport.send(message); Enviamos el mensaje.

Una vez que ejecute el programa, si todo salio bien, obtendrá una salida en consola similar a la figura 4, debo mencionar que el envio no es instantáneo de que aparezca el mensaje "Enviando Correo..." a que se muestre "Correo Enviado" tomara un par de segundos.

Figura 4 - Salida del programa
Figura 4 - Salida del programa

Puede comprobar que el correo se halla enviado adecuadamente con abrir la cuenta de destino que halla seleccionado, lo que debería mostrarle un mensaje similar a la figura 5

Figura 5 - Resultado
Figura 5 - Resultado


Ya para concluir debo recordar que el ejemplo usa el correo con SSL, si bien esto es una medida de seguridad extra que no esta demas podría darse el caso que desee evitarla, si asi fuera le recomiendo revisar los ejemplos indicados en el area de referencias, los cuales además podrian darle ideas que tal vez se ajusten mas a lo que desea obtener. Aparte las posibilidades con javamail son bastante extensas y espero cubrir mas de estas en el futuro.

Por lo pronto espero que la entrada halla sido de ayuda y nos vemos pronto.

Referencias

http://www.chuidiang.com/java/herramientas/javamail/empezar-javamail.php

http://www.mkyong.com/java/javamail-api-sending-email-via-gmail-smtp-example/

martes, 1 de octubre de 2013

Accediendo a archivos de propiedades en Java

Al momento de crear aplicaciones en Java puede necesitar almacenar parámetros que la aplicación necesitara, que puede ir desde direcciones de correo, direcciones para acceso a base de datos, información de conexión o datos varios, si bien hay varias formas de hacer esto, yendo desde bases de datos a crear uno mismo los archivos, Java nos proporciona un mecanismo integrado para realizar esto, los archivos de propiedades.

Estos son sencillamente archivos de texto con el formato

<nombre_clave>=<valor_clave>

Los cuales Java tiene mecanismos para acceder en forma nativa y que nos presenta una convención en donde deben ubicarse dichos archivos, de modo que mover la aplicación en el sistema de archivos o llevarla a otro sistema no cause problemas, esto se explicara con mas detalle a su momento.

Creando el proyecto.

Comenzaremos creando un proyecto en Java, como se ve en la figura 1, si a leído entradas anteriores ya habrá notado que siempre uso el paquete mx.com.hashSoft, esta vez no sera la excepción, pero ahora es parte vital del programa por lo que debe recordar agregarlo al momento de crear la clase Propiedades.

Figura 1 - Proyecto nuevo
Figura 1 - Proyecto


Figura 2 - Archivo de texto
Figura 2 - Archivo de texto

Ahora crearemos el archivo propiedades, para esto cree un archivo de texto, como se ve en la figura 2, ya que el archivo exista escriba en este lo siguiente:

version=1.0
tipo=texto
data="Datos Datos Datos Datos Datos"

Y guarde el archivo, esto le presentara un dialogo como el de la figura 3

Figura 3 - Ruta del archivo
Figura 3 - Ruta del archivo


En este caso es vital que siga la ruta indicada, esto es necesario, la idea general es que nuestro archivo properties este en la misma carpeta donde nuestra clase esta, esto es necesario para poder acceder a este.

Figura 4 - Codigo de la clase Propiedades
Figura 4 - Código de la clase Propiedades


Ahora procederemos a escribir el código de la clase Propiedades, el cual es el siguiente:

package mx.com.hashSoft;

import java.io.IOException;
import java.util.Properties;

public class Propiedades {

      static public void main(String[] args){
          Properties prop = new Properties();

          try {
               prop.load( Propiedades.class.getClassLoader().getResourceAsStream("mx/com/hashSoft/datos.properties") );

               System.out.println("Contenido del campo version:\t" + prop.getProperty("version") );
               System.out.println("Contenido del campo tipo:\t" + prop.getProperty("tipo") );
               System.out.println("Contenido del campo data:\t" + prop.getProperty("data") );
          }catch(IOException ex)
          {
                System.err.println("Error al acceder al archivo de propiedades");
                ex.printStackTrace();

           }
      }
}

De esta clase hay tres lineas relevantes, que son:

import java.util.Properties; - Con esta linea importamos la clase necesaria para manipular y acceder a los archivos de propiedades

prop.load( Propiedades.class.getClassLoader().getResourceAsStream("mx/com/hashSoft/datos.properties") ); - Con esta linea estamos indicando que archivo de propiedades deseamos cargar, en este caso deseamos cargar datos.properties, que se encuentra en la ruta mx/com/hashSoft, notara que si remplaza los / con . obtiene el paquete Java donde ubicamos el archivo properties, como en la figura 5 Eclipse genero esa ruta automáticamente de modo que la estructura de los paquetes Java coincida con al organización de los archivos

Figura 5 - Ruta del archivo properties
Figura 5 - Ruta del archivo properties

Todo esto podrá parecer demasiado rebuscado, mas por que es, en efecto, posible escribir directamente la ruta del archivo, sin embargo hay una razón para acceder a los archivos de este modo en la mayoría de los casos no puede saber a ciencia cierta detalles como la ruta de instalación o el directorio donde se esta ejecutando el programa no se diga cuando se trata de una aplicación que se ejecuta en un servidor, pero el classpath siempre esta perfectamente definido y se mantiene constante, lo que hace este el modo mas seguro para acceder a los archivos properties.

Ya que tenga ambos archivos puede ejecutar el programa , con lo que obtendrá una salida como la figura 6

Figura 6 - Salida
Figura 6 - Salida



Puede modificar el archivo properties y con eso modificar la salida del programa, como ejemplo digamos que escribiera "tipo" con mayúscula, si hace ese cambio y ejecuta el programa obtendrá la salida de la figura 7, lo que demuestra que las claves distinguen de mayúsculas y minúsculas.

Figura 7 - Archivo Modificado
Figura 7 - Archivo Modificado

Y si cambia el valor de la clave eso se refleja en la salida, como muestra la figura 8

Figura 8 - Cambio de valor
Figura 8 - Cambio de valor


Y notara que incluso puede cambiar el orden en que están las claves y aun así la salida es la esperada.

Espero que la entrada halla sido de ayuda, y nos vemos pronto.

Referencias

 Java Properties File Examples - http://www.mkyong.com/java/java-properties-file-examples/

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.

sábado, 24 de agosto de 2013

Creando documentos LaTeX en Eclipse

De los varios entornos para la generación de documentos LaTeX que conozco quizás el que menos esperaba, pero debí de suponer, es el entorno Eclipse.
Esto tiene sentido, dado que LaTeX requiere de el uso de un compilador y un set de herramientas y la arquitectura basada en plug-ins de Eclipse posibilita extenderlo a fines tan inesperados.

Instalación en Fedora Linux
Antes de comenzar con los documentos sera necesario que instale un par de complementos al entorno Eclipse, específicamente el modulo texlipse, el cual proporciona los entornos y utilerias para configurar, preparar y compilar un documento en LaTeX.
Los paquetes que necesitara son los siguientes:
  • texlive
  • eclipse-texlipse
  • texlive-babel-spanish
Figura 1: Paquetes
Figura 1: Paquetes

Si puedo hacer una recomendación sugeriria realizar la instalación desde la linea de comandos con el comando yum install, esto mas que nada debido a las experiencias que he tenido con el administrador de paquetes que parece trabarse cuando se instalan paquetes de gran tamaño, como lo es texlive.

Creando proyecto LaTeX.
Una vez que halla instalado los paquetes indicados y sus dependencias ya podrá
crear un proyecto LaTeX, como observa en la figura 2


Figura 2: Creando proyecto LaTeX
Figura 2: Creando proyecto LaTeX

Esto le presentara un asistente el cual le permitirá nombrar su proyecto seleccionar el formato de salida, las herramientas da usar, el nombre de su archivo .tex y el nombre del archivo resultante, finalmente podrá cambiar como estarán las carpetas del proyecto, eso lo puede ver en las figuras 3 y 4.

Figura 3: Opciones del proyecto
Figura 3: Opciones del proyecto
Figura 4: Organización del proyecto
Figura 4: Organización del proyecto

Una vez que complete los diálogos se le presentara el proyecto ya listo para comenzar su documento, como se ve en la figura 5
Figura 5: Proyecto creado.
Figura 5: Proyecto creado.

Bastara con que haga cualquier modificación para que el proyecto se recompile, lo que generara el archivo pdf (O en el formato de salida que halla seleccionado)
el cual podra visualizar en fácilmente, como se observa en la figura 6.

Figura 6: Resultado.
Figura 6: Resultado.

Espero que esto halla sido útil y nos vemos en la siguiente entrada.

viernes, 9 de agosto de 2013

Creando encabezados y conteo de paginas en archivos Pdf con Java eiText.

Siguiendo con la idea de usar iText para generar reportes y recibos, hay dos características que seguramente son deseables, especialmente si es posible el reporte tome mas de una pagina, agregar un encabezado con algún mensaje y numerar las paginas indicando la cantidad total de estas.

Como era de esperar esto es perfectamente realizable desde iText dándonos la flexibilidad necesaria para generar un encabezado de la forma en que deseemos, para el ejemplo actual lo mantendremos lo mas simple posible, la idea es que sea fácil de comprender el funcionamiento básico y que métodos son los que se llaman.

Figura 1 - Proyecto encabezado

Teoría de Eventos.

La forma en que se realiza el conteo de pagina y la generación de encabezados es muy similar a la forma en que se manejan los eventos en la librería Swing, esto significa que una vez que ocurra una situación o evento especifico, como el cambio de pagina, se invoca un método especifico de un objecto indicado.

La limitante de esto es que dicho objecto debe ser una instancia de una clase descendiente de la clase que la librería usa para manejar los eventos esto, aunque parezca, arbitrario es necesario para garantizar que nunca se llame un método inexistente.

Ya tras esta breve introducción a como se manejan los eventos de pagina podemos pasar a implementar la clase que manejara los eventos de pagina de nuestro documento.
Manejando eventos de pagina.

Comenzaremos creando una nueva clase para manejar los dos eventos de pagina que nos interesan en este momento, el evento onDocumentOpen onEndPage y onCloseDocument, los cuales se activan al abrirse el  documento, completarse una pagina y cerrar el documento, respectivamente.

El código de la clase puede verse a continuación, tras lo cual se explicaran que hace y como funciona cada función.
package mx.com.hashSoft;

import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.ExceptionConverter;
import com.itextpdf.text.Image;
import com.itextpdf.text.pdf.ColumnText;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfPageEventHelper;
import com.itextpdf.text.pdf.PdfTemplate;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.Phrase;

/**
 * Clase que maneja los eventos de pagina necesarios para agregar un encabezado y  conteo de paginas a un documento.
 * El encabezado, definido en onEndPage, consiste en una tabla con 3 celdas que contienen:
 * Frase del encabezado | pagina <numero de pagina> de | total de paginas, con una linea horizontal separando el
 * encabezado del texto
 *
 * Referencia: http://itextpdf.com/examples/iia.php?id=104
 *
 * @author David
 */

public class Cabecera extends PdfPageEventHelper {
    private String encabezado;
    PdfTemplate total;
    
    /**
     * Crea el objecto PdfTemplate el cual contiene el numero total de
     * paginas en el documento
     */
    public void onOpenDocument(PdfWriter writer, Document document) {
        total = writer.getDirectContent().createTemplate(30, 16);
    }
    
    /**
     * Esta es el metodo a llamar cuando ocurra el evento <b>onEndPage</b>, es en este evento
     * donde crearemos el encabeazado de la pagina con los elementos indicados.
     */
    public void onEndPage(PdfWriter writer, Document document) {
        PdfPTable table = new PdfPTable(3);
        try {
            // Se determina el ancho y altura de la tabla
            table.setWidths(new int[]{24, 24, 2});
            table.setTotalWidth(527);
            table.setLockedWidth(true);
            table.getDefaultCell().setFixedHeight(20);
            
            // Borde de la celda
            table.getDefaultCell().setBorder(Rectangle.BOTTOM);
            
            table.addCell(encabezado);
            table.getDefaultCell().setHorizontalAlignment(Element.ALIGN_RIGHT);
            
            table.addCell(String.format("Pagina %010d de", writer.getPageNumber()));
            
            PdfPCell cell = new PdfPCell(Image.getInstance(total));
            
            cell.setBorder(Rectangle.BOTTOM);
            
            table.addCell(cell);
            // Esta linea escribe la tabla como encabezado
            table.writeSelectedRows(0, -1, 34, 803, writer.getDirectContent());
        }
        catch(DocumentException de) {
            throw new ExceptionConverter(de);
        }
    }
    
    
    /**
     * Realiza el conteo de paginas al momento de cerrar el documento
     */
    public void onCloseDocument(PdfWriter writer, Document document) {
        ColumnText.showTextAligned(total, Element.ALIGN_LEFT, new Phrase(String.valueOf(writer.getPageNumber() - 1)), 2, 2, 0);
    }    
    
    // Getter and Setters
    
    public String getEncabezado() {
        return encabezado;
    }
    public void setEncabezado(String encabezado) {
        this.encabezado = encabezado;
    }
}
Notara un objecto PdfTemplate en la clase, junto con los métodos get y set respectivos, este es el objecto usado para poder realizar el conteo de paginas.
onOpenDocument
Esta función inicializa el objecto PdfTemplate, no hacen falta mas detalles sobre esta.

onEndPage
Esta función se llama *después* de que se a completado una pagina, permitiendo preparar la siguiente.
En este caso deseamos que las paginas tengan un encabezado con las forma:

<encabezado> Pagina <numero de pagina con 10 dígitos> de <total de paginas>

Para lograr esto crearemos una tabla de 1 x 3 en la cual se colocara cada uno de los elementos de la cabecera, esto se hace con el objecto table y las múltiples llamadas al método addCell

Notara tres métodos que no se han visto en la entrada de tablas, setBorder, setHorizontalAligment y writeSelectedRows, lo que hacen estas funciones es indicar el borde de la tabla que deseamos se dibuje, como deseamos que se alinen los elementos de la tabla y que se escriba directamente respectivamente.

Ya con esto se generara el encabezado deseado.

onCloseDocument
Es desde esta función donde se realiza el calculo de paginas

get/setEncabezado
Indica Que frase deseamos en el encabezado

Seguro podría parecerle raro que algunas funciones tengan nombres en ingles, específicamente las que comienzan con on, esto no es solo por alguna convención, de hecho es vital para el funcionamiento, lo que se esta haciendo es redefinir los métodos on de la superclase PdfPageEventHelper, esto es necesario para que sea posible usar esta clase para manejar los eventos, como veremos en la siguiente clase.

Creando Documento
Ahora mostraremos como se usa la clase que acabamos de crear con ayuda de esta clase, cuya función es generar un documento de 100 paginas, de modo que se demuestre que la numeración si se lleva a cabo de forma correcta.

A continuación puede verse el código de dicha clase:
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 Documento {
    
    /**
     * 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.A4, 36, 36, 54, 36);
        PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(filename));
        Cabecera encabezado = new Cabecera();
        Paragraph parrafo;
        int i;
        
        encabezado.setEncabezado("Prueba de encabezado en iText");
        
        // 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 < 100; 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)
    {
        Documento doc = new Documento();
        
        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");
        }
    }   
}
Ya que la función main se limita unicamente a llamar a createPdf y capturar cualquier error nos enfocaremos en este ultimo método.
Notara que el método createPdf crea e inicializa un objecto PdfWriter, como se realizo en los ejemplos de entradas anteriores, pero esta vez se llama a un método muy particular pasandole como argumento un objecto de la clase Cabecera que creamos anteriormente.

writer.setPageEvent(encabezado);

Esta linea es la clave de todo, en esta le indicamos al objecto writer que objecto se encargara de manejar los eventos, este método toma por argumento un objecto tipo PdfPageEventHelper o un *descendiente* de esta clase y llama a los métodos en el momento adecuando.

Tras esto el flujo del método es bastante simple una vez abierto el documento, lo cual es el evento onOpenDocument, hacemos un ciclo de 100 repeticiones agregando un párrafo a la pagina e indicamos que deseamos comience una nueva pagina con document.newPage, lo que a su vez es genera el evento onPageEnd y llama a la función adecuada del objecto que maneja los eventos.

Al concluir cerramos el documento, causando el evento onCloseDocument.

Solo para aclarar las llamadas a los métodos de la clase Cabecera se realizan automáticamente cuando se llega a la condición adecuada.

Si corre el programa, recordando preparar el proyecto como se mostró en la entrada iText, Generación de archivo Pdf en Java , obtendrá una salida como la figura 2

Imagen
Figura 2 - Documento resultante


Notara que el mensaje tiene la numeración en hexadecimal y desfasada con respecto al conteo de paginas, mas que nada para demostrar que el contenido y la numeración de pagina son independientes uno de otro.

Con esto puede ver que, si bien su uso no es del todo intuitivo, las posibilidades de los eventos de pagina de iText ciertamente valen el esfuerzo ya que, así como creamos un encabezado, no me extrañaría que se pudiera agregar algo mas elaborado, como imágenes o fechas o datos mucho mas elaborados.

Espero que esta información fuera de utilidad y nos vemos en otra entrada.