Android的油漆:.measureText()与.getTextBounds() [英] Android Paint: .measureText() vs .getTextBounds()

查看:622
本文介绍了Android的油漆:.measureText()与.getTextBounds()的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我用 Paint.getTextBounds测量文本(),因为我感兴趣的是获得高度和宽度的文字来呈现。然而,呈现的实际文本总是比宽一点的 .WIDTH()的填充<在矩形信息code> getTextBounds()。

要我惊讶的是,我测试了 .measureText(),并发现它返回一个不同的(更高)的价值。我给它一个尝试,并发现它是正确的。

为什么他们的报告不同的宽度?我怎样才能获得正确的高度和宽度?我的意思是,我的可以的使用 .measureText(),但我不知道我是否应该信任。高度()返回getTextBounds()

根据要求,这里是最小的code重现该问题:

 最后弦乐someText =你好,我相信我的一些文字。!

涂料P =新的油漆();
矩形边界=新的矩形();

为(浮动F = 10; F&LT; 40; F + = 1F){
    p.setTextSize(F);

    p.getTextBounds(someText,0,someText.length(),边界);

    Log.d(测试,的String.Format(
        大小%F,measureText%F,getTextBounds%D,
        F,
        p.measureText(someText)
        bounds.width())
    );
}
 

输出显示这种差异不仅得到大于1(并没有最后一分钟的舍入误差),也似乎增加与大小(我正要吸引更多的结论,但它可能是完全的字体依赖):

  D /测试(607):大小10.000000,measureText 135.000000,getTextBounds 134
D /测试(607):大小11.000000,measureText 149.000000,getTextBounds 148
D /测试(607):大小12.000000,measureText 156.000000,getTextBounds 155
D /测试(607):大小13.000000,measureText 171.000000,getTextBounds 169
D /测试(607):大小14.000000,measureText 195.000000,getTextBounds 193
D /测试(607):大小15.000000,measureText 201.000000,getTextBounds 199
D /测试(607):大小16.000000,measureText 211.000000,getTextBounds 210
D /测试(607):大小17.000000,measureText 225.000000,getTextBounds 223
D /测试(607):大小18.000000,measureText 245.000000,getTextBounds 243
D /测试(607):大小19.000000,measureText 251.000000,getTextBounds 249
D /测试(607):大小20.000000,measureText 269.000000,getTextBounds 267
D /测试(607):大小21.000000,measureText 275.000000,getTextBounds 272
D /测试(607):大小22.000000,measureText 297.000000,getTextBounds 294
D /测试(607):大小23.000000,measureText 305.000000,getTextBounds 302
D /测试(607):大小24.000000,measureText 319.000000,getTextBounds 316
D /测试(607):大小25.000000,measureText 330.000000,getTextBounds 326
D /测试(607):大小26.000000,measureText 349.000000,getTextBounds 346
D /测试(607):大小27.000000,measureText 357.000000,getTextBounds 354
D /测试(607):大小28.000000,measureText 369.000000,getTextBounds 365
D /测试(607):大小29.000000,measureText 396.000000,getTextBounds 392
D /测试(607):大小30.000000,measureText 401.000000,getTextBounds 397
D /测试(607):大小31.000000,measureText 418.000000,getTextBounds 414
D /测试(607):大小32.000000,measureText 423.000000,getTextBounds 418
D /测试(607):大小33.000000,measureText 446.000000,getTextBounds 441
D /测试(607):大小34.000000,measureText 455.000000,getTextBounds 450
D /测试(607):大小35.000000,measureText 468.000000,getTextBounds 463
D /测试(607):大小36.000000,measureText 474.000000,getTextBounds 469
D /测试(607):大小37.000000,measureText 500.000000,getTextBounds 495
D /测试(607):大小38.000000,measureText 506.000000,getTextBounds 501
D /测试(607):大小39.000000,measureText 521.000000,getTextBounds 515
 

解决方案

您可以做什么,我做了检查这样的问题:

研究Android源$ C ​​$ C,Paint.java源,同时看到measureText和getTextBounds方法。 你会了解到measureText调用native_measureText,并getTextBounds调用nativeGetStringBounds,这是用C ++实现本地方法。

所以,你会继续研究Paint.cpp,这同时实现了。

