Java OpenJDK与OracleJDK中字体略宽
我注意到使用OpenJDK与OracleJDK在字体间距上的差异。我把范围缩小到了字体。它们被OpenJDK渲染得更宽一些。。。仔细观察上面的屏幕截图可以发现字符宽度是相同的,唯一的区别是间距。我还通过对所有字符A-Za-z0-9的字体度量进行编程检查来确认这一点 e、 g.12pt处的字符串“Dialog-plain”为Java OpenJDK与OracleJDK中字体略宽,java,Java,我注意到使用OpenJDK与OracleJDK在字体间距上的差异。我把范围缩小到了字体。它们被OpenJDK渲染得更宽一些。。。仔细观察上面的屏幕截图可以发现字符宽度是相同的,唯一的区别是间距。我还通过对所有字符A-Za-z0-9的字体度量进行编程检查来确认这一点 e、 g.12pt处的字符串“Dialog-plain”为 OpenJDK中125px宽-我的8u131-b11版本 OpenJDK中125px宽-redhat磁盘的库存RPM-1.8u45-b13 Oracle网站发布的Orac
- OpenJDK中125px宽-我的8u131-b11版本
- OpenJDK中125px宽-redhat磁盘的库存RPM-1.8u45-b13
- Oracle网站发布的OracleJDK-8u131-b11版本中的120px宽
-Dawt.useSystemAAFontSettings
,-Dswing.useSystemFontSettings
,-Dswing.defaultlaf=com.sun.java.swing.plaf.gtk.GTKLookAndFeel
。我尝试过改变所有这些,但结果都是一样的
进一步的调查发现,sun.font.FontScaler
,它使用不同的底层FontScaler。在检查系统属性的-Dsun.java2d.font.scaler=t2k
的sun.font.FontUtilities
中,这将显示为部分可配置,但是设置这一设置没有任何区别
我的问题是: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));
}
}
}
更新-2020年1月
*在Java11中,有一个新的选项可能与此相关-请参阅
进一步调查发现sun.font.FontScaler,它使用不同的底层FontScaler。这在sun.font.FontUtilities中显示为部分可配置,该工具检查-Dsun.java2d.font.scaler=t2k的系统属性,但是设置这一点没有任何区别
您是正确的,Oracle和OpenJDK之间的底层字体缩放器是不同的,但不幸的是,这是硬编码的,不可配置
相关代码位于:
还有isOpenJDK
标志?它由以下各项设置:
这个常数是:
static final String LUCIDA_FILE_NAME = "LucidaSansRegular.ttf";
除非我在这些源文件中遗漏了什么,否则没有其他配置标志或任何其他条件会改变正在使用的scaler类
因此,做这件事的唯一明智的方法(我这里排除了可怕的类加载器/反射黑客)是将Lucida文件添加到位。不幸的是,在我能想到的大多数场景中(假设您没有将JRE与包一起分发)这也不是一个切实可行的解决方案。我认为您试图实现的目标是不可能的,因为字体呈现库在Oracle Java和大多数OpenJDK版本中是不同的-很可能不是这样:但由于DIALOG是一种逻辑字体,您最好先检查一种特定的非JDK字体,或者探索字体是否确实相同,甚至比“稍微宽一点”更糟糕。我有一个“6”,看起来非常像一个“8”+谢谢你看这个。我在前面研究了您的建议——将Lucida字体放在OpenJDK上使其“看起来”像Oracle JDK,不幸的是,T2KFontScaler有一个本机libt2k.so支持,但它不存在。这是一个封闭的源代码,我对仅仅从Oracle发行版复制该版本所带来的许可问题非常谨慎。…@Adam是的,这是正确的-事实上,我在不久前开发的东西上报告了相同(或类似)的问题,并得出了相同的结论(除非我想要潜在的法律问题,否则我真的不可能复制这些文件并加以处理。)不幸的是,我不认为有一个简单的解决方案。有一个解决方案我还没有探索过……因为我的调查显示,不同之处在于“advance X”不同于TTF文件的值被勇敢地表示出来……我可以创建一组新的被操纵的TTF文件,只有OpenJDK在“AdvanceX”中应用了一个“模糊因子”,使得渲染输出大致相同——这看起来很疯狂,但与调整100多个传统UI屏幕的布局相比,成本要低得多:)@亚当:这看起来确实很疯狂,但我非常感激维护遗留软件经常要求采用疯狂的方法@亚当:出于兴趣,你有没有实现过一套新的“伪造”TTF文件?我很好奇这是否有帮助!
FREETYPE_PROPERTIES=truetype:interpreter-version=35
if (FontUtilities.isOpenJDK) {
scalerClass = Class.forName("sun.font.FreetypeFontScaler");
} else {
scalerClass = Class.forName("sun.font.T2KFontScaler");
}
File lucidaFile = new File(jreFontDirName + File.separator + LUCIDA_FILE_NAME);
isOpenJDK = !lucidaFile.exists();
static final String LUCIDA_FILE_NAME = "LucidaSansRegular.ttf";