gpt4 book ai didi

java - OpenJDK 与 OracleJDK 中的字体略宽

转载 作者:搜寻专家 更新时间:2023-10-30 21:10:29 26 4
gpt4 key购买 nike

我注意到与 OracleJDK 相比,使用 OpenJDK 的字体间距有所不同。我已经将范围缩小到字体。它们由 OpenJDK 渲染得稍微宽一点……仔细观察上面的屏幕截图可以看出字符宽度是相同的,唯一的区别是间距。我还通过对所有字符 A-Za-z0-9 的字体指标进行编程检查来确认这一点。

OpenJDK vs OracleJDK fonts

例如12pt 处的字符串“Dialog - plain”是

  • 在 OpenJDK 中 125 像素宽 - 我构建的 8u131-b11
  • OpenJDK 中 125 像素宽 - 来自 redhat 磁盘的库存 RPM - 1.8u45-b13
  • OracleJDK 中的 120px 宽 - 来自 Oracle 网站的 8u131-b11 版本

我广泛搜索了这方面的信息并找到了各种选项,包括 -Dawt.useSystemAAFontSettings , -Dswing.useSystemFontSettings , -Dswing.defaultlaf=com.sun.java.swing.plaf.gtk.GTKLookAndFeel来自 Java_Runtime_Environment_fonts .我已尝试更改所有这些,但结果保持不变。

进一步调查发现sun.font.FontScaler ,这使用不同的底层 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”),高级 X 值使用 Oracle JDK(通过 T2KFontScaler)返回 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

最佳答案

Further investigation has found sun.font.FontScaler, this uses different underlying fontscaler. This appears partially configurable in sun.font.FontUtilities which checks the system property for -Dsun.java2d.font.scaler=t2k, however setting this makes no difference.

您是正确的,因为底层字体缩放器在 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";

除非我遗漏了那些源文件中的某些内容,否则没有其他配置标志或任何其他条件会更改正在使用的缩放器类。

因此唯一隐约合理的方法(我在这里排除了可怕的类加载器/反射 hacks)是在适当的位置添加 Lucida 文件。不幸的是,尽管在我能想到的大多数情况下(假设您没有随包一起分发 JRE)这也不是真正可行的解决方案。

关于java - OpenJDK 与 OracleJDK 中的字体略宽,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47884684/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com