我注意到使用OpenJDK与OracleJDK在字体间距上的差异。我把范围缩小到字体上了。它们被OpenJDK渲染得更宽.仔细检查屏幕截图上面显示的字符宽度是相同的,唯一的差异是间距。我还确认了这一点,并对所有字符A-Za-z0-9的字体进行编程检查。

例如,12 at处的字符串"Dialog -平原“是
我已经广泛地搜索了有关这方面的信息,并找到了各种选项,包括-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)返回了不同的结果。对于字形id 39 ("D"),使用Oracle (通过T2KFontScaler)以14.0px的形式返回前进的X值,而使用OpenJDK (通过FreetypeFontScaler)返回15.0px。
为了说明哪个是“正确的”,我使用方框 Java解析器从TTF文件LiberationSans-Regular.ttf中的HMTX表中提取Glyph-ID39的提前X值。这个值是1479个字体设计单元--在20pt字体大小下映射到14.44 at。
下一个字符"i“-字形-id 76没有区别。根据fontbox,这是4.44,由T2KScaler和FreetypeScaler作为4返回
我进一步将其缩小到使用标准“非小数”度量时所使用的舍入/计算。如果启用了小数度量,那么Oracle和Open的行为都是相同的,尽管宽度仍然比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发布于 2017-12-20 13:59:09
进一步的调查发现sun.font.FontScaler,这使用了不同的底层字体定标器。在sun.font.FontUtilities中,这似乎是部分可配置的,它检查系统属性是否为-Dsun.java2d.font.scaler=t2k,但是设置这一点没有什么区别。
您是正确的,因为底层字体定标器在甲骨文和OpenJDK之间是不同的-不幸的是,这是硬编码和不可配置的。
相关代码在FontScaler:97中
if (FontUtilities.isOpenJDK) {
scalerClass = Class.forName("sun.font.FreetypeFontScaler");
} else {
scalerClass = Class.forName("sun.font.T2KFontScaler");
}isOpenJDK旗子呢?是由实用程序:125设置的
File lucidaFile = new File(jreFontDirName + File.separator + LUCIDA_FILE_NAME);
isOpenJDK = !lucidaFile.exists();而这个常数:
static final String LUCIDA_FILE_NAME = "LucidaSansRegular.ttf";除非我忽略了这些源文件中的某些内容,否则没有其他配置标志或任何其他条件可以更改所使用的scaler类。
因此,做这件事的唯一不太明智的方法(这里我排除了可怕的类加载器/反射黑客)是在适当的地方添加Lucida文件。不幸的是,在大多数情况下,我可以想到(假设您没有将JRE与包一起分发),这也不是一个可行的解决方案。
https://stackoverflow.com/questions/47884684
复制相似问题