20

We have an app (GrapeCity ActiveReports) that generates pdf reports running inside a container built on the following image: microsoft/dotnet-framework:4.7.2-sdk

This image is based on the 2019ltsc release, which is where the issue comes in. The pdf generating app is (attempting) to use the Arial font for these reports, but it is not being found in the Windows font directory.

Per this Microsoft blog (under the Container Improvements section), the 2019ltsc release stripped out all fonts except Arial, and it apparently prevents installing additional fonts. https://blogs.windows.com/windowsexperience/2018/05/29/announcing-windows-server-2019-insider-preview-build-17677/

Launching the un-modified SDK image interactively and browsing to C:\Windows\Fonts only shows the lucon.ttf font present and nothing else. We have also attempted the install fonts method outlined in this doc from Microsoft with no change. The font itself installs fine but the generating program fails to use it. https://learn.microsoft.com/en-us/azure/app-service/app-service-web-tutorial-windows-containers-custom-fonts

When run it returns the following exception:

System.InvalidOperationException: Cannot read the file for font: Arial

UPDATE: Recieved a reply from MS support, looks like there is probably no resolution at this time.

After a few days research, I haven’t got much progress about why the only font in mcr.microsoft.com.windows/servercore:ltsc2019 based image is lucon.ttf, and seems there’s no published method to add additional fonts to windows server core 2019 image. Based on the situation, I have sent emails to windows server 2019 product team to consult this issue. However, please understand, due to permission limit, I couldn’t guarantee I can get feedback from Product Team. I will keep researching and monitor on the product team, if I get any progress, I will get back to you as soon as possible.

