我正在编写这个使用我在GraphicsEnvironment中注册的自定义字体的程序。问题是字体名称在不同的机器上以不同的方式返回,一个是mac OS,另一个是linux。
public void loadCustomFonts() {
LOG.info("Loading custom fonts.");
File folder = new File("fontsDirectory");
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
Arrays.stream(folder.listFiles()).forEach(f -> {
try {
ge.registerFont(Font.createFont(Font.TRUETYPE_FONT, f));
} catch (FontFormatException e) {
LOG.error(e);
} catch (IOException e) {
LOG.error(e);
}
});
}
但是当我运行以下代码时,我在不同的机器上得到不同的输出:
Arrays.stream(ge.getAllFonts()).forEach(f -> System.out.println(f.getName()));
例如,在一台机器上,字体名称将显示为FontLight,而在另一台机器上,它将显示为字体灯(中间有空格)。
我为什么会遇到这种行为的任何解释?
答案 0 :(得分:2)
现代字体格式复杂且历史悠久。出于向后兼容性的原因,当定义了一种新的更好的声明字体元数据的方法时,它会添加到之前存在并且仍然存在于字体文件中的之前。 OpenType现在至少有三个这样的层IIRC。
最老的有各种限制,并且旨在向后兼容较旧的格式,例如Postscript字体(系列名称中没有空格,只有4种可能的面正常/粗体/斜体/粗体斜体,仅限7位ASCII)还有另外一个对命名没有任何限制,并且添加了一个更健全规则的新版本(一些字体作者将人类文本放在面部名称中,这对于像bigder这样的CSS选择器来说并不真正有用)。可能还有其他我忘了(OS / 2和Panose信息任何人?)。
文本堆栈读取写入时存在的最新层,因此根据它们的年龄,它们不会在同一文件中读取相同的层。字体作者通常期望在各种元数据层中声明一致的信息,但从技术上讲,没有什么能阻止作者声明字体被命名为" Foo"在一个层和" Bar"在另一个(当字体作者使用字体创作应用程序将占位符信息放入元数据中,或者通过复制另一个字体创建字体,并且作者未正确检查他在发布之前更改了所有元数据层时)会发生可怕的事情。此外,即使作者努力保持一致,与不同层相关的技术限制也不允许在某些情况下使用严格相同的值。
此外,现代操作系统尝试使用损坏的元数据修复字体,因此即使两位软件读取相同的元数据层,也可以在进入应用程序之前通过系统文本堆栈进行更改。
随着Java在各种操作系统中的集成越来越好,它往往更多地依赖于系统文本堆栈,因为当Java不像系统的其他部分那样引用字体文件时,用户往往会讨厌。例如,最近的openjdks通过fontconfig访问Linux字体,而fontconfig具有非常复杂的字体匹配和重命名功能。
此外,字体元数据可以被本地化,字体文件可以包含各种语言的面部名称的翻译,软件可以选择使用(或不使用)。读取字体中包含的本地化名称在各系统中更容易且更一致(但是某些语言的字体文件元数据可能缺少翻译),始终读取英文名称(并使用单个系统范围的翻译显示常见面部名称的翻译) table)与系统级别更加一致(但是字体文件元数据可能缺少英文版本或使用系统范围的翻译表中不存在的奇怪的独一无二的面部名称。)
最后一些OpenType变体允许插值权重或倾斜,他们不使用面名,但在各种插值轴上使用数值(可变字体)。
所有这一切都意味着"字体名称"你可能会喜欢它,而不是那么简单,不变和一致。特别是在越过系统边界时。