Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

stb_truetype: Weird kerning #281

Closed
AlexAltea opened this issue Apr 12, 2016 · 8 comments
Closed

stb_truetype: Weird kerning #281

AlexAltea opened this issue Apr 12, 2016 · 8 comments

Comments

@AlexAltea
Copy link

I'm getting weird kernings on stb_truetype in any recent version up to the latest, v1.11. And I'm unsure if this is an issue with my code, the fonts I'm using or stb_truetype. This has happened to me so far with Segoe UI Light (5.53) and Source Sans Pro Light (2.020).

The problem is, stbtt_GetCodepointKernAdvance is returning almost always 0 (sometimes uppercase followed by lowercase is non-zero). This is how my text renderer works:

// The text in my application never changes so the whole string is rendered to txBuffer
// after precomputing its dimensions: txWidth and txHeight.
txBuffer.clear();
txBuffer.resize(txWidth * txHeight);
for (size_t i = 0; i < text.length(); i++) {
    int dx, dy = (ascent - descent) + lineGap;
    int kern = stbtt_GetCodepointKernAdvance(fontInfo, text[i], text[i+1]);
    stbtt_GetCodepointHMetrics(fontInfo, text[i], &dx, 0);
    int x1, y1, x2, y2;
    stbtt_GetCodepointBitmapBox(fontInfo, text[i], scale, scale, &x1, &y1, &x2, &y2);
    size_t offset = x + ((y + ascent + y1) * txWidth);
    stbtt_MakeCodepointBitmap(fontInfo, &txBuffer[offset], x2 - x1, y2 - y1, txWidth, scale, scale, text[i]);
    x += (dx + kern) * scale;
 }

This is the output with Segoe UI Light:

Expected result:

Sorry about the diffent font size, the second image comes from Microsoft. Looking for support on the internet about this, I've also seen other people noticing this kerning issue.

@nothings
Copy link
Owner

  • It is normal that it almost always returns 0; most character pairs are unkerned.
  • The issue with Segoe UI Light sure looks like a bug. (What's it look like if you don't kern?)
  • The "other people noticing the kerning issue" looks more like people not using subpixel positioning; small font sizes w/o subpixel, kerning is irrelevant. So not related to your problem.

I didn't write the kerning code and I've never used it. I don't know when I'll get a chance to look at it.

@nothings
Copy link
Owner

(Also, btw, note that your code won't actually work correctly if a pair of characters does get kerned together tightly, as the later character will partially erase the earlier character if their bounding boxes overlap (which often happens with kerning). The sample code at the top of stb_truetype explains how this is a bug.)

@AlexAltea
Copy link
Author

I see, thanks a lot for your answer!

It is normal that it almost always returns 0

Oh, my bad. Feel free to rename the issue to whatever you think it suits best. I'll remain subscribed until someone figures out what's wrong with this font. :-)

What's it look like if you don't kern?

It looks quite similar:

Comparing without (black) and with (grey) kerning:

(Sorry about crappy Photoshop skills). As you see only "W-a" and "r-s" got non-zero kerning.

@nothings
Copy link
Owner

That looks pretty wrong without kerning too.

Ok, I guess the big question is whether the reference image you say 'came from microsoft' was actually directly rendered, or whether someone hand-kerned it. If the former, then clearly there's info in the font to fix it; if the latter, it may not be a bug at all.

@nothings
Copy link
Owner

You might try taking the second value from GetHMetrics ("left side bearing" or "lsb") and using that as an extra horizontal offset for each character (not applied as an advance, just to offset the x position of each char). I don't know if this is necessary, I don't do it anywhere so I thought it wasn't, but maybe it is.

@AlexAltea
Copy link
Author

Perfect! Adding the (scaled) left side bearing to the offset solves the issue:

Thanks for your help. I leave the corrected code below, in case someone else blindly copies some sample code and comes accross the same problem. :-)

// The text in my application never changes so the whole string is rendered to txBuffer
// after precomputing its dimensions: txWidth and txHeight.
txBuffer.clear();
txBuffer.resize(txWidth * txHeight);
for (size_t i = 0; i < text.length(); i++) {
    int lsb, dx, dy = (ascent - descent) + lineGap;
    int kern = stbtt_GetCodepointKernAdvance(fontInfo, text[i], text[i+1]);
    stbtt_GetCodepointHMetrics(fontInfo, text[i], &dx, &lsb);
    int x1, y1, x2, y2;
    stbtt_GetCodepointBitmapBox(fontInfo, text[i], scale, scale, &x1, &y1, &x2, &y2);
    size_t offset = x + (lsb * scale) + ((y + ascent + y1) * txWidth);
    stbtt_MakeCodepointBitmap(fontInfo, &txBuffer[offset], x2 - x1, y2 - y1, txWidth, scale, scale, text[i]);
    x += (dx + kern) * scale;
 }

@AlexAltea AlexAltea changed the title stb_truetype: Zero-length kerning stb_truetype: Weird kerning Apr 13, 2016
@nothings nothings reopened this Apr 13, 2016
@nothings
Copy link
Owner

I'm leaving this open since I need to fix the samples.

@nothings
Copy link
Owner

Actually I suspect this isn't a bug and the issue isn't that you should use lsb, but rather that you're not using x1 (which may or may not have the same functionality, but is the approved way to do it).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants