在服务器核心 2019ltsc 容器映像中添加字体

ste*_*ler 14 windows containers docker

我们有一个应用程序 (GrapeCity ActiveReports) 生成 pdf 报告,该报告在基于下图构建的容器内运行: microsoft/dotnet-framework:4.7.2-sdk

此图像基于 2019ltsc 版本,这是问题所在。 pdf 生成应用程序(尝试)为这些报告使用 Arial 字体,但在 Windows 字体目录中找不到。

根据这篇 Microsoft 博客(在容器改进部分),2019ltsc 版本删除了Arial之外的所有字体,并且显然阻止了安装其他字体。 https://blogs.windows.com/windowsexperience/2018/05/29/annoucing-windows-server-2019-insider-preview-build-17677/

以交互方式启动未修改的 SDK 图像并浏览至C:\Windows\Fonts仅显示当前lucon.ttf字体,不显示其他任何内容。我们还尝试了 Microsoft 的此文档中概述的安装字体方法,但没有进行任何更改。字体本身安装良好,但生成程序无法使用它。https://docs.microsoft.com/en-us/azure/app-service/app-service-web-tutorial-windows-containers-custom-fonts

运行时返回以下异常:

System.InvalidOperationException: Cannot read the file for font: Arial
Run Code Online (Sandbox Code Playgroud)

更新:收到 MS 支持的回复,目前看来可能没有解决方案。

经过几天的研究,关于为什么基于 mcr.microsoft.com.windows/servercore:ltsc2019 的图像中唯一的字体是 lucon.ttf,我没有取得太大进展,而且似乎没有公开的方法可以向 Windows Server 添加其他字体2019 年核心形象。我根据情况发邮件给windows server 2019产品团队咨询这个问题。但是,请理解,由于权限限制,我不能保证我可以得到产品团队的反馈。我会继续研究和监控产品团队,如果有任何进展,我会尽快回复您。

Ton*_*ony 8

当托管 ASP.Net 应用程序呈现一些图像和文档时,我遇到了同样的问题,我设法通过两个步骤解决:

我在 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"]
Run Code Online (Sandbox Code Playgroud)

这是run.bat包含以下内容的自定义入口点文件:

C:\FontReg.exe
C:\ServiceMonitor.exe w3svc
Run Code Online (Sandbox Code Playgroud)


小智 7

方法1(多阶段构建)

最好将字体从mcr.microsoft.com/windows映像复制到mcr.microsoft.com/windows/servercore或您想要使用的任何基础映像。由于它附带了大多数字体并且它也支持大多数亚洲字体。

以下三件事需要从 mcr.microsoft.com/windows 图像复制。

  1. 来自C:\Windows\Fonts 的字体(我们需要在复制时排除 lucon.ttf,因为默认情况下它会出现在大多数 Windows 容器映像中)
  2. 导出“HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts”注册表
  3. 导出“HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontLink\SystemLink”注册表(对于某些情况,我们还需要 FontLink,因此最好包含此注册表)

我使用多级 dockerfile 来复制它们。

# 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
Run Code Online (Sandbox Code Playgroud)

如果您复制上述所有字体,它将为您的最终 docker 映像添加超过 300MB 的大小。

方法二

如果您不想在管道中使用多阶段构建或只需要复制一些选定的字体,您可以继续使用其他答案中提到的以下方法。最重要的是仔细注册字体和fontLInk

  1. 从本地计算机 (C:\Windows\Fonts) 或 mcr.microsoft.com/windows 容器映像复制所需的字体(您可以在运行容器时使用卷绑定来复制字体)
  2. 注册复制的字体。
  3. 为复制的字体注册 FontLink。

默认情况下存在的 lucon.ttf 不支持亚洲语言。在下面的示例中,我将添加对中文、韩文和日文字体的支持。

我会将支持大多数中文、韩文和日文字符的 malgun.ttf、msgothic.ttc 和 simsun.ttc 字体复制到 docker 构建上下文中的 Fonts 文件夹中。

我将为 GenericMonospace fontStyle 添加 FontLink。如果您想支持其他样式(例如 Arial 等),请相应地更改此...

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
Run Code Online (Sandbox Code Playgroud)


小智 6

通过按照之前的建议安装它,我能够让它在 ltsc2019 中工作:

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
Run Code Online (Sandbox Code Playgroud)

然后打电话

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

在使用字体之前。在构建图像时调用 AddFontResource 没有帮助。

当我们从 powershell 启动我们的应用程序时,我们从 C:\Users\ContainerAdministrator\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1 调用 LoadFonts.ps1

RUN echo "C:\tools\LoadFonts.ps1" | Out-File -FilePath $profile
Run Code Online (Sandbox Code Playgroud)

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
    }
}
Run Code Online (Sandbox Code Playgroud)


cod*_*eal 6

我对“mcr.microsoft.com/dotnet/framework/aspnet:4.8-windowsservercore-ltsc2019”有同样的问题。字体已安装,但应用程序无法使用它们。

我通过将字体复制到“c:\windows\fonts”文件夹,然后调用“AddFontResource”,然后在“HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts”中添加一个注册表项来安装字体。但没有运气。

但是后来我运行了以下命令以查看字体是否已写入注册表:

Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts"
Run Code Online (Sandbox Code Playgroud)

并注意到缺少 Arial 字体。所以我通过shell运行了以下命令:

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

然后重新运行以下命令以确认未列出字体 Arial:

Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts"
Run Code Online (Sandbox Code Playgroud)

之后,当我运行我的应用程序时,它能够加载 Arial 字体。


小智 1

我也无法让它在 Windows Server Core 2019 映像上运行。我可以使用以下命令确认添加字体在 1803 图像中是否有效。

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 ;
Run Code Online (Sandbox Code Playgroud)

通过 shell 对象通过 powershell 执行此操作不起作用。