stevenmiller
  • 383
  • 1
  • 4
  • 12
  • Hi, did you get any further with this problem? I've run into the same issue where I can get a successful build in 1709 but not ltsc2019. I've looked at the answers below but wondered if you managed to solve it a particular way or are still having issues? – Patrick Magee Jan 13 '20 at 12:30
  • 1
    @PatrickMagee I did not, we ended up switching to linux containers pretty shortly after. I did come across this in the Azure github repo, it specifies ltsc2019: https://github.com/Azure/app-service-windows-containers/tree/master/Recipes/Custom-fonts – stevenmiller Jan 14 '20 at 14:23
  • In case we only need the fonts in the container see: [link](https://stackoverflow.com/a/69191895/5770014) – minus one Sep 15 '21 at 11:06

7 Answers7

9

I was able to get it to work in ltsc2019 by installing it like suggested before:

COPY calibri.ttf c:/windows/fonts/calibri.TTF
RUN powershell.exe -NoProfile -Command New-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts' -Name 'Calibri (TrueType)' -PropertyType String -Value calibri.ttf

and then calling

[DllImport("gdi32.dll")] static extern int AddFontResource(string lpFilename);

before using the font. Calling AddFontResource while building the image didn't help.

As we start our application from powershell we call the LoadFonts.ps1 from C:\Users\ContainerAdministrator\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1

RUN echo "C:\tools\LoadFonts.ps1" | Out-File -FilePath $profile

LoadFonts.ps1:

$fontCSharpCode = @'
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Runtime.InteropServices;
namespace FontResource
{
    public class AddRemoveFonts
    {
        [DllImport("gdi32.dll")]
        static extern int AddFontResource(string lpFilename);
        public static int AddFont(string fontFilePath) {
            try 
            {
                return AddFontResource(fontFilePath);
            }
            catch
            {
                return 0;
            }
        }
    }
}
'@

Add-Type $fontCSharpCode

foreach($font in $(gci C:\Windows\Fonts))
{
    if(!$font.FullName.EndsWith("lucon.ttf"))
    {
        Write-Output "Loading $($font.FullName)"
        [FontResource.AddRemoveFonts]::AddFont($font.FullName) | Out-Null
    }
}
Daniel Romero
  • 287
  • 2
  • 5
  • This answer worked for windows server ltsc2019, I load each using font at the beginning of my program startup: ``` public static void Main(string[] args) { AddFont("arial.ttf"); AddFont("arialbd.ttf"); AddFont("tahoma.ttf"); AddFont("tahomabd.ttf"); ..... ``` – Mohammad Zatkhahi Feb 22 '23 at 11:47
8

I got same problem when hosted ASP.Net app which rendered some images and docs and I managed to solve with 2 steps:

I used the following in Dockerfile

FROM mcr.microsoft.com/windows/servercore/iis:windowsservercore-ltsc2019

...

# Take font from host machine, exclude lucon.ttf, as it exists in image already
COPY Fonts/* /Windows/Fonts/

# Take FontReg.exe FROM http://code.kliu.org/misc/fontreg/, extract proper version
COPY FontReg.exe /    

# Described below
COPY run.bat /

ENTRYPOINT ["cmd.exe", "/C run.bat"]

And here is the custom entry point run.bat file with the following content:

C:\FontReg.exe
C:\ServiceMonitor.exe w3svc
Tony
  • 7,345
  • 3
  • 26
  • 34
  • I can confirm this solution currently works. The FontReg.exe does some magic to make the fonts register correctly. All I did was copy the fonts I needed from my local `C:\Windows\Fonts` folder. – Gerard Wilkinson Nov 23 '20 at 09:30
  • Confirming this approach worked for me. – Gareth Feb 01 '22 at 03:10
  • This approach is the only one that worked for me on aspnet:4.8-windowsservercore-ltsc2019. I combined it with Nithesh's method 1 of getting fonts from mcr.microsoft.com/windows:1809 – R44 Mar 08 '22 at 21:40
  • Confirm this works for me in servercore:ltsc2019. Thank you! – TrojanName Feb 08 '23 at 17:20
7

I was having same issue with "mcr.microsoft.com/dotnet/framework/aspnet:4.8-windowsservercore-ltsc2019". Fonts got installed but the application failed to use them.

I installed the fonts by copying them to "c:\windows\fonts" folder and then calling "AddFontResource" and then also adding a registry entry to "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts". But no luck.

But then I ran the below command to see if the fonts were written to the registry:

Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts"

and noticed that the Arial font was missing. So I ran the below command through the shell:

Set-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts" -name "Arial (TrueType)" -value "arial.ttf" -type STRING

And then re ran the below command to confirm the font Arial was not listed:

Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts"

After that when I ran my application it was able to load the Arial font.

code2real
  • 71
  • 1
  • 2
6

Method 1 (multi-stage build)

It's better to copy fonts from mcr.microsoft.com/windows image to mcr.microsoft.com/windows/servercore or whichever base image you would like to use. Since it is shipped with most of the fonts & it supports most of the asian fonts as well.

Below three things need to be copied from mcr.microsoft.com/windows image.

  1. Fonts from C:\Windows\Fonts (we need to exclude lucon.ttf while copying since it will be present in most of the windows container images by default)
  2. Export 'HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts' registry
  3. Export 'HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontLink\SystemLink' registry (for some scenarios we need FontLink's as well, so its better to include this registry)

I used multistage dockerfile to copy those.

# stage-1
FROM mcr.microsoft.com/windows:1809 AS fullWindows

# Copy below stuff
RUN powershell -NoProfile -Command "\
Copy-Item -Path C:\Windows\Fonts -Exclude lucon.ttf -Destination c:\Fonts -Recurse; \
New-Item -ItemType Directory -Force -Path c:\registries; \
reg export 'HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts' c:\registries\FontsReg.reg ; \
reg export 'HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontLink\SystemLink' c:\registries\FontLink.reg ; \

# stage-2 (final build)
FROM mcr.microsoft.com/windows/servercore:1809

# Take font from above image, exclude lucon.ttf, as it exists in image already
COPY --from=fullWindows /Fonts/ /Windows/Fonts/

COPY --from=fullWindows /registries/ ./registries/

# Import the font registries.
RUN powershell -NoProfile -Command "\
reg import C:\registries\FontsReg.reg; \
reg import C:\registries\FontLink.reg; \
"

# Copy your code
COPY your-code ./your-code/

ENTRYPOINT C:/your-code/your-app.exe

If you copy all fonts as mentioned above it will add more than 300MB to your final docker image.

Method 2

If you prefer not to use multi-stage builds in your pipeline or need to copy only a few selected fonts, you can go ahead with the approach below as mentioned by other answers. Most importantly register the font & fontLInk carefully.

  1. Copy required fonts either from your local machine(C:\Windows\Fonts) or from mcr.microsoft.com/windows container image(you can use volume binding while running the container to copy fonts)
  2. Register the copied fonts.
  3. Register the FontLink for the copied fonts.

lucon.ttf which is present by default does not support asian languages. In the below example i would add support for chinese, korean & japanese fonts.

I will copy malgun.ttf, msgothic.ttc & simsun.ttc fonts which support most of the chinese, korean & japanese characters to the Fonts folder in the docker build context.

I will add FontLink for GenericMonospace fontStyle. Change this accordingly if you want to support other styles such as Arial etc...

FROM mcr.microsoft.com/windows/servercore:1809

# Copy fonts 
COPY Fonts ./Windows/Fonts

# Register the Fonts.
RUN powershell.exe -NoProfile -Command New-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts' -Name 'SimSun "&" NSimSun (TrueType)' -PropertyType String -Value simsun.ttc
RUN powershell.exe -NoProfile -Command New-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts' -Name 'Malgun Gothic (TrueType)' -PropertyType String -Value malgun.ttf
RUN powershell.exe -NoProfile -Command New-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts' -Name 'MS Gothic "&" MS UI Gothic "&" MS PGothic (TrueType)' -PropertyType String -Value msgothic.ttc

# Register the FontLink
RUN powershell.exe -NoProfile -Command New-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontLink\SystemLink' -Name 'SimSun' -PropertyType MultiString -Value ('MSGOTHIC.TTC,MS UI Gothic','SIMSUN.TTC,SimSun','MALGUN.TTF,Malgun Gothic')

# Copy your code
COPY your-code ./your-code/

ENTRYPOINT C:/your-code/your-app.exe
  • I like Method #1 and I can confirm it works on ltsc2022. The issue I have with the suggested solution from MS is that I can't run the powershell script after starting the container since I'm running my container as AWS ECS Fargate service with no VM to manage. The only issue with Method #1 is it takes FOREVER to build since the full windows server image is huge. https://techcommunity.microsoft.com/t5/itops-talk-blog/adding-optional-font-packages-to-windows-containers/ba-p/3559761 – Kevin Aung Feb 16 '23 at 00:03
  • Just to add to my comment above. I'm using this to support Telerik Reporting with custom fonts. The HTML viewer will render the fonts correctly but the PDF export will throw `System.OverflowException: Arithmetic operation resulted in an overflow.` exception. Haven't figured out why but the export works if fonts aren't installed. So this works 90% for me. – Kevin Aung Mar 01 '23 at 19:08
1

I wasn't able to get it working on a windows server core 2019 image either. I can confirm adding fonts does work in an 1803 image by using the following.

COPY MICRFONT.TTF c:/windows/fonts/MICRFONT.TTF
RUN powershell.exe -NoProfile -Command New-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts' -Name 'MICRFONT (TrueType)' -PropertyType String -Value micrfont.ttf ;

Doing it through powershell via a shell object did not work.

Tim
  • 11
  • 1
0

can confirm that the following worked for me

COPY arial.ttf c:\windows\fonts
COPY arialbd.ttf c:\windows\fonts

a unit test which previously failed due to lack of arial succeeded after.

additionally running this script inside the container showed arial

   [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
   (New-Object System.Drawing.Text.InstalledFontCollection).Families
Tim
  • 7,401
  • 13
  • 61
  • 102
0

I found that installing and building an application that needed the fonts within the same RUN step in the dockerfile fixed the problem. I don't fully understand why, but when I had these steps in multiple layers, it did not detect the fonts.

Previous base images worked without needing to build the dockerfile using a single RUN such as 1709, 1803, but for the 2019ltc base image, the application was failing.

If others have issues such as this, I recommend attempting to run several steps under one RUN step in the dockerfile, when strange cases like this occur that do not seem to be application specific and are showing signs of a platform issue.

Patrick Magee
  • 2,951
  • 3
  • 33
  • 50