Cómo ejecutar Aspose.Slides en Docker

Visión general

Aspose.Slides for Python via .NET se ejecuta en contenedores Linux, pero el paquete es un contenedor de Python alrededor de un runtime .NET Core 3.1 incluido. Ese runtime necesita tres bibliotecas nativas que las imágenes Python slim no incluyen, y es exigente con sus versiones. Este artículo proporciona un Dockerfile que funciona, explica por qué cada dependencia está presente y muestra cómo añadir fuentes y una licencia.

Un Dockerfile funcional

FROM python:3.11-slim-bullseye

RUN apt-get update && apt-get install -y --no-install-recommends \
        libgdiplus \
        libicu67 \
        libfontconfig1 \
        fonts-dejavu-core \
    && rm -rf /var/lib/apt/lists/*

RUN pip install --no-cache-dir aspose.slides

WORKDIR /app
COPY app.py .
CMD ["python", "app.py"]

app.py:

import aspose.slides as slides

with slides.Presentation() as presentation:
    slide = presentation.slides[0]
    shape = slide.shapes.add_auto_shape(slides.ShapeType.RECTANGLE, 100, 100, 400, 100)
    shape.text_frame.text = "Created inside a Docker container"
    presentation.save("output.pptx", slides.export.SaveFormat.PPTX)
    presentation.save("output.pdf", slides.export.SaveFormat.PDF)

Compilar y ejecutar:

docker build -t aspose-slides-python .
docker run --rm aspose-slides-python

Por qué la imagen base es Debian 11

La rueda aspose.slides incluye un runtime .NET Core 3.1, y ese runtime es anterior a las versiones de biblioteca que incluyen las versiones actuales de Debian. En Debian 12 y 13 el contenedor se construye correctamente pero falla en la primera llamada a Presentation():

Process terminated. Couldn't find a valid ICU package installed on the system.

El mensaje es engañoso — ICU está instalado en esas imágenes, pero es ICU 72 o 76, y .NET Core 3.1 solo reconoce versiones mayores más antiguas. Debian 12 además incluye OpenSSL 3, lo que produce un segundo error:

No usable version of libssl was found

python:3.11-slim-bullseye es Debian 11, que proporciona ambas versiones que el runtime incluido espera:

Paquete Versión en Debian 11 Por qué es necesario
libgdiplus 6.0.4 Implementación GDI+ utilizada para renderizar formas, texto e imágenes
libicu67 67.1 Datos de globalización. Las versiones mayores más recientes no son reconocidas por .NET Core 3.1
libssl1.1 1.1.1w Criptografía. Preinstalado en Debian 11; ausente en Debian 12+
libfontconfig1 Descubrimiento de fuentes

libssl1.1 ya está presente en la imagen base, por lo que no es necesario incluirlo en apt-get install.

Si debe utilizar una imagen base más reciente, establezca DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1 para eludir el requisito de ICU. Esto desactiva el formato dependiente de la cultura y no resuelve el problema de OpenSSL, por lo que Debian 11 sigue siendo la opción más sencilla.

Fuentes

Las imágenes slim no contienen fuentes en absoluto. Sin al menos una fuente instalada, el texto se muestra como cajas vacías en la salida PDF, de imagen y HTML. fonts-dejavu-core es un pequeño punto de partida de propósito general.

Para que la presentación tenga la apariencia prevista, copie las fuentes que utiliza dentro de la imagen y apunte Aspose.Slides a ellas:

COPY fonts/ /usr/share/fonts/truetype/custom/
RUN fc-cache -f
import aspose.slides as slides

slides.FontsLoader.load_external_fonts(["/usr/share/fonts/truetype/custom/"])

Licencias dentro de un contenedor

No incorpore el archivo de licencia en la imagen — cualquier persona que descargue la imagen obtendrá la licencia. Montela en tiempo de ejecución en su lugar:

docker run --rm -v /path/on/host:/license aspose-slides-python
import aspose.slides as slides

license = slides.License()
license.set_license("/license/Aspose.Slides.Python.NET.lic")

Sin una licencia la biblioteca funciona en modo de evaluación, lo que añade una marca de agua y limita el número de diapositivas procesadas. Consulte Licencias para más detalles.

Memoria

Renderizar a PDF o imágenes consume más memoria que leer un archivo. Los contenedores con límites de memoria estrictos pueden ser finalizados por el OOM killer a mitad de una conversión, lo que generalmente se manifiesta como la desaparición del proceso sin una traza de error de Python. Si ocurre, aumente el límite de memoria del contenedor antes de investigar el código.