OfficeMath (Equation) Conversion to HTML with IMAGE Mode Fails on Alpine Linux

I am experiencing issues when converting DOCX files containing math equations (OfficeMath) to HTML using Aspose.Words 21.9 with JDK 16 inside an Alpine Linux Docker container (amazoncorretto:17-alpine3.18).

First noticed issue:
The problem occurs when using:

saveOptions.setOfficeMathOutputMode(HtmlOfficeMathOutputMode.IMAGE);
  • On Alpine Linux, this produces a NullPointerException:
java.lang.NullPointerException: Cannot invoke "com.aspose.words.internal.zzYfp.zzoN()" 
because "this.zzXQs" is null
	at com.aspose.words.zzXqZ.zzWqN(Unknown Source)
	at com.aspose.words.zzZOP.visitOfficeMathStart(Unknown Source)
	at com.aspose.words.OfficeMath.zzYMS(Unknown Source)
	at com.aspose.words.CompositeNode.acceptCore(Unknown Source)
  • On Windows, IMAGE mode works fine.

What I Have Tried:

  • Copied Windows fonts into the container:
Cambria.ttc
cambriab.ttf
cambriai.ttf
cambriaz.ttf
STIXTwoMath-Regular.otf
  • Placed in /app/fonts/
  • Also copied to /usr/share/fonts/truetype/microsoft/ and /usr/share/fonts/truetype/custom/
  • Installed packages:
fontconfig ttf-dejavu ttf-freefont fontforge texlive msttcorefonts-installer libc6-compat cairo libpng libjpeg giflib
  • Rebuilt font cache using fc-cache.
  • Configured Aspose.Words to use /app/fonts as a custom font folder in code.

Additional Observation:

  • Switching to MathML mode (HtmlOfficeMathOutputMode.MATH_ML) renders equations, but sometimes elements like matrix brackets (||) are missing on both Windows and Linux.

I am seeking advice on how to get IMAGE mode working properly on Alpine Linux

Word document:
test.docx (13.5 KB)

@harshani

Why HtmlOfficeMathOutputMode.IMAGE crashes on Alpine

HtmlOfficeMathOutputMode.IMAGE is rendered by Aspose.Words through its native library (libAspose.Words.Native.so).
When the native library cannot be loaded – for example because the container uses musl (Alpine) instead of glibc, or because required graphics/font libraries are missing – the internal renderer object is never created. The first call to it therefore throws the NPE you see:

java.lang.NullPointerException: Cannot invoke "com.aspose.words.internal.zzYfp.zzoN()" because "this.zzXQs" is null

In short, the native rendering engine cannot start on a plain Alpine image.


Two reliable ways to make the conversion work

:one: Use a glibc‑based container (recommended)

A glibc‑based Linux distribution already provides the libraries expected by the Aspose native code, so no extra compatibility work is required.

Dockerfile (Amazon Corretto 17 on a glibc base)

# Base image that uses glibc
FROM amazoncorretto:17

# Install the graphics and font libraries required by Aspose.Words
RUN yum -y install \
        fontconfig \
        freetype \
        libX11 \
        libXext \
        libXrender \
        libpng \
        libjpeg-turbo \
        giflib \
        cairo \
        harfbuzz && \
    yum clean all

# Application files
COPY target/your-app.jar /app/your-app.jar
COPY fonts/               /app/fonts/
COPY native/              /app/native/   # <-- libAspose.Words.Native.so

WORKDIR /app

# Make the native library visible to the JVM
ENV LD_LIBRARY_PATH=/app/native

ENTRYPOINT ["java","-jar","your-app.jar"]

Java code (no change needed)

// Register the folder that contains the fonts you need
FontSettings.getDefaultInstance().setFontsFolder("/app/fonts", true);

Document doc = new Document("test.docx");
HtmlSaveOptions opts = HtmlSaveOptions.create();
opts.setOfficeMathOutputMode(HtmlOfficeMathOutputMode.IMAGE);
doc.save("out.html", opts);

Result – The same code that works on Windows now works inside the container because the native library loads successfully and all graphics dependencies are satisfied.


:two: Stay on Alpine and add glibc + the required native libraries

If image size is a concern and you must keep Alpine, you need to provide the glibc compatibility layer and the graphics/font libraries that the native renderer expects.

Step‑by‑step

  1. Install glibc (Aspose native library is built for glibc).

    apk add --no-cache ca-certificates wget
    wget -q -O /etc/apk/keys/sgerrand.rsa.pub https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub
    wget https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.34-r0/glibc-2.34-r0.apk
    apk add glibc-2.34-r0.apk
    
  2. Install the graphics and font libraries required by the native renderer.

    apk add --no-cache \
        fontconfig \
        freetype \
        harfbuzz \
        libpng \
        libjpeg-turbo \
        giflib \
        cairo \
        libstdc++ \
        libgcc
    
  3. Make the native library reachable.

    mkdir -p /app/native
    cp /path/to/libAspose.Words.Native.so /app/native/
    export LD_LIBRARY_PATH=/app/native:$LD_LIBRARY_PATH   # or set -Djava.library.path
    
  4. Run the same Java code as shown in the glibc example.

Note: Even with glibc added, some low‑level X11 calls may still fail on Alpine because the underlying musl system lacks certain symbols. In practice the glibc‑based image is more stable, but the Alpine approach works for many scenarios.


If the native renderer cannot be used at all

When you cannot get the native library to load, fall back to MathML and render the equations yourself (e.g., with MathJax + headless Chromium).

HtmlSaveOptions opts = HtmlSaveOptions.create();
opts.setOfficeMathOutputMode(HtmlOfficeMathOutputMode.MATH_ML);
doc.save("out.html", opts);

// Afterwards:
// 1. Extract <math>…</math> blocks from the HTML.
// 2. Render each block with MathJax (Node.js + Puppeteer) to PNG/SVG.
// 3. Replace the <math> element with an <img> that points to the generated image.

This completely avoids the native rendering path, at the cost of an extra post‑processing step.


Quick checklist for a working Alpine‑based setup

Item Action
glibc Install via sgerrand/alpine-pkg-glibc.
Graphics / font libs apk add fontconfig freetype harfbuzz libpng libjpeg-turbo giflib cairo libstdc++ libgcc.
Native library Copy libAspose.Words.Native.so to a directory and add it to LD_LIBRARY_PATH (or use -Djava.library.path).
Fonts Place required fonts (e.g., Cambria, STIXTwoMath) in a folder and register with FontSettings.
Test Run a tiny program that only loads the native library: System.loadLibrary("Aspose.Words.Native"); – it should complete without exception.
If test fails Switch to a glibc‑based container; the native library is not compatible with musl.

Bottom line

The NullPointerException is caused by the Aspose.Words native rendering engine being unable to start on Alpine (musl + missing graphics libraries).

  • The most reliable fix is to run the conversion in a glibc‑based container.
  • If you must stay on Alpine, add glibc and the required graphics/font packages, and ensure the native .so is on the library path.
  • When native rendering is impossible, use HtmlOfficeMathOutputMode.MATH_ML and render the MathML yourself.

Feel free to share your Dockerfile or a minimal reproducer if you encounter further errors – I can help fine‑tune the environment.

@harshani The problem is not reproducible with the latest 25.10 version of Aspose.Words for Java. So please try using the latest version and let us know if the problem still persists on your side.

After I tried with the latest version (25.10), the NullPointerException issue was resolved. However, with my test file, I noticed an issue related to the matrix. When I tested the same file using Amazon Linux 2023, it worked fine. Could you please guide me on what I should do when using Alpine?

//Issue

//Success

I have tried installing these one as well, but result was the same.

RUN apk update \
    && apk add --no-cache shadow curl unzip bash \
    && apk add --no-cache fontconfig ttf-dejavu ttf-freefont \
    && apk add --no-cache freetype harfbuzz libpng libjpeg-turbo giflib cairo libstdc++ libgcc \
    && fc-cache -f -v \
    && rm -rf /var/cache/apk/*

@harshani By default MS Word uses Cambria Math font in Office Math Equations. The fonts are required to build accurate document layout. If Aspose.Words cannot find the fonts used in the document the fonts are substituted . This might lead into the layout differences due to differences in fonts metrics. You can implement IWarningCallback to get a notification when font substitution is performed.
The following articles can be useful for you:
https://docs.aspose.com/words/java/specify-truetype-fonts-location/
https://docs.aspose.com/words/java/install-truetype-fonts-on-linux/