java - 如何配置简单的 Java fontconfig.properties 文件以在 Linux 上使用

标签 java fonts openjdk-11

我在自定义 Linux 硬件上使用自定义 Java 11 运行时,Java 运行时不是我自己构建的。
但是我有一个问题,我的应用程序需要访问字体并且运行时没有配置任何字体,所以我得到了这个堆栈跟踪

Exception in thread "main" java.lang.InternalError: java.lang.reflect.InvocationTargetException
        at java.desktop/sun.font.FontManagerFactory$1.run(FontManagerFactory.java:86)
        at java.base/java.security.AccessController.doPrivileged(Native Method)
        at java.desktop/sun.font.FontManagerFactory.getInstance(FontManagerFactory.java:74)
        at java.desktop/java.awt.Font.getFont2D(Font.java:497)
        at java.desktop/java.awt.Font.getFamily(Font.java:1410)
        at java.desktop/java.awt.Font.getFamily_NoClientCode(Font.java:1384)
        at java.desktop/java.awt.Font.getFamily(Font.java:1376)
        at java.desktop/java.awt.Font.toString(Font.java:1869)
        at java.base/java.lang.String.valueOf(String.java:2951)
        at java.base/java.io.PrintStream.println(PrintStream.java:897)
        at Fonts.main(Fonts.java:7)
Caused by: java.lang.reflect.InvocationTargetException
        at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
        at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
        at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:490)
        at java.desktop/sun.font.FontManagerFactory$1.run(FontManagerFactory.java:84)
        ... 10 more
Caused by: java.lang.NullPointerException
        at java.desktop/sun.awt.FontConfiguration.getVersion(FontConfiguration.java:1262)
        at java.desktop/sun.awt.FontConfiguration.readFontConfigFile(FontConfiguration.java:225)
        at java.desktop/sun.awt.FontConfiguration.init(FontConfiguration.java:107)
        at java.desktop/sun.awt.X11FontManager.createFontConfiguration(X11FontManager.java:719)
        at java.desktop/sun.font.SunFontManager$2.run(SunFontManager.java:367)
        at java.base/java.security.AccessController.doPrivileged(Native Method)
        at java.desktop/sun.font.SunFontManager.<init>(SunFontManager.java:312)
        at java.desktop/sun.awt.FcFontManager.<init>(FcFontManager.java:35)
        at java.desktop/sun.awt.X11FontManager.<init>(X11FontManager.java:56) 

我可以提供一些字体,并且我已经确定我需要创建一个 fontconfig.properties 并将 i 放入 Java 运行时 lib 文件夹,但我很难理解我需要放入 fontconfig.properties 的内容。

有人可以给我一个示例,说明如何在 linux 上的 fontconfig.properties 中指定一组最小字体以防止发生异常。

更具体地说,我有一组 truetype 字体,已放入 字体 中的文件夹库 文件夹,那么我如何将此集用作 Java 可用的一组字体
  • LucidaBrightDemiItalic.ttf
  • LucidaBrightRegular.ttf
  • LucidaSansRegular.ttf
  • LucidaTypewriterRegular.ttf
  • LucidaBrightDemiBold.ttf
  • LucidaBrightItalic.ttf
  • LucidaSansDemiBold.ttf
  • LucidaTypewriterBold.ttf

  • 如果我创建一个空的 fontconfig.properties 文件,那么第一个异常更改为
    Caused by: java.lang.NullPointerException
            at java.desktop/sun.awt.FontConfiguration.getInitELC(FontConfiguration.java:465)
            at java.desktop/sun.awt.FontConfiguration.initFontConfig(FontConfiguration.java:441)
            at java.desktop/sun.awt.FontConfiguration.init(FontConfiguration.java:108)
            at java.desktop/sun.awt.X11FontManager.createFontConfiguration(X11FontManager.java:719)
            at java.desktop/sun.font.SunFontManager$2.run(SunFontManager.java:367)
            at java.base/java.security.AccessController.doPrivileged(Native Method)
            at java.desktop/sun.font.SunFontManager.<init>(SunFontManager.java:312)
            at java.desktop/sun.awt.FcFontManager.<init>(FcFontManager.java:35)
            at java.desktop/sun.awt.X11FontManager.<init>(X11FontManager.java:56)
    

    所以这表明 Java 运行时至少找到了(空)fontconfig.properties 文件,所以如果我可以正确配置它,这应该可以工作。

    我试图用一个文件创建一个非常小的 fontconfig.properties 文件,但它没有用。
    version=1
    
    allfonts.plain.latin-1=-monotype-times new roman-medium-r-normal--*-%d-*-*-p-*-iso10646-1
    
    filename.-monotype-times new roman-medium-r-normal--*-%d-*-*-p-*-iso10646-1=/mnt/app/opt/SongKong/songkong/jre/lib/fonts/ipag.ttf
    
    awtfontpath.latin-1=/mnt/app/opt/SongKong/songkong/jre/lib/fonts
    

    最佳答案

    Jdk 版本不附带任何字体,Oracle 版本通常有,所以我想下载一个 Oracle 版本并查看它们的功能,但 fontconfig.properties 文件在 Windows 和 UNIX 版本之间存在显着差异,因此我需要一个 UNIX 版本。

    我首先下载了 jdk-11.0.6_linux-x64_bin.tar.gz 但这没有 fontconfig.properties 文件,可能是因为它只是一个通用的 linux 构建,而不是特定于任何特定的。由于我的主要开发机器是 Windows,我不热衷于尝试 .deb 或 .rpm 构建,因为我没有简单的安装它们的途径。因此,我下载了 Solaris jdk-11.0.6_solaris-sparcv9_bin.tar.gz 并将其解压缩。

    确实包含遵循此结构的 font.properties.src 文件

    Version =1
    # Component Font Mappings
    # Search Sequences
    # Font Filenames
    # AWT X11 font paths
    

    我的理解是 Component Font Mappings 从 Java 组件字体映射到逻辑字体名称,Search Sequence 指定了基于 Java 组件字体搜索字体的顺序。字体文件名从逻辑字体名映射到字体在机器上的实际文件名。 AWT X11 字体路径指定从组件字体名称到包含机器上实际字体的实际文件夹。

    因此,我对文件进行了搜索和替换,将实际文件名替换为服务器上我的字体上的位置,并将实际文件夹替换为包含实际字体的文件夹上的位置。

    然后我重命名了这个修改后的 fontconfig.proprties.src fontconfig.properties 并将其存储在 jre/lib 文件夹中

    以前失败的简单测试程序现在可以工作了
    import java.awt.*;
    public class Fonts
    {
         public static void main(String[] args) throws Exception
         {
             Font defaultFont = Font.decode(null);
             System.out.println(defaultFont);
         }
    }
    

    但是,我只指定了一种字体(ipag.ttf)用于不同的脚本和不同的样式(普通、粗体等)。

    当我运行程序时,字体需要与 jakarta.poi 一起使用(用于创建 excel 电子表格文件),现在出现以下异常:
    java.lang.ClassCastException: class sun.font.CompositeFont cannot be cast to class sun.font.PhysicalFont (sun.font.CompositeFont and sun.font.PhysicalFont are in module java.desktop of loader 'bootstrap')
        at java.desktop/sun.font.SunFontManager.getDefaultPhysicalFont(SunFontManager.java:1086)
        at java.desktop/sun.font.SunFontManager.initialiseDeferredFont(SunFontManager.java:965)
        at java.desktop/sun.font.SunFontManager.findOtherDeferredFont(SunFontManager.java:903)
        at java.desktop/sun.font.SunFontManager.findDeferredFont(SunFontManager.java:919)
        at java.desktop/sun.font.SunFontManager.findFont2D(SunFontManager.java:2120)
        at java.desktop/java.awt.Font.getFont2D(Font.java:506)
        at java.desktop/java.awt.Font.canDisplayUpTo(Font.java:2246)
        at java.desktop/java.awt.font.TextLayout.singleFont(TextLayout.java:469)
        at java.desktop/java.awt.font.TextLayout.<init>(TextLayout.java:530)
        at org.apache.poi.ss.util.SheetUtil.getDefaultCharWidth(SheetUtil.java:275)
    

    我认为这里的问题是 实物字体意料之中,但因为我没有指定粗体、斜体字体等 Java 尝试根据对物理字体的修改创建字体,创建 复合字体 .但是 Java 总是希望为一些基本样式提供物理字体。

    所以我然后将 Lucida 字体复制到字体目录,修改了 fontconfig。属性文件来使用这些字体变体,如下所示
    filename.-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1=/mnt/app/opt/jre/lib/fonts/LucidaSansRegular.ttf
    filename.-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1=/mnt/app/opt/jre/lib/fonts/LucidaSansRegular.ttf
    filename.-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1=/mnt/app/opt/jre/lib/fonts/LucidaSansDemiBold.ttf
    filename.-monotype-arial-bold-i-normal--*-%d-*-*-p-*-iso10646-1=/mnt/app/opt/jre/lib/fonts/LucidaSansDemiBold.ttf
    filename.-monotype-courier_new-medium-r-normal--*-%d-*-*-p-*-iso10646-1=/mnt/app/opt/jre/lib/fonts/LucidaTypewriterRegular.ttf
    filename.-monotype-courier_new-medium-i-normal--*-%d-*-*-p-*-iso10646-1=/mnt/app/opt/jre/lib/fonts/LucidaTypewriterRegular.ttf
    filename.-monotype-courier_new-bold-r-normal--*-%d-*-*-p-*-iso10646-1=/mnt/app/opt/jre/lib/fonts/LucidaTypewriterBold.ttf
    filename.-monotype-courier_new-bold-i-normal--*-%d-*-*-p-*-iso10646-1=/mnt/app/opt/jre/lib/fonts/LucidaTypewriterBold.ttf
    filename.-monotype-times_new_roman-medium-r-normal--*-%d-*-*-p-*-iso10646-1=/mnt/app/opt/jre/lib/fonts/LucidaBrightRegular.ttf
    filename.-monotype-times_new_roman-medium-i-normal--*-%d-*-*-p-*-iso10646-1=/mnt/app/opt/jre/lib/fonts/LucidaBrightItalic.ttf
    filename.-monotype-times_new_roman-bold-r-normal--*-%d-*-*-p-*-iso10646-1=/mnt/app/opt/jre/lib/fonts/LucidaBrightDemiBold.ttf
    filename.-monotype-times_new_roman-bold-i-normal--*-%d-*-*-p-*-iso10646-1=/mnt/app/opt/jre/lib/fonts/LucidaBrightDemiItalic.ttf
    

    只保留东南亚脚本的 ipag.ttf
    并重新启动应用程序并且有效。我不确定这是否适用于所有情况。

    关于java - 如何配置简单的 Java fontconfig.properties 文件以在 Linux 上使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61024955/

    相关文章:

    java - AbstractTableModel 中的 JTable 未显示

    java - Spring AOP @After 建议导致异常

    java - 如何使用 GridBagLayout 定位组件?

    html - 在单独的 .css 样式表中正确使用自定义字体

    java - 如何在 M1 Macbook 上编译 OpenJDK 11?

    java.lang.NoClassDefFoundError : Could not initialize class sun. font.SunFontManager with OpenJDK 11.0

    java - Jackson:JsonIninclude 如何添加多个 JsonIninclude 注释

    fonts - Adobe LiveCycle 字体转换

    Android textview文本在自定义字体的两侧被截断

    spring-boot - 来自 JDK8 的 JDK 11 迁移问题,com.fasterxml.jackson.module.afterburner.util.MyClassLoader 的非法反射访问