Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

StaticLayout height measurements off

Tags:

android

bitmap

I am trying to draw multiline text to a bitmap with the font Latto-Reg, and StaticLayout seems to have problems with it.

paint.setTextSize(label.fontSize);
paint.setTypeface(face);
StaticLayout textLayout = new StaticLayout(label.text, paint, (int)StaticLayout.getDesiredWidth(label.text, paint), Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);
Bitmap bitmapAux = Bitmap.createBitmap(textLayout.getEllipsizedWidth(), textLayout.getHeight(), Bitmap.Config.ALPHA_8);
canvas.setBitmap(bitmapAux);
canvas.save();
canvas.translate(0, textLayout.height());
textLayout.draw(canvas);
canvas.restore();

The texture has padding on top and bottom depending on the font and size, while the text fits perfectly in the bitmap it is a lot of wasted memory space and makes laying it out to be off by a random amount.

Top/bot padding wrong

I tested using single-line drawing and the bitmap was perfectly fitting the text

paint.getTextBounds(label.text, 0, label.text.length(), rect);
Bitmap bitmapAux = Bitmap.createBitmap(rect.width(), rect.height(), Bitmap.Config.ALPHA_8);
canvas.drawText(label.text, -rect.left, -rect.bottom, paint);

pixel-perfect

I have tried getting all kinds of metrics from StaticLayout and all of them seem to be off from the text: line 0 bounds, line 0 top, last line bottom...leading to the same padding problems.

EDIT: I solved the problem by using offset-based single line drawing. Still the StaticLayout class was drawing incorrectly with several different non-standard fonts and I want to know why.

like image 316
MLProgrammer-CiM Avatar asked Nov 20 '13 14:11

MLProgrammer-CiM


2 Answers

I've created a minimal working example of what I think you're trying to accomplish: creating a bitmap precisely large enough to contain the text rendered through a StaticLayout.

It seems that there are a few things wrong with your code:

  1. You're needlessly translating vertically inside the bitmap;
  2. There doesn't appear to be a height() method for StaticLayout.

Here's my result:

Application result

I added a green background to illustrate the size of the bitmap, but otherwise, my code differs very little from yours:

public void createTexture() {
    int width = textLayout.getEllipsizedWidth();
    int height = textLayout.getHeight();
    bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
    Canvas canvas2 = new Canvas(bitmap);
    Paint p2 = new Paint();
    p2.setStyle(Style.FILL);
    p2.setColor(Color.GREEN);
    canvas2.drawRect(0, 0, width, height, p2);
    textLayout.draw(canvas2);
}

I created a very simple custom component to draw the bitmap:

@Override
protected void onDraw(Canvas canvas) {
    canvas.drawBitmap(bitmap, 0, 0, paint);
}

It seems that perhaps you're translating to draw multiple textures after one another. I'd recommend that you do so in your draw method instead, translating vertically in the height of the previous texture after drawing it.

like image 24
Paul Lammertsma Avatar answered Nov 02 '22 06:11

Paul Lammertsma


Looking at the android developper page, it looks like it's designed to handle both the multi-line case and being used next to another Layout well, and hence there is space on top of the line of text so that if you place it directly below another Layout it will be correctly spaced. In essence, it's just not designed for what you are trying to achieve.

Overall, it may be easier to get the Text bounds from Paint.getTextBounds() to know what the extent of the text will be within the Layout.

like image 127
Neil Townsend Avatar answered Nov 02 '22 07:11

Neil Townsend