native_measureText - > SkPaintGlue :: measureText_CII

nativeGetStringBounds - > SkPaintGlue :: getStringBounds

现在你的学习检查当这些方法不同。 经过一些参数的检查,无论是通话功能SkPaint :: measureText在Skia的库(安卓的一部分),但他们都调用不同的重载形式。

进一步挖掘Skia的,我看到两个调用导致到相同的计算在相同的功能,只是不同的返回结果。

要回答你的问题: 无论您的通话做相同的计算。结果可能差别在于事实的 getTextBounds 的返回范围为整数,而 measureText 的返回浮点值。

所以,你所得到的转换浮到INT的过程中舍入误差,而这发生在Paint.cpp在SkPaintGlue :: doTextBounds呼叫功能SkRect ::拉平。

这两个呼叫的计算宽度之间的差异可以是最大限度1

修改2011年10月4日

什么可能比视觉更好。我接过努力,为自己的探索,以及值得赏金:)

这是字体大小60,在红色的范围的矩形,紫色是measureText的结果。

它看出,边界左部开始一些像素从左侧和measureText的值是由在两个左和右此值递增。这是一种叫Glyph的AdvanceX价值。 (我发现这个在SkPaint.cpp Skia的来源)

所以测试的结果是,measureText增加了一些进步价值,双方的文本,而getTextBounds计算最小的边界在哪里给定文本适合。

希望这个结果是对你有用。

测试code:

 保护无效的OnDraw(帆布油画){
     最终的String =你好,我是一些文本。!

     涂料P =新的油漆();
     矩形边界=新的矩形();
     p.setTextSize(60);

     p.getTextBounds(S,0,s.length(),边界);
     浮MT = p.measureText(S);
     INT体重= bounds.width();

     Log.i(LCG的String.Format(
          measureText%F,getTextBounds%D(%S),
          公吨,
          体重,bounds.toShortString())
      );
     bounds.offset(0,-bounds.top);
     p.setStyle(Style.STROKE);
     canvas.drawColor(0xff000080);
     p.setColor(为0xffff0000);
     canvas.drawRect(边界,P);
     p.setColor(0xff00ff00);
     canvas.drawText(S,0,bounds.bottom,p)的;
  }
 

I'm measuring text using Paint.getTextBounds(), since I'm interested in getting both the height and width of the text to be rendered. However, the actual text rendered is always a bit wider than the .width() of the Rect information filled by getTextBounds().

To my surprise, I tested .measureText(), and found that it returns a different (higher) value. I gave it a try, and found it correct.

Why do they report different widths? How can I correctly obtain the height and width? I mean, I can use .measureText(), but then I wouldn't know if I should trust the .height() returned by getTextBounds().

As requested, here is minimal code to reproduce the problem:

final String someText = "Hello. I believe I'm some text!";

Paint p = new Paint();
Rect bounds = new Rect();

for (float f = 10; f < 40; f += 1f) {
    p.setTextSize(f);

    p.getTextBounds(someText, 0, someText.length(), bounds);

    Log.d("Test", String.format(
        "Size %f, measureText %f, getTextBounds %d",
        f,
        p.measureText(someText),
        bounds.width())
    );
}

The output shows that the difference not only gets greater than 1 (and is no last-minute rounding error), but also seems to increase with size (I was about to draw more conclusions, but it may be entirely font-dependent):

