Java 11没有字体吗?

4

我正在使用Java 11 Corretto + Spring Boot与Apache POI,但在AWS Lambda上使用时遇到问题。如果我以“正常”的API运行,它可以正常工作,但是在AWS Lambda中运行则失败。

try (ByteArrayOutputStream out = new ByteArrayOutputStream(); SXSSFWorkbook workbook = new SXSSFWorkbook(1000)) {
    SXSSFSheet sheet = workbook.createSheet("test"); //error here!!
    } ...

由:java.lang.Error: 可能是致命错误:未找到物理字体。 在 java.desktop/sun.font.SunFontManager.lambda$getDefaultPhysicalFont$0(Unknown Source) 中发生。在 java.base/java.util.Optional.orElseThrow(Unknown Source) 中使用默认选项。在 java.desktop/sun.font.SunFontManager.getDefaultPhysicalFont(Unknown Source) 中获取默认字体。在 java.desktop/sun.font.CompositeFont.doDeferredInitialisation(Unknown Source) 中执行延迟初始化。在 java.desktop/sun.font.CompositeFont.getSlotFont(Unknown Source) 中获取字体插槽。在 java.desktop/sun.font.CompositeGlyphMapper.initMapper(Unknown Source) 中初始化复合字形映射器。在 java.desktop/sun.font.CompositeGlyphMapper.(Unknown Source) 中创建复合字形映射器。在 java.desktop/sun.font.CompositeFont.getMapper(Unknown Source) 中获取字形映射器。在 java.desktop/sun.font.CompositeFont.canDisplay(Unknown Source) 中检查是否可以显示。在 java.desktop/java.awt.Font.canDisplayUpTo(Unknown Source) 中检查字符是否可显示。在 java.desktop/java.awt.font.TextLayout.singleFont(Unknown Source) 中搜索单个字体。在 java.desktop/java.awt.font.TextLayout.(Unknown Source) 中创建文本布局。在 org.apache.poi.ss.util.SheetUtil.getDefaultCharWidth(SheetUtil.java:285) 中获取默认字符宽度。在 org.apache.poi.xssf.streaming.AutoSizeColumnTracker.(AutoSizeColumnTracker.java:117) 中创建自动调整列宽跟踪器。在 org.apache.poi.xssf.streaming.SXSSFSheet.(SXSSFSheet.java:84) 中创建 SXSSF 工作表。在 org.apache.poi.xssf.streaming.SXSSFWorkbook.createAndRegisterSXSSFSheet(SXSSFWorkbook.java:705) 中创建和注册 SXSSF 工作表。在 org.apache.poi.xssf.streaming.SXSSFWorkbook.createSheet(SXSSFWorkbook.java:724) 中创建工作表。
我试图修复字体问题,但不知道如何继续。
@PostConstruct
public void loadFonts() {
    URL configURL = getClass().getClassLoader().getResource("fontconfig.properties");
    String path = configURL != null ? configURL.getPath() : null;
    Properties props = System.getProperties();
    LOGGER.info("Loading font config file: {}", path);
    props.put("sun.awt.fontconfig", path);

    String[] fonts;
    try {
        GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames();
    } catch (Throwable ex) {
        LOGGER.warn("Reloading Fonts");
    }
    try {
        fonts = GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames();

        for (String font : fonts) {
            LOGGER.info("Available Font: {}", font);
        }
    } catch (Throwable ex) {
        LOGGER.error("Could not load Fonts");
    }
}

配置文件:

version=1
sequence.allfonts=default

在AWS Lambda上运行时,它会将一些字体输出到日志中,因此我不明白为什么会出现这个错误:
2022-05-31 16:00:14  INFO  Starting Lambda Container Handler
2022-05-31 16:00:18  INFO  Loading font config file: /var/task/fontconfig.properties
2022-05-31 16:00:18  INFO  Available Font: Dialog
2022-05-31 16:00:18  INFO  Available Font: DialogInput
2022-05-31 16:00:18  INFO  Available Font: Monospaced
2022-05-31 16:00:18  INFO  Available Font: SansSerif
2022-05-31 16:00:18  INFO  Available Font: Serif

有什么办法可以添加物理字体?为什么POI不能使用可用的字体来输出日志?

编辑: 我也尝试了以无界面方式运行,但是我得到了相同的错误信息:

`props.setProperty("java.awt.headless", "true");`

当在AWS Lambda上使用时,它是在服务器上运行的吗?大多数服务器都是“无头”的,也就是说它们根本没有GUI。我猜这可能意味着没有字体。您可能需要在Unix设备上搜索如何安装Java字体包。 - markspace
我刚刚完成了AWS Lambda的教程。它绝对是一个服务器,只是被市场营销称为“无服务器”。(从未阅读过市场营销废话。)如果您无法安装软件包,则我认为您不能将其用于此功能。请获取一个真正的服务器。 - markspace
2
总会有一个服务器。"无服务器"只是意味着您不必管理服务器。如果您无法通过将字体捆绑在Lambda部署包中来修复此问题,那么您可能需要考虑将Lambda函数部署为Docker容器,这样您将拥有更多对运行时环境的控制。 - Mark B
1个回答

4

字体捆绑

有没有想法如何添加物理字体?

自Java 11起,来自Oracle的Oracle JDK产品停止捆绑字体

OpenJDK项目至少在最近的版本中不捆绑字体。

Corretto JDK 来自亚马逊产品是基于OpenJDK代码库的。根据您的报告,显然他们不捆绑字体。

你必须选择:

  • 依赖主机操作系统提供的字体。
  • 将字体捆绑到您的Java应用程序中。注意研究许可证条款。一些字体允许这样的绑定,而一些则不允许。有些需要付费,有些则不需要。有些需要承认,有些则不需要。
  • 从包含字体的供应商那里获取JDK。

我知道至少有一个这样的供应商:Azul Systems与其商业产品Azul Platform Core捆绑字体。

可能还有其他我不知道的供应商。许多供应商提供JDK二进制文件和安装程序。这些供应商包括Adoptium、SAP、BellSoft、Microsoft、Azul Systems、Amazon、Oracle、Red Hat/IBM、Pivotal等等。

物理字体与逻辑字体

为什么POI不能使用输出到日志中的可用字体?

您在日志中列出的字体是逻辑字体,而不是物理字体。这个区别在Font类的Javadoc中有明确的文档说明。

要使用逻辑字体名称,必须有一些支持的物理字体。如果你的应用程序、JDK或主机操作系统中不存在字体,则逻辑字体无法工作。

AWS Lambda的字体

关于在AWS Lambda中使字体可用,也许这两个页面可能会有所帮助。(感谢jarmod提供的链接。)

基本思路是在您的包中创建一个名为 /fonts 的文件夹,其中包含一个 fonts.conf 文件,里面有 XML 配置元素。将捆绑的字体文件与该配置文件放在一起。

许可条款

请注意一些字体是商业字体,其许可证需要支付费用。在捆绑/部署字体时,请确保您符合其许可证条款。


谢谢回复,但是您有什么想法可以让我在Java Lambda中使用物理字体吗? - daph111

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接