Calculating size of String rendered with stb_truetype again

Started by Cornix, August 18, 2017, 11:12:04

Previous topic - Next topic

Cornix

Hi there,

I am running into troubles with stb_truetype again when it comes to calculating string sizes. I have a very simple question and I am afraid of the answer since I guess it wont be the one I want:

Can I calculate the width of a String rendered with stb_truetype without actually rendering it?

I tried the following:
1) My first approach was to call stbtt_GetCodepointBox and stbtt_GetCodepointHMetrics for each code point and calculating the width and height of the glyph like this:
float glyphW = Math.max(Math.abs(x0 - x1), Math.abs(adv + lsb));
float glyphH = Math.max(Math.abs(y0 - y1), fontHeight);
with x0, x1, y0 and y1 taken from stbtt_GetCodepointBox and adv and lsb being the advance and the left side bearing from stbtt_GetCodepointHMetrics.

Then I calculated the size of a string by adding up the glyphW values for each code point in the String. This value was too large! It usually missed the mark by 5% ~ 20% depending on the contents of the String.

2) My second approach was to calculate the width of all glyphs the same way the rendering does and store the widths statically. I called stbtt_GetBakedQuad and calculated:
float glyphW = Math.abs(q.x0() - q.x1());
float glyphH = Math.max(Math.abs(q.y0() - q.y1()), fontHeight);

Again I calculated the width of a String by iterating over all code points and adding the glyphW values I previously calculated. This value was often (not always) too small!




So, is there a reliable and correct way to statically calculate the string size without keeping the stb data around after an initialization phase? Or do I need to call stbtt_GetBakedQuad (and keep the quad info) every time I want to know the size of a String?

Thank you all.

spasi

The correct approach has already been explained here. What you're trying to do is unnecessarily complex, the only thing you need is stbtt_GetCodepointHMetrics and the advance value.

I have updated the Truetype demo in the LWJGL repository with some example code, here. It does the following:

- Iterates the string's codepoints correctly (i.e. combines surrogate pairs), so works across the entire UTF-16 range.
- Uses stbtt_GetCodepointHMetrics to sum the codepoint advance values. (super simple)
- Uses stbtt_GetCodepointKernAdvance to adjust the advance value, for fonts with kerning information. (improves quality significantly)

All of the above can be precomputed/cached for performance.

If you can run the demo, press K to toggle kerning on/off and B to render a bounding box around each line (it should be tight around the text). Note that the included demo/FiraSans.ttf does not have kerning information. Change it to e.g. C:\Windows\Fonts\Arial.ttf to see how kerning works.

Also note how the line bounding box is adjusted with the descent value returned from stbtt_GetFontVMetrics.

Cornix