首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在OpenJDK和OracleJDK中字体略宽一些

在OpenJDK和OracleJDK中字体略宽一些
EN

Stack Overflow用户
提问于 2017-12-19 10:17:31
回答 1查看 3K关注 0票数 16

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

例如,12 at处的字符串"Dialog -平原“是

  • 125 my in OpenJDK -my build of 8u131-b11
  • 125 in宽的OpenJDK -来自红帽盘的股票RPM - 1.8u45-b13
  • 120 in in OracleJDK - 8u131-b11从甲骨文网站发布

我已经广泛地搜索了有关这方面的信息,并找到了各种选项,包括-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类似或更接近的行为?

代码语言:javascript
复制
if (FontUtilities.isOpenJDK) {
      scalerClass = Class.forName("sun.font.FreetypeFontScaler");
} else {
      scalerClass = Class.forName("sun.font.T2KFontScaler");
}

这是我一直在使用的测试程序

代码语言:javascript
复制
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的非小数情况小得多。

代码语言:javascript
复制
g2.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);

更新-2020年1月*在Java 11中有可能相关的新选项-请参阅https://bugs.openjdk.java.net/browse/JDK-8217731

代码语言:javascript
复制
FREETYPE_PROPERTIES=truetype:interpreter-version=35
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-12-20 13:59:09

进一步的调查发现sun.font.FontScaler,这使用了不同的底层字体定标器。在sun.font.FontUtilities中,这似乎是部分可配置的,它检查系统属性是否为-Dsun.java2d.font.scaler=t2k,但是设置这一点没有什么区别。

您是正确的,因为底层字体定标器在甲骨文和OpenJDK之间是不同的-不幸的是,这是硬编码和不可配置的。

相关代码在FontScaler:97

代码语言:javascript
复制
if (FontUtilities.isOpenJDK) {
    scalerClass = Class.forName("sun.font.FreetypeFontScaler");
} else {
    scalerClass = Class.forName("sun.font.T2KFontScaler");
}

isOpenJDK旗子呢?是由实用程序:125设置的

代码语言:javascript
复制
File lucidaFile = new File(jreFontDirName + File.separator + LUCIDA_FILE_NAME);
isOpenJDK = !lucidaFile.exists();

而这个常数:

代码语言:javascript
复制
static final String LUCIDA_FILE_NAME = "LucidaSansRegular.ttf";

除非我忽略了这些源文件中的某些内容,否则没有其他配置标志或任何其他条件可以更改所使用的scaler类。

因此,做这件事的唯一不太明智的方法(这里我排除了可怕的类加载器/反射黑客)是在适当的地方添加Lucida文件。不幸的是,在大多数情况下,我可以想到(假设您没有将JRE与包一起分发),这也不是一个可行的解决方案。

票数 8
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/47884684

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档