Java2d / AWT文本渲染的奇怪尺寸/界限与给定的字体pt大小和dpi屏幕分辨率?

时间:2015-12-17 16:15:14

标签: java fonts size awt dpi

我刚开始使用屏幕上的 Java2D / AWT 直接渲染文本。基本上它可以工作,但我无法理解AWT报告并在屏幕上呈现的结果的像素大小/尺寸。

参数:

  • 文字为“这是字形测试
  • 字体是java.awt。字体[family = Dialog,name = sans,style = plain,size = 72] (pt)
  • 屏幕分辨率 96 dpi
  • 平台 x86-64 Linux X11 Java 8

屏幕分辨率已通过 Toolkit.getDefaultToolkit()。getScreenResolution()以编程方式确定,并与 xdpyinfo 对应。

fontMetrics.get ...() graphics.drawString() drawGlyphVector()的结果都与这些相关恕我直言,有些奇怪的结果值:

  • 界限是java.awt.geom.Rectangle2D $ Float [x = 0.0,y = -71.55469, w = 448.0,h = 55.875 ]
  • 字体提升: 45 px
  • 字体下降: 12 px
  • 字体高度: 57像素

如果我将字体大小从72改为192 pt,结果是连贯的:java.awt.geom.Rectangle2D $ Float [x = 0.0,y = -190.8125, w = 1208.0,h = 149.0 ],上升:119,下降:31,身高: 150 。如果我更改字体,则只有宽度更改而高度保持不变。 (这是我的预期。)

我认为AWT使用DTP指标,其中1 pt 总是1/72英寸。在96 dpi的屏幕上,96像素将构成一英寸(物理)。 (提供的屏幕dpi值不一定准确反映实际物理设备的值,但这并不重要。)因此,72 pt == 1英寸应该转换为96.我希望找到接近 96的东西在得到的大小值(或它们的组合)中的某个地方,可能是高度值,但它们中的任何一个看起来都不接近它......

问题

  • 任何人都可以像我一样重现类似的价值观,还是非常不典型?
  • 如何计算边界高度/字体高度? (我预计字体高度为96 px,72 pt)
  • 或者:如果它不是类似DTP的点,那么Java中字体大小参数的解释(单位)是什么?
  • AWT中的四舍五入或其他不准确错误是否使 bounds.h metrics.height metrics.ascent + metrics.descent <不同/ strong>或者这是有价值的信息吗?
  • 我错过了其他相关参数吗? (此处不涉及AffineTransforms。)
  • 是否有一种安全(跨平台)的方式可以在96 dpi设备和72磅字体大小上可靠地生成96 px的字体高度? (只是将字体大小乘以常数值是可以接受的吗?)

1 个答案:

答案 0 :(得分:0)

问题解决了:这是我的错!

更确切地说:我实际上不是通过简单的new Font (Font.DIALOG, Font.PLAIN, 72))或类似的方式初始化Font对象,而是使用new Font(Map<? extends AttributedCharacterIterator.Attribute,?> attributes)构造函数。那个人从我的配置中预设了各种字体属性的地图。因为一个变量预设的值不正确,所以它实际上包含了一个map.put (SUPERSCRIPT, SUPERSCRIPT_SUPER);(在我的实际代码中并不如此处所示)。

所以,实际上,这些奇怪的界限是字体在这里一直被创建为较小的上标变体的结果。没有它,边界/创建的文本大小更接近我的预期:

Dialog,style = plain,size = 72],height:84,ascent:67,descent:17,bounds:java.awt.geom.Rectangle2D $ Float [x = 0.0,y = -66.83203,w = 681.0中,h = 83.8125]

虽然它们并不完全符合目标尺寸,但它们更接近。感谢 user1803551 提供MCVE建议,这让我走上了正轨。为了完整起见,这里是(导入省略):

public final class TextRenderTest extends WindowAdapter {

int fontSource;
static private final String TESTTEXT = "This is a glyph test";
static public void  main (String [] args) { new TextRenderTest ().main (); }

void main () {
 Frame frame = new Frame ("Text render test") {
    @Override public void paint (Graphics g) {
     FontMetrics    fm;
     Font           font;
        g.setFont (fontSource++ % 2 == 0 ? createFont () : new Font (Font.DIALOG, Font.PLAIN, 72));
        g.drawString (TESTTEXT, 16, 96);
        fm = g.getFontMetrics ();
        System.out.println (
            "DPI: "      + Toolkit.getDefaultToolkit ().getScreenResolution () +
            ", font: "   + g.getFont ()    + ", font height: " + fm.getHeight () +
            ", ascent: " + fm.getAscent () + ", descent: "     + fm.getDescent () +
            ", bounds: " + fm.getStringBounds (TESTTEXT, g)); } };
    frame.setBounds (64, 32, 800, 280);
    frame.setVisible (true);
    frame.addWindowListener (this);
}
static private Font createFont () {
 HashMap <TextAttribute,Object> map = new HashMap<TextAttribute,Object> (9, 1.0f);
    map.put (FAMILY, "sans");
    map.put (WEIGHT, 500);
    map.put (WIDTH, 1);
    map.put (SIZE, 72);
    map.put (SUPERSCRIPT, SUPERSCRIPT_SUPER);   // <-- Something like this was the fault
    return new Font (map);
}
@Override public void windowClosing (WindowEvent event) { event.getWindow ().dispose (); }
}

此示例以触发器方式演示两种变体:预期边界和意外边界(使用上标)。重绘过程很脏,只需考虑控制台输出。

所以我可以回答我的所有问题:

  1. 不,其他人不太可能重现这些奇怪的结果; - )
  2. 我的期望基本上是正确的,但细节上仍有很小的变化。
  3. 字体大小的解释(单位)似乎基本上是Point,确实。
  4. 这些小变化是我唯一无法解释的,虽然它们对我来说可以忽略不计。
  5. 错过了SUPERSCRIPT参数
  6. 可能根本不需要进一步补偿