Getting Font Error on Linux Alpine when Using FontFolders and Calibri Font

When using FontFolders and the Calibri font is in one of those folders we are getting a error on save. Using any pptx originally created in PowerPoint.

Font ‘?’ cannot be found.
at System.Drawing.FontFamily.GetCellAscent(FontStyle style)
at .(Font , Single& , Single& , Single& )
at  .(String ,  ,  , Boolean , Int32 , Single& , Single& )
at  .( ,  ,  ,  , Int32 , Single& , Single& , Single&  )
at  .() at  …ctor(TextFrame , Single , Single , IBaseSlide ,  )
at Aspose.Slides.TextFrame.(Single , Single , IShapeStyle ,  )
at Aspose.Slides.TextFrame.(ShapeFrame& , RectangleF& , Single& , Single& , Single& , Single& ,  )
at  .(IAutoShape ,  ,  ,  )
at  .(IGroupShape ,  ,  ,  )
at  .(IBaseSlide ,  ,  )
at  .(IMasterSlide , Boolean )
at  .( , IMasterSlide , Boolean ,  )
at  .(IPresentation , Stream , PresentationTypeEx , IPptxOptions , InterruptionToken )
at Aspose.Slides.Presentation.(Stream , PresentationTypeEx , IPptxOptions )
at Aspose.Slides.Presentation.Save(Stream stream, SaveFormat format, ISaveOptions options)

If Calibri is not in the folder there is no error.
If Ubuntu is used instead of Alpine there is no error.
No error from Aspose.Words or Aspose.Cells with a similar test.
Application is a ASP.NET site using .NET Core v3.1.

Load code
var opts = new Aspose.Slides.LoadOptions();

        opts.DocumentLevelFontSources.FontFolders = new string[] { "{local folder}" };

        return new Aspose.Slides.Presentation(
            documentStream,
            opts);

Save code
using var ms = new MemoryStream();
document.Save(ms, SaveFormat.Pptx);

Docker
FROM mcr.microsoft.com/dotnet/aspnet:3.1-alpine
WORKDIR /app
COPY Product .

#default environment variables
ENV Logging__LogLevel__Default=Warning
ENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=false

RUN apk update
RUN apk --no-cache add icu-libs msttcorefonts-installer fontconfig harfbuzz-dev tzdata &&
update-ms-fonts &&
fc-cache -f
RUN apk --no-cache add libgdiplus --update-cache --repository Index of /alpine/edge/testing/ --allow-untrusted

ENTRYPOINT [“dotnet”, “Product.dll”]

@bruceb6,
Thank you for the issue description. Could you please specify the version of Aspose.Slides you used?

I’ve tried with 21.8.0 and 21.11.0.
I also just tried with a .NET 6 image and application with the same result.

Thanks

@bruceb6,
Thank you for the additional information.

I logged the issue with ID SLIDESNET-42911 in our tracking system. Our development team will investigate this case. We will inform you of any progress.

@bruceb6,
Our developers have investigated the issue occurring in Docker Alpine when using external fonts via the property options.DocumentLevelFontSources.FontFolders. This issue is reproducible with various fonts on Alpine, not just for Calibri. This problem does not occur on Ubuntu or Debian, likely due to the use of different versions of the libgdiplus libraries.

The issue is reproducible outside of Aspose.Slides with a simple example:

PrivateFontCollection fontCollection = new PrivateFontCollection();
fontCollection.AddFontFile("FontFolder/calibri.ttf");
var fontFamily = fontCollection.Families[0];
float cellAscent = fontFamily.GetCellAscent(FontStyle.Regular); // Exception occurs here

This exception does not occur for fonts that were installed in the system. Retrieving font metrics through FontFamily objects obtained from the FontFamily.Families collections or (new InstalledFontCollection()).Families works correctly without exceptions. This suggests that the issue may be related to the handling of fonts added via PrivateFontCollection in the Alpine environment.

After conducting research, we found two solutions:

  1. Installing the required fonts into the system, bypassing the font loading mechanism through FontsLoader.LoadExternalFonts or by specifying the external font source via DocumentLevelFontSources.FontFolders. Installing fonts directly into system directories avoids exceptions when working with them.
    Example Docker script snippet for installing fonts:
    # Copy the necessary fonts
    COPY /DockerSlidesAlpine/FontFolder /usr/share/fonts/custom/
    # Rebuild the font cache
    RUN fc-cache -f -v
    # Verify font installation
    RUN fc-list
  1. Use the latest version of libgdiplus built from source in Docker Alpine. Updating libgdiplus resolves the issue when using fonts loaded through PrivateFontCollection.
    Example Docker commands for building libgdiplus from source:
    # Install dependencies and tools for building libgdiplus
    RUN apk update && apk add --no-cache \
    icu-libs \
    fontconfig \
    harfbuzz \
    autoconf \
    automake \
    libtool \
    pkgconfig \
    git \
    build-base \
    cairo-dev \
    fontconfig-dev \
    freetype-dev \
    giflib-dev \
    glib-dev \
    icu-dev \
    libexif-dev \
    libjpeg-turbo-dev \
    libpng-dev \
    tiff-dev \
    libwebp-dev \
    && rm -rf /var/cache/apk/*
    #Clone and build the latest libgdiplus from GitHub
    RUN git clone https://github.com/mono/libgdiplus.git /tmp/libgdiplus \
    && cd /tmp/libgdiplus \
    && ./autogen.sh \
    && make \
    && make install \
    && rm -rf /tmp/libgdiplus

This approach allows the proper use of external font loading mechanisms via FontsLoader.LoadExternalFonts or DocumentLevelFontSources.FontFolders, resolving the exception.