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

我在自定义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并将其放入Java运行时lib文件夹中的问题,但是我正在努力理解我需要将其放入fontconfig.properties中的方法。

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

更具体地说,我将一组真字体放入了 lib 文件夹内的字体文件夹中,因此如何将这组字体用作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发行版并查看其功能,但是Windows和UNIX发行版之间的fontconfig.properties文件存在显着差异,因此我需要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
    

    我的理解是从Java组件字体到逻辑字体名称的Component Font Maps映射,“搜索顺序”指定了基于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)
    

    我认为这里的问题是应该使用物理字体,但是由于我没有指定粗体,斜体字体ectera Java会尝试基于对物理字体的修改来创建字体,从而创建复合字体。但是Java一直希望为某些基本样式提供Physical字体。

    因此,我然后将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

    我的模式类似于OR:“word1 | word2 | word3”我大约有800个字。可能有问题吗? 参考方案 您仅受记忆和理智的限制。 :)

    Java:线程池如何将线程映射到可运行对象 - java

    试图绕过Java并发问题,并且很难理解线程池,线程以及它们正在执行的可运行“任务”之间的关系。如果我创建一个有10个线程的线程池,那么我是否必须将相同的任务传递给池中的每个线程,或者池化的线程实际上只是与任务无关的“工人无人机”可用于执行任何任务?无论哪种方式,Executor / ExecutorService如何将正确的任务分配给正确的线程? 参考方案 …

    JAVA:字节码和二进制有什么区别? - java

    java字节代码(已编译的语言,也称为目标代码)与机器代码(当前计算机的本机代码)之间有什么区别?我读过一些书,他们将字节码称为二进制指令,但我不知道为什么。 参考方案 字节码是独立于平台的,在Windows中运行的编译器编译的字节码仍将在linux / unix / mac中运行。机器代码是特定于平台的,如果在Windows x86中编译,则它将仅在Win…

    java:继承 - java

    有哪些替代继承的方法? java大神给出的解决方案 有效的Java:偏重于继承而不是继承。 (这实际上也来自“四人帮”)。他提出的理由是,如果扩展类未明确设计为继承,则继承会引起很多不正常的副作用。例如,对super.someMethod()的任何调用都可以引导您通过未知代码的意外路径。取而代之的是,持有对本来应该扩展的类的引用,然后委托给它。这是与Eric…

    Java:BigInteger,如何通过OutputStream编写它 - java

    我想将BigInteger写入文件。做这个的最好方式是什么。当然,我想从输入流中读取(使用程序,而不是人工)。我必须使用ObjectOutputStream还是有更好的方法?目的是使用尽可能少的字节。谢谢马丁 参考方案 Java序列化(ObjectOutputStream / ObjectInputStream)是将对象序列化为八位字节序列的一种通用方法。但…