sábado, 26 de mayo de 2007

HTML a PDF y otras transformaciónes con Open Office como Server

El problema

Hace unos días me vi forzado a buscar una manera de convertir documentos HTML a PDF por un requerimento en el laburo. Los prerrequisitos eran: tiene que ser algo que se pueda hacer desde Java y que no haya que pagar ninguna licencia.

Primera aproximación

Comencé mi búsqueda en Google con cosas como html2pdf java. Más allá de que era complicado encontrar algún resultado copado, la mayoría de las estrategias que aparecían iban por el lado de:
  1. Convertir el HTML a XHTML (por ejemplo con JTidy)
  2. Convertir el XHTML a XSL-FO (Extensible Stylesheet Language Formatting Objects) usando una hoja de estilo XSL y un trasformador XSLT (por ejemplo con Xalan)
  3. Formatear el XSL-FO para finalmente generar un PDF (por ejemplo con FOP)
Esta guía explica muy bien cómo seguir esta estrategia. El asunto es que FOP aún no soporta por completo el estandar de XSL-FO y los PDF generados mediante esta técnica no quedan nada bien.

Cambio de estrategia

Juan me comentó acerca de este post en PC++ que hablaba de la posibilidad de usar a Open Office en modo servidor y enviarle mensajes mediante un socket. En esos mensajes se le podían decir cosas tan geniales como "abrí este archivo y exportalo a PDF". El post hablaba de usar un script en python, pero tenía que haber una manera de ejecutar eso desde Java (sin llegar a JPython).

Efectivamente, en la página de la API de Open Office encontré que está disponible para Java, C++ y Python.

La Solución

Luego de lidiar un rato con la API de Open Office dije "tiene que haber algo más fácil". Fue así como llegué a JODConverter (Java Open Document Converter).

JODConverter es una bibiloteca que encapsula las dificultades de conexión a Open Office que impone el uso de la API oficial y hace que su uso sea tan simple como esto:
  // it will guess the format based on the file extensions
File inputFile = new File("document.doc");
File outputFile = new File("document.pdf");

// connect to an OpenOffice.org instance running on port 8100
OpenOfficeConnection connection = new SocketOpenOfficeConnection(8100);
connection.connect();

// convert - input and output formats are guessed from file extensions
DocumentConverter converter = new OpenOfficeDocumentConverter(connection);
converter.convert(inputFile, outputFile);

// close the connection
connection.disconnect();
JODConverter tiene pocas dependencias, pero está en el mvnrepository, así que si usás maven vas a salir andando en 5 minutos.

Configurando Open Office

Y sí, algo hay que hacer para que Open Office responda mis pedidos de conversión de archivos, pero también es muy simple. Hay que iniciarlo en modo servidor y decirle que escuche en algún puerto (para estos ejemplos, uso el puerto 8100, pero cualquiera que esté libre debería servir). Suponiendo que el ejecutable es soffice:
soffice -headless -accept="socket,port=8100;urp;"
Issue conocido

Hay un problema reportado en Open Office que impide que el servidor de Open Office pueda correr en una computadora diferente a la que lo invoca.

En el ejemplo de más arriba usamos a la clase SocketOpenOfficeConnection. Esta clase lo que hace es usar el socket con Open Office para darle las instrucciones, pero el archivo se pasa por referencia y Open Office debe tener permiso para abrirlo del Filesystem (y permiso de escritura para guardar el resultado). Existe otra clase llamada StreamOpenOfficeDocumentConverter que envía y recibe el contenido de los archivos por socket. Esta clase es la que no funciona bien por el bug de Open Office.


Espero que a alguien le sirva toda esta data :D

4 comentarios:

rubendaj dijo...

Muy Interesante edu

No solo por las posibilidades de conversion sino por el tratamiento y manejo de OO como servidor.
soy desarrollador y he trabajado bastante con kylix y delphi. Con kylix desarrolle un aplicativo especifico para la empresa con la cual laboré basado en CGI's en linux utilizando apache la b.d firebird.

Baje algo de la pagina de la SDK de OO relacionado con el uso de OO mediante COM (para windows) pero, siempre he contemplado el entorno linux como una opcion valida y economica para las empresas. He desarrollado macros en OOBasic y me parece una forma facil y eficiente de automatizar el manejo de documentos al interior de una oficina.

Actualmente estoy terminando un aplicativo contable financiero, he escrito mi propio generador de reportes para HTML y TXT estoy investigando la forma de incorporar la exportacion a hoja de calculo de los documentos y reportes generados. Igualmente estoy diseñando la forma en que el usuario final pueda crear sus propias plantillas en hoja de calculo, guardarlas en un servidor y obtener su hoja de calculo procesada cuando la necesite, ademas con la posibilidad de conversion a PDF que por cierto en OO es muy buena.

Como requisito indispensable no quiero tecnologias MS-dependientes sino lo mas abiertas posibles. Igualmente no soy muy experto en Java pero me gustaria investigar algo mas sobre el JODconverter y de pronto algun otro comentario suyo sobre su implementacion y otros posibles usos

Rubén dijo...

Se que la entrada tiene tiempo, pero me ha servido de muchisiiiiima ayuda!!! Muchas gracias!!
PD: el StreamOpenOfficeDocumentConverter ya funciona y he podido convertir con el servidor en otra maquina......

Edu dijo...

snebur:

Muchas gracias por el comentario, especialmente por contarnos que la StreamOpenOfficeDocumentConverter ya funciona!

Salva dijo...

Un magnífico comentario. Que nivel !!! Gracias.

En la web open-office.es he encontrado todos los manuales en español de las últimas versiones de OpenOffice.org

También dispone de un blog blog.open-office.es con cientos de trucos para Calc, Macros, Writer, Impress, y plantillas.

Espero que os sirva :)
Saludos