【发布时间】:2018-06-01 18:04:56
【问题描述】:
我注意到与 OracleJDK 相比,使用 OpenJDK 的字体间距存在差异。我已将其范围缩小到字体。它们由 OpenJDK 渲染得稍微宽一些……仔细观察上面的屏幕截图,可以看出字符宽度是相同的,唯一的区别是间距。我还通过对所有字符 A-Za-z0-9 的字体度量进行编程检查来确认这一点。
例如12pt 处的字符串“Dialog - plain”是
- OpenJDK 中 125px 宽 - 我构建的 8u131-b11
- OpenJDK 中 125 像素宽 - 来自 redhat 磁盘的库存 RPM - 1.8u45-b13
- OracleJDK 中的 120px 宽 - Oracle 网站上的 8u131-b11 版本
我已经广泛搜索了这方面的信息,并从Java_Runtime_Environment_fonts 中找到了各种选项,包括-Dawt.useSystemAAFontSettings、-Dswing.useSystemFontSettings、-Dswing.defaultlaf=com.sun.java.swing.plaf.gtk.GTKLookAndFeel。我已尝试更改所有这些,但结果保持不变。
进一步调查发现sun.font.FontScaler,这使用了不同的底层字体缩放器。这似乎在sun.font.FontUtilities 中部分可配置,它检查-Dsun.java2d.font.scaler=t2k 的系统属性,但是设置它没有任何区别。
我的问题:FreetypeFontScaler 是否可以配置为与 T2KFontScaler 类似或更接近的行为方式?
if (FontUtilities.isOpenJDK) {
scalerClass = Class.forName("sun.font.FreetypeFontScaler");
} else {
scalerClass = Class.forName("sun.font.T2KFontScaler");
}
这是我一直在使用的测试程序
public class FontTester {
public static void main(String[] args) throws Exception {
System.out.println(String.format("java.home=%s", System.getProperty("java.home")));
String family = Font.DIALOG;
int style = Font.PLAIN;
describeFont(new Font(family, style, 12));
JFrame frame = new JFrame();
frame.setSize(800, 600);
frame.add(new DemoPanel());
frame.setVisible(true);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
}
private static class DemoPanel extends JPanel {
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
String family = Font.DIALOG;
int style = Font.PLAIN;
Font font = new Font(family, style, 20);
g.setFont(font);
String str = family + " - " + name(font) + " ";
Rectangle2D bounds = g.getFontMetrics().getStringBounds(str, g);
str += String.format("%f x %f", bounds.getWidth(), bounds.getHeight());
g.drawString(str, 10, 50);
}
private String name(Font font) {
List<String> attrs = new ArrayList<>();
if (font.isBold()) {
attrs.add("bold");
}
if (font.isItalic()) {
attrs.add("italic");
}
if (font.isPlain()) {
attrs.add("plain");
}
return String.join(",", attrs);
}
}
private static void describeFont(Font font) throws Exception {
Method method = Font.class.getDeclaredMethod("getFont2D");
method.setAccessible(true);
Font2D font2d = (Font2D) method.invoke(font);
System.out.print(String.format("%s: ", font));
describeFont2D(font2d);
}
private static void describeFont2D(Font2D font) {
if (font instanceof CompositeFont) {
CompositeFont cf = (CompositeFont) font;
for (int i = 0; i < cf.getNumSlots(); i++) {
PhysicalFont pf = cf.getSlotFont(i);
describeFont2D(pf);
break;
}
} else {
System.out.print(String.format("-> %s \n", font));
}
}
}
更多的调查已经追踪到 sun.font.FontStrike.getGlyphMetrics(int) 返回不同的结果。对于 glyph-id 39(“D”),使用 Oracle JDK(通过 T2KFontScaler)将 Advance X 值返回为 14.0px,但使用 OpenJDK(通过 FreetypeFontScaler)返回 15.0px
为了确定哪个是“正确的”,我使用fontbox Java 解析器从 TTF 文件 LiberationSans-Regular.ttf 中的 HMTX 表中提取 Glyph-ID 39 的提前 X 值。该值是 1479 个字体设计单位 - 在 20pt 字体大小下映射到 14.44px。
下一个字符“i”没有区别 - glyph-id 76。根据 fontbox,这是 4.44,由 T2KScaler 和 FreetypeScaler 返回为 4
我已将其进一步缩小为使用标准“非小数”指标时使用的舍入/计算。如果启用了分数指标,则 Oracle 和 Open JDK 的行为相同,尽管宽度仍略小于 Oracle 非分数情况。
g2.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
更新 - 2020 年 1 月 * 在 Java 11 中有一个可能相关的新选项 - 请参阅 https://bugs.openjdk.java.net/browse/JDK-8217731
FREETYPE_PROPERTIES=truetype:interpreter-version=35
【问题讨论】:
-
我认为你想要实现的目标是不可能的,因为 Oracle Java 和大多数 OpenJDK 版本中的字体渲染库不同 - mail.openjdk.java.net/pipermail/discuss/2017-November/…
-
很可能不是这样:但由于 DIALOG 是一种逻辑字体,您最好先检查特定的非 JDK 字体,或者探索字体是否确实相同。
-
它可能比“稍微宽一点”还要糟糕。我有一个“6”,看起来非常像“8”。来自我的 +1。
标签: java