Java: FontMetrics ascent incorrect?

偶尔善良 提交于 2019-11-30 11:37:18

One possible reason is that this value takes into accounts letters with diacritics.

For example, adding the umlauts ÄÖÜ shows that their trema are much closer to the ascent (although they still don't quite reach it).

Looking for a more general definition of ascent I find the definition in Wikipedia:

[..] the ascent spans the distance between the baseline and the top of the glyph that reaches farthest from the baseline. The ascent and descent may or may not include distance added by accents or diacritical marks.

So it seems that even within typography there is no precise, absolute definition.

Tomasz Radziszewski

I came across the same problem and it appears that the true upper bound of a character can be obtained by using GlyphVector class.

package graphics;

import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.font.GlyphVector;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;

public class FontMetricsTest2 {

    public static void main(String[] args) throws IOException {
        //Draw the text to measure it with a drawing program
        BufferedImage img = new BufferedImage(
            500, 300, BufferedImage.TYPE_INT_RGB);
        Graphics2D graphics = img.createGraphics();
        Font font = new Font(Font.SERIF, Font.PLAIN, 150);
        graphics.setFont(font);
        String text = "ABCxyz";
        graphics.drawString(text, 20, 180);
        ImageIO.write(img, "PNG", new File("G:\\someDir\\fontMetrics2.png"));

        //Failed attempts to determine ascent with FontMetrics
        FontMetrics fm = graphics.getFontMetrics();
        System.out.println("FM Ascent=" + fm.getAscent() + 
            ", FM descent=" + fm.getDescent());
        //returned ascent is too high
        System.out.println("FM string bounds: " + 
            fm.getStringBounds(text, graphics));
        //too high as well

        //The succesful way with glyph vector
        GlyphVector gv = font.layoutGlyphVector(
            graphics.getFontRenderContext(), text.toCharArray(),
            0, text.length(), Font.LAYOUT_LEFT_TO_RIGHT);
        Rectangle pixBounds = gv.getPixelBounds(
            graphics.getFontRenderContext(), 0, 0);
        System.out.println("GlyphVector - pixelBounds: " + pixBounds);
        Rectangle2D visBounds = gv.getVisualBounds();
        System.out.println("GlyphVector - visualBounds: " + visBounds);
    }

}

The y value in the rectangles returned by ascent of characters appearing in the string represented "text" variable.

The main difference between pixel bounds and visual bounds is that the pixelBounds are integers and the visualBounds are floats. Otherwise they seem almost equal.

The TrueType Reference Manual says that the ascent of a font is stored in the 'hhea' table. The documentation for hhea states, "The values for ascent, descent and lineGap represent the design intentions of the font's creator rather than any computed value." The OpenType specification is an extension of the TrueType specification. It also stores the ascender in the hhea table and references the TrueType definition of ascent. Bottom line, the ascent property is a guide, not an absolute. The GlyphLayoutVector is the most accurate way to get the bounds of text.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!