Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android: Measure Text Height on a Canvas

I am currently working on rendering a Bitmap, that I then want to send to a mobile printer. However, I am struggling with measuring the height of my text, so I can advance the y position appropriately.

My basic bitmap/canvas/paint configuration is this (Font Size is 16 and the dimensions of the bitmap are 200x400 (width x height):

public MyRenderer() {
    // Initialize bitmap
    bitmap = Bitmap.createBitmap(200, 400, Bitmap.Config.ARGB_8888);

    // Initialize canvas
    canvas = new Canvas(bitmap);

    // Initialize brush (Paint instance)
    brush = new Paint();
    brush.setTextSize(16);
    brush.setTypeface(Typeface.SANS_SERIF);
    brush.setColor(Color.BLACK);
    brush.setStyle(Paint.Style.FILL);
    brush.setAntiAlias(true);
    brush.setTextAlign(Align.LEFT);
}

So far so good, now what I want to do is: If I use the Paint's method drawText I need to supply the x and y coordinates. As for x that's zero (assuming left aligned text) but as for y, I'd have to calculate the height of each text I print and add it up, so I can keep track of my current y position.

And this is where it gets odd: I am using the following method to determine the height of a text (using the Paint objected that I initialized previously - it's called "brush"):

public int measureHeight(String text) {
    Rect result = new Rect();
    // Measure the text rectangle to get the height
    brush.getTextBounds(text, 0, text.length(), result);
    return result.height();
}

The above method returns the following values for the following texts:

  1. "Hello World" returns a height of 12
  2. "A camera instance can be used to compute 3D transformations and generate a matrix." returns a height of 16
  3. "Introducing Android Design: The place to learn about principles, building blocks, and patterns for creating world-class Android user interfaces. Whether you're a UI professional or a developer playing that role, these docs show you how to make good design decisions, big and small." returns a height of 16

It makes sense to me, that number 2 and 3 return a greater height than number 1 but if one line has a height of 12 (as number one does) - it makes no sense, that multiple lines have a height of 16 ?

Am I missing something here? There is a convenience method for measuring the width of a text (using an instance of paint and call measureText("myText") which works perfectly, however I am quite at a loss, when it comes to the height, as the above given results don't make any sense to me.

EDIT

I am aware, that getTextBounds probably does no auto-wrapping of multi-lined text, and that's ok, I already wrote a method for splitting text, but even if it just measures one line, the above given length values still seem unlikely.

like image 996
AgentKnopf Avatar asked Feb 20 '12 16:02

AgentKnopf


2 Answers

I think it is because the "p" in "compute" extends below the baseline whereas "Hello World" only contains letters that are above the baseline.

Since the line distance should not depend on what specific letters your text happens to consist of you are probably looking for Paint.FontMetrics which can be obtained via Paint.getFontMetrics(). Compute descent - ascent + leading to get the recommended baseline distance (because ascent has a negative value).

like image 75
devconsole Avatar answered Nov 08 '22 03:11

devconsole


There is a small error in the accepted answer. If you want the text height, you should use

Paint.FontMetrics fm = mTextPaint.getFontMetrics();
float textHeight = fm.descent - fm.ascent;

And if you want the line height, you should use

float lineHeight = fm.bottom - fm.top + fm.leading;

Leading is optional interline spacing, so if you need to get the line hight you can include it. But if you just want the text height, then you can leave it off.

Note

  • I've never actually seen leading be anything else than 0, and as far as I can tell it even seems to be ignored in the TextView source code (and its associated Layout, StaticLayout, etc.). Please correct me if I'm wrong. So it is probably safe it leave it out of line hight calulations, but I'm not completely sure about that.

See also

  • Getting text height from getTextBounds vs FontMetrics vs StaticLayout
  • Meaning of top, ascent, baseline, descent, bottom, and leading in Android's FontMetrics
like image 5
Suragch Avatar answered Nov 08 '22 03:11

Suragch