我注意到使用OpenJDK与OracleJDK相比,字体间距存在差异。我把它缩小到了字体。它们由OpenJDK渲染得更宽......上面截图的仔细目视检查显示字符宽度相同,唯一的区别是间距。我还通过对所有字符A-Za-z0-9的字体度量的编程检查来确认这一点。
e.g。 String" Dialog - plain"在12点是
我已经广泛搜索了相关信息,并发现了各种选项,包括来自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(&#34; D&#34;),使用Oracle JDK(通过T2KFontScaler)将advance X值返回为14.0px,使用OpenJDK(通过FreetypeFontScaler)返回15.0px
确定哪个是&#34;正确&#34;我使用fontbox Java解析器从TTF文件LiberationSans-Regular.ttf中的HMTX表中提取Glyph-ID 39的advance X值。该值为1479个字体设计单位 - 以20pt字体大小映射到14.44px。
下一个角色没有区别&#34; i&#34; - glyph-id 76.根据fontbox,这是4.44,T2KScaler和FreetypeScaler都返回4;
我进一步将其缩小到标准&#34;非小数&#34;时使用的舍入/计算。使用指标。如果启用了小数度量标准,那么Oracle和Open JDK的行为都相同,尽管宽度仍然比Oracle非小数情况小得多。
g2.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
答案 0 :(得分:7)
进一步调查发现sun.font.FontScaler,它使用不同的底层fontscaler。这在sun.font.FontUtilities中可以部分配置,它检查-Dsun.java2d.font.scaler = t2k的系统属性,但设置此项没有区别。
您正确认为Oracle和OpenJDK之间的底层字体缩放器不同 - 不幸的是,这是硬编码的,不可配置。
相关代码位于FontScaler:97:
if (FontUtilities.isOpenJDK) {
scalerClass = Class.forName("sun.font.FreetypeFontScaler");
} else {
scalerClass = Class.forName("sun.font.T2KFontScaler");
}
isOpenJDK
旗帜?它由FontUtilities:125设置:
File lucidaFile = new File(jreFontDirName + File.separator + LUCIDA_FILE_NAME);
isOpenJDK = !lucidaFile.exists();
那个常数:
static final String LUCIDA_FILE_NAME = "LucidaSansRegular.ttf";
除非我错过了这些源文件中的内容,否则没有其他配置标志或任何其他条件会改变正在使用的缩放器类。
所以唯一含糊不清的做法(我在这里排除可怕的类加载器/反射黑客)是将Lucida文件添加到位。不幸的是,虽然在大多数情况下我都能想到(假设你没有将JRE与包一起分发),这也不是一个可行的解决方案。