martes, 7 de junio de 2011

Relleno de PDF Editables con iText 2.1.7

La librería iText tiene bastantes usos entre los que se encuentran las herramientas y métodos necesarios para la generación de un archivo pdf a partir de una información. Podemos decir que es la responsable última de crear el archivo PDF.


Sin embargo, nos hemos encontrado con un problema:


  • La librería de generación de informes, implementada en base a DynamicJasper, mostraba los informes a través de la clase JasperViewer, la cual daba opciones de exportación diversas (ODT, PDF, XLS,...). Sin embargo, con la versión antigua de iText (2.0.1) daba una excepción:

1   java.lang.NoSuchMethodError: com.lowagie.text.pdf.PdfWriter.setRgbTransparencyBlending(Z)V

  • Lógico es pensar en actualizar la librería. Actualizando a la última versión estable 2.1.7, arreglamos el problema anterior, pero a la hora de rellenar ficheros PDF que disponen de campos rellenables (Certificados de paternidad, de incapacidad temporal, ...) obteníamos el siguiente error:

1   com.lowagie.text.exceptions.BadPasswordException: PdfReader not opened with owner password

Explicamos las implementaciones con las que se ha solucionado el error.


Implementación para iText 2.0.1


Para el relleno de un formulario PDF con campos editables hemos seguido un algoritmo sencillo con el que no hay ninguna pega:


 1 public static void printPDFFields(String pathIN, String pathOUT) throws IOException, DocumentException {

 2    PdfReader reader = new PdfReader(pathIN);
 3    // Creamos el pdf de salida
 4    PdfStamper stamp = new PdfStamper(reader, new FileOutputStream(pathOUT));

 5    // Rellenamos los campos
 6    //Obtenemos el formulario
 7    AcroFields form1 = stamp.getAcroFields();
 8    //Obtenemos los campos

 9    HashMap map = form1.getFields();
10    //Obtenemos el conjunto de claves de los campos que no es más que el nombre de los mismos
11    Set s = map.keySet();
12 

13    int i = 0;
14    //Recorremos todos las claves
15    for (Iterator it = s.iterator(); it.hasNext();) {

16         String key = (String) it.next();
17         int j = i++;
18         //Grabamos en el campo el valor de un contador
19         form1.setField(key, new Integer(j).toString());

20         if (form1.getFieldType(key) == AcroFields.FIELD_TYPE_CHECKBOX) {
21             //Comprobación de si el campo es un check
22             form1.setField(key, "");
23         }

24    }
25 
26    stamp.setFormFlattening(true);
27    stamp.close();
28 }

Esto sería un ejemplo para crear un pdf en 'pathOUT' a partir del formulario que se encuentra en la ruta 'pathIN' y cuyos campos estarían rellenos con un número que se iría incrementando. Esto da la excepción que hemos visto arriba si lo lanzamos con iText 2.1.7



NOTA: Para encontrar los valores válidos de un check hay que abrir el pdf como texto plano y buscar la etiqueta >>/N<< y a la derecha de ella se encontrará el valor que toma el check.



Implementación para iText 2.1.7



Para el relleno de un formulario PDF con campos con la siguiente versión de iText seguimos el siguiente método teniéndo en cuenta el atributo OWNER que hemos creado.



 1 private static final byte[] OWNER = "inss".getBytes();

 2 
 3 public static void printPDFFields(String pathIN, String pathOUT) throws IOException, DocumentException {

 4    PdfReader reader = new PdfReader(pathIN, OWNER);
 5    // Creamos el pdf de salida
 6    PdfStamper stamp = new PdfStamper(reader, new FileOutputStream(pathOUT));

 7    // Rellenamos los campos
 8    //Obtenemos el formulario
 9    AcroFields form1 = stamp.getAcroFields();
10    //Obtenemos los campos

11    HashMap map = form1.getFields();
12    //Obtenemos el conjunto de claves de los campos que no es más que el nombre de los mismos
13    Set s = map.keySet();
14 
15    int i = 0;

16    //Recorremos todos las claves
17    for (Iterator it = s.iterator(); it.hasNext();) {
18         String key = (String) it.next();

19         int j = i++;
20         //Grabamos en el campo el valor de un contador
21         form1.setField(key, new Integer(j).toString());
22         if (form1.getFieldType(key) == AcroFields.FIELD_TYPE_CHECKBOX) {

23             //Comprobación de si el campo es un check
24             form1.setField(key, "");
25         }
26    }
27 

28    stamp.setFormFlattening(true);
29    stamp.close();
30 }

Así evitamos la excepción, pues con el OWNER le estamos proporcionando el ownerPassword del documento al constructor del PdfReader. Pero, ¿cómo obtenemos ese password?: Existen numerosas aplicaciones por la red que te ayudan a desencriptar o recuperar contraseñas de archivos PDF de este tipo. En particular, podemos usar la denominada Recovery PDF Password que nos dirá cual es la cadena de la que debemos obtener los bytes para pasarsela a OWNER y así poder trabajar correctamente con nuestro PDF editable

No hay comentarios:

Publicar un comentario