D/Test    (  607): Size 10.000000, measureText 135.000000, getTextBounds 134
D/Test    (  607): Size 11.000000, measureText 149.000000, getTextBounds 148
D/Test    (  607): Size 12.000000, measureText 156.000000, getTextBounds 155
D/Test    (  607): Size 13.000000, measureText 171.000000, getTextBounds 169
D/Test    (  607): Size 14.000000, measureText 195.000000, getTextBounds 193
D/Test    (  607): Size 15.000000, measureText 201.000000, getTextBounds 199
D/Test    (  607): Size 16.000000, measureText 211.000000, getTextBounds 210
D/Test    (  607): Size 17.000000, measureText 225.000000, getTextBounds 223
D/Test    (  607): Size 18.000000, measureText 245.000000, getTextBounds 243
D/Test    (  607): Size 19.000000, measureText 251.000000, getTextBounds 249
D/Test    (  607): Size 20.000000, measureText 269.000000, getTextBounds 267
D/Test    (  607): Size 21.000000, measureText 275.000000, getTextBounds 272
D/Test    (  607): Size 22.000000, measureText 297.000000, getTextBounds 294
D/Test    (  607): Size 23.000000, measureText 305.000000, getTextBounds 302
D/Test    (  607): Size 24.000000, measureText 319.000000, getTextBounds 316
D/Test    (  607): Size 25.000000, measureText 330.000000, getTextBounds 326
D/Test    (  607): Size 26.000000, measureText 349.000000, getTextBounds 346
D/Test    (  607): Size 27.000000, measureText 357.000000, getTextBounds 354
D/Test    (  607): Size 28.000000, measureText 369.000000, getTextBounds 365
D/Test    (  607): Size 29.000000, measureText 396.000000, getTextBounds 392
D/Test    (  607): Size 30.000000, measureText 401.000000, getTextBounds 397
D/Test    (  607): Size 31.000000, measureText 418.000000, getTextBounds 414
D/Test    (  607): Size 32.000000, measureText 423.000000, getTextBounds 418
D/Test    (  607): Size 33.000000, measureText 446.000000, getTextBounds 441
D/Test    (  607): Size 34.000000, measureText 455.000000, getTextBounds 450
D/Test    (  607): Size 35.000000, measureText 468.000000, getTextBounds 463
D/Test    (  607): Size 36.000000, measureText 474.000000, getTextBounds 469
D/Test    (  607): Size 37.000000, measureText 500.000000, getTextBounds 495
D/Test    (  607): Size 38.000000, measureText 506.000000, getTextBounds 501
D/Test    (  607): Size 39.000000, measureText 521.000000, getTextBounds 515

解决方案

You can do what I did to inspect such problem:

Study Android source code, Paint.java source, see both measureText and getTextBounds methods. You'd learn that measureText calls native_measureText, and getTextBounds calls nativeGetStringBounds, which are native methods implemented in C++.

So you'd continue to study Paint.cpp, which implements both.

native_measureText -> SkPaintGlue::measureText_CII

nativeGetStringBounds -> SkPaintGlue::getStringBounds

Now your study checks where these methods differ. After some param checks, both call function SkPaint::measureText in Skia Lib (part of Android), but they both call different overloaded form.

Digging further into Skia, I see that both calls result into same computation in same function, only return result differently.

To answer your question: Both your calls do same computation. Possible difference of result lies in fact that getTextBounds returns bounds as integer, while measureText returns float value.

So what you get is rounding error during conversion of float to int, and this happens in Paint.cpp in SkPaintGlue::doTextBounds in call to function SkRect::roundOut.

The difference between computed width of those two calls may be maximally 1.

EDIT 4 Oct 2011

What may be better than visualization. I took the effort, for own exploring, and for deserving bounty :)

This is font size 60, in red is bounds rectangle, in purple is result of measureText.

It's seen that bounds left part starts some pixels from left, and value of measureText is incremented by this value on both left and right. This is something called Glyph's AdvanceX value. (I've discovered this in Skia sources in SkPaint.cpp)

So the outcome of the test is that measureText adds some advance value to the text on both sides, while getTextBounds computes minimal bounds where given text will fit.

Hope this result is useful to you.

Testing code:

  protected void onDraw(Canvas canvas){
     final String s = "Hello. I'm some text!";

     Paint p = new Paint();
     Rect bounds = new Rect();
     p.setTextSize(60);

     p.getTextBounds(s, 0, s.length(), bounds);
     float mt = p.measureText(s);
     int bw = bounds.width();

     Log.i("LCG", String.format(
          "measureText %f, getTextBounds %d (%s)",
          mt,
          bw, bounds.toShortString())
      );
     bounds.offset(0, -bounds.top);
     p.setStyle(Style.STROKE);
     canvas.drawColor(0xff000080);
     p.setColor(0xffff0000);
     canvas.drawRect(bounds, p);
     p.setColor(0xff00ff00);
     canvas.drawText(s, 0, bounds.bottom, p);
  }

这篇关于Android的油漆:.measureText()与.getTextBounds()的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