如何在Linux上配置简单的Java fontconfig.properties文件。

huangapple go评论89阅读模式
英文:

How do I configure simple Java fontconfig.properties file for use on Linux

问题

以下是翻译好的内容:

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

    Exception in thread "main" java.lang.InternalError: java.lang.reflect.InvocationTargetException
            at java.desktop/sun.font.FontManagerFactory$1.run(FontManagerFactory.java:86)
            ...
    Caused by: java.lang.reflect.InvocationTargetException
            ...
    Caused by: java.lang.NullPointerException
            ...

我可以提供一些字体,我已经弄清楚我需要创建一个 *fontconfig.properties* 文件并将其放入Java运行时的 *lib* 文件夹中,但我难以理解我需要在fontconfig.properties中放入什么内容。

有人可以给我一个在Linux上指定一组最小字体集以防止异常发生的示例吗?

更具体地说,我有一组TrueType字体,我将其放入了 **lib** 文件夹内的 **fonts** 文件夹中,那么我如何将这个集合用作Java可用的字体集呢?

- LucidaBrightDemiItalic.ttf
- LucidaBrightRegular.ttf
- LucidaSansRegular.ttf
- LucidaTypewriterRegular.ttf
- LucidaBrightDemiBold.ttf
- LucidaBrightItalic.ttf
- LucidaSansDemiBold.ttf
- LucidaTypewriterBold.ttf

如果我创建一个空的 fontconfig.properties 文件,那么第一个异常变成了

    Caused by: java.lang.NullPointerException
            ...

这表明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

请注意,这是您提供的内容的翻译,不包含任何其他内容。

英文:

I am using a custom Java 11 runtime on custom linux hardware, the Java runtime was not built my me.
But I have a problem my application requires access to a font and the runtime is not configured with any so I get this stacktrace

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) 

I can provide some fonts and I have worked out I need to create a fontconfig.properties and put i into the Java runtimes lib folder, but I am struggling to understand what I need to put into fontconfig.properties.

Can someone give me an example of how to specify a minimal set of fonts in fontconfig.properties on linux to prevent the exception occurring.

More specificially, I have a set of truetype fonts that I have put into a fonts folder within the lib folder so how do I use this set as a set of fonts available to Java

  • LucidaBrightDemiItalic.ttf
  • LucidaBrightRegular.ttf
  • LucidaSansRegular.ttf
  • LucidaTypewriterRegular.ttf
  • LucidaBrightDemiBold.ttf
  • LucidaBrightItalic.ttf
  • LucidaSansDemiBold.ttf
  • LucidaTypewriterBold.ttf

If I create an empty fontconfig.properties file then the first exception changes to

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)

so this shows Java runtime is at least finding the (empty) fontconfig.properties file so if I can configure it correctly this should work.

I tried to create a very minimal fontconfig.properties file with one file but it didnt work.

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

答案1

得分: 3

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
# 组件字体映射
# 搜索顺序
# 字体文件名
# AWT X11字体路径

我理解的是,组件字体映射Java组件字体映射到逻辑字体名称搜索顺序指定了根据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.properties文件以使用这些字体变体,如下所示:

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用于东南亚脚本,并重新启动了

英文:

Jdk releases do not come with any fonts, Oracle releases generally do, so I had an idea to download an Oracle release and see what they do but the fontconfig.properties file differs significantly between Windows and UNIX releases so I needed a UNIX release.

I first downloaded jdk-11.0.6_linux-x64_bin.tar.gz but this had no fontconfig.properties file probably because it was just a generic linux buiild rather than tied to any in particular. Since my main dev machine is Windows I wasn't keen to try out the .deb or .rpm builds because no easy route for me to install them. So instead I download the Solaris jdk-11.0.6_solaris-sparcv9_bin.tar.gz and unzipped that.

That did contain a font.properties.src file following this structure

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

My understanding is the Component Font Mappings map from a Java component font to a logical font name, Search Sequence specifies an order to search for fonts based on the Java component fonts. Font Filenames map from logical font name to actual filename where the font is located on machine. AWT X11 font paths specifies from the component font name to the actual folder containing the actual font on machine.

So I did a search and replace on the file replacing actual filename with the location on my font on the server, and replacing actual folder with the location on the folder containing the actual font.

I then renamed this modified fontconfig.proprties.src to fontconfig.properties and stored it in the jre/lib folder

A simple test program that previously failed now works

import java.awt.*;
public class Fonts
{
     public static void main(String[] args) throws Exception
     {
         Font defaultFont = Font.decode(null);
         System.out.println(defaultFont);
     }
}

However I have only specified one font (ipag.ttf) to be used for different scripts and for different styles (plain, bold etc).

When I run the program the fonts are required for use with jakarta.poi (for creating an excel spreadsheet file) and this now give the following exception:

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 &#39;bootstrap&#39;)
    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.&lt;init&gt;(TextLayout.java:530)
    at org.apache.poi.ss.util.SheetUtil.getDefaultCharWidth(SheetUtil.java:275)

I think the problem here is that a Physical font was expected but because I had not specified bold, italic fonts ectera Java try to create a font based on modifications to a physical font, creating Composite font. But Java always expects Physical fonts to be provided for some basic styles.

So I then copied the Lucida fonts to the fonts dir, modified the fontconfig. properties file to use these these font variations as follows

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

Just kept the ipag.ttf for South East Asian scripts
and restarted application and that worked. Whether or not this will work in all circumstances I am not sure.

huangapple
  • 本文由 发表于 2020年4月4日 15:22:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/61024955.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定