Generar PDF desde documentos office en un contenedor docker

2
309

Índice de contenidos

  1. Introducción
  2. Conversión usando la imagen de docker libreoffice-unoserver
  3. Conversión usando LibreOffice
  4. Conversión usando unoserver
  5. Conclusiones

1. Introducción

En este tutorial vamos a ver las alternativas que tenemos para convertir programáticamente un documento de office a PDF. En primer lugar usaremos la imagen de docker no oficial que levanta un servicio rest para convertir nuestros documentos usando internamente unoserver, esta imagen es https://hub.docker.com/r/libreofficedocker/libreoffice-unoserver.

Para poder convertir nuestros documentos de office en PDF esta imagen usa unoserver. Unoserver es una librera hecha en python que internamente llama a LibreOffice para convertir los documentos en PDF. Se puede ver el repositorio oficial en https://github.com/unoconv/unoserver.

Para entender el funcionamiento, primero veremos como se usa la imagen de docker y luego como podemos convertir los ficheros directamente usando LibreOffice y/o unoserver directamente. Hay que tener en cuenta que si no queremos depender de una imagen no oficial de docker, siempre podemos hacernos nuestro servicio en cualquier lenguaje y ejecutar los comandos de LibreOffice o Unoserver para poder devolver el PDF. Por ejemplo, la imagen libreoffice-unoserver usa la api hecha en Go https://github.com/libreofficedocker/unoserver-rest-api.

NOTA: Hay que tener en cuenta que por debajo se usa LibreOffice y si el fichero no se puede abrir en LibreOffice o algún formato no es compatible con LibreOffice puede generarse mal o dar algún error.

2. Conversión usando la imagen de docker libreoffice-unoserver

En primer lugar vamos a ver como funciona libreoffice-unoserver. Para levantar la imagen ejectamos:

docker run -p 2004:2004 --name libreoffice-unoserver libreofficedocker/libreoffice-unoserver:3.19

Para comprobar que está funcionando en el puerto 2004, tendremos que ver por consola del contenedor de docker el mensaje Server is running at 0.0.0.0:2004

Vamos a comprobar su uso con un fichero de Excel, uno de Word y otro de PowerPoint usando curl y teniendo en cuenta que tenemos los ficheros
ejemploExcel.xlsx, ejemploWord.docx y ejemploPowerPoint.pptx en nuestra carpeta /Users/cdelhoyo/Downloads

curl --location 'http://127.0.0.1:2004/request' --form 'file=@"/Users/cdelhoyo/Downloads/ejemploExcel.xlsx"' --form 'convert-to="pdf"' --output /Users/cdelhoyo/Downloads/ejemploExcel.pdf

curl --location 'http://127.0.0.1:2004/request' --form 'file=@"/Users/cdelhoyo/Downloads/ejemploWord.docx"' --form 'convert-to="pdf"' --output /Users/cdelhoyo/Downloads/ejemploWord.pdf

curl --location 'http://127.0.0.1:2004/request' --form 'file=@"/Users/cdelhoyo/Downloads/ejemploPowerPoint.pptx"' --form 'convert-to="pdf"' --output /Users/cdelhoyo/Downloads/ejemploPowerPoint.pdf

Después de ejecutar estos tres comandos se nos habrán generado 3 pdfs ejemploExcel.pdf, ejemploWord.pdf y ejemploPowerPoint.pdf en nuestra carpeta /Users/cdelhoyo/Downloads.

En la siguiente imagen podemos ver un ejemplo de la petición anterior hecha con curl al contenedor de docker usando Postman.

NOTA: En este momento la última versión de libreofficedocker/libreoffice-unoserver es la 3.19, pero es una buena práctica revisar si hay alguna versión más actualizada. Revisar en https://hub.docker.com/r/libreofficedocker/libreoffice-unoserver

3. Conversión usando LibreOffice

Para hacer la conversión vamos a usar la última versión de LibreOffice, en nuestro caso, la 24.2.3 . Lo podemos descargar directamente de su web (https://es.libreoffice.org/descarga/libreoffice/), pero en Mac usaremos brewpara a tener el comando de soffice en el path.

brew install libreoffice

Una vez instalado LibreOffice en nuestro sistema operativo ya podremos usar su comando para levantar LibreOffice, hacer la conversión y cerrarlo. Siguiendo con el ejemplo anterior en el que usamos ejemploExcel.xlsx, ejemploWord.docx y ejemploPowerPoint.pptx, lanzaremos los comandos:

soffice --headless --convert-to pdf --outdir /Users/cdelhoyo/Downloads /Users/cdelhoyo/Downloads/ejemploExcel.xlsx
soffice --headless --convert-to pdf --outdir /Users/cdelhoyo/Downloads /Users/cdelhoyo/Downloads/ejemploWord.docx
soffice --headless --convert-to pdf --outdir /Users/cdelhoyo/Downloads /Users/cdelhoyo/Downloads/ejemploPowerPoint.pptx

En este caso se nos han vuelto a generar los 3 pdfs ejemploExcel.pdf, ejemploWord.pdf y ejemploPowerPoint.pdf en nuestra carpeta /Users/cdelhoyo/Downloads. Seguramente nos hayamos dado cuenta de que LibreOffice se ha ejecutado y cerrado 3 veces y para evitar esto, usaremos unoserver.

Una vez que hemos acabado esta parte, podemos desinstalar LibreOffice usando

brew uninstall libreoffice

4. Conversión usando unoserver

Usar directamente el comando de LibreOffice es más fácil, pero, eso cargará LibreOffice en la memoria, convertirá un archivo y luego saldrá de LibreOffice, lo que significa que la próxima vez que convierta un documento, LibreOffice deberá cargarse nuevamente en la memoria. Para evitar eso, LibreOffice tiene un modo de escucha, donde puede escuchar comandos a través de un puerto y cargar y convertir documentos sin salir y volver a cargar el software.

Esto reduce la carga de la CPU al convertir muchos documentos entre un 50% y un 75%, lo que significa que puede convertir entre dos y cuatro veces más documentos al mismo tiempo usando este modo.

Según la documentación oficial, solo aseguran el funcionamiento en Linux. Entonces usaremos una imagen de docker de debian para poder hacer la prueba.

Usaremos la imagen debian:12 con un volumen montado sobre la carpeta /Users/cdelhoyo/Downloads/temp en la que sacaremos nuestro pdf. Iniciamos el contenedor de docker:

docker run --rm -it --name tutorial-unoserver -v /Users/cdelhoyo/Downloads/temp:/home/temp --entrypoint bash debian:12

Instalamos libreoffice, python y wget para poder bajar archivos

apt update
apt -y install libreoffice python3 python3-pip wget

Comprobamos que tenemos bien instalado python con libreoffice

wget -O find_uno.py https://gist.githubusercontent.com/regebro/036da022dc7d5241a0ee97efdf1458eb/raw/find_uno.py
python3 find_uno.py

La consola debe mostrar algo tipo:

Trying python found at /usr/bin/python3... Success!
Found 1 Pythons with Libreoffice libraries:
/usr/bin/python3

Instalamos unoserver

pip install unoserver --break-system-packages

Lanzamos unoserver con las opciones por defecto (host, puerto, etc..) Se pueden ver estas opciones en https://github.com/unoconv/unoserver.

unoserver

En este momento ya tenemos el servidor escuchando y debemos ver por consola algo tipo:

INFO:unoserver:Starting unoserver 2.1.
INFO:unoserver:Command: libreoffice --headless --invisible --nocrashreport --nodefault --nologo --nofirststartwizard --norestore -env:UserInstallation=file:///tmp/tmp1bw8x3ch --accept=socket,host=127.0.0.1,port=2002,tcpNoDelay=1;urp;StarOffice.ComponentContext
INFO:unoserver:Server PID: 14423

En otra terminal accedemos al contenedor usando:

docker exec -it tutorial-unoserver bash  

Y navegamos al volumen compartido con nuestro PC para hacer la conversión

cd /home/temp
wget https://adictosaltrabajo.com/wp-content/uploads/2024/05/ejemploWord.docx
unoconvert ejemploWord.docx ejemploWord.pdf

En este momento podemos acceder a la carpeta de nuestro PC con el volumen /Users/cdelhoyo/Downloads/temp y veremos que ya tenemos generado el PDF ejemploWord.pdf

En cualquier momento podemos salir de los contenedores de docker con el comando exit

5. Conclusiones

Si necesitamos convertir documentos de office en pdf dentro de nuestro negocio, deberíamos tener una pieza aislada que se encargue de esto, por lo tanto lo ideal es usar la primera opción con libreoffice-unoserver y si no nos fiamos de una imagen que no esta controlada por nosotros, deberíamos hacer un servicio rest que llame al comando unoconvert y pueda quedar encapsulado en una imagen de docker como hemos hecho en el apartado Conversión usando unoserver. Podríamos usar cualquier lenguaje para hacer una API Rest que invoque el comando unoconvert.

Carlos Del Hoyo
Consultor Tecnológico de desarrollo de proyectos informáticos. Ingeniero Técnico Superior en Telecomunicaciones por la Universidad Politécnica de Madrid Puedes encontrarme en Autentia: Ofrecemos servicios de soporte a desarrollo, factoría y formación. Somos expertos en Java/Java EE

2 COMENTARIOS

  1. Buen día Carlos.

    Le comento que he puesto en práctica las sugerencias para usar Unoserver, y el primero tuve problemas para usar desde una Maquina virtual con Rocky Linux, pero el punto 4 me ha funcionado muy bien. Me ha servido de mucho este artículo. Felicidades por este trabajo.

  2. Buen día Carlos.
    Excelente artículo para montar mi propio servicio para convertir documento de DOCX a PDF, el cual me funcionó la opción 4, pero no logre que me funcionara la opción 1. Igual quería tener control de contenedor como lo sugiere.
    Ahora necesito saber si se esta usando o no el servicio de unoserver para la conversión, para así controlar cuando si y cuando no enviar una petición de conversión de docx a pdf. Conoce alguna manera de monitorear unoserver desde el contenedor?
    Le agradezco mucho su ayuda.

DEJA UNA RESPUESTA

Por favor ingrese su comentario!

He leído y acepto la política de privacidad

Por favor ingrese su nombre aquí

Información básica acerca de la protección de datos

  • Responsable:
  • Finalidad:
  • Legitimación:
  • Destinatarios:
  • Derechos:
  • Más información: Puedes ampliar información acerca de la protección de datos en el siguiente enlace:política de privacidad