Search code examples
freetype2

Why does Freetype render characters too close together?


I'm trying to use Freetype to render text for use in an SDL/framebuffer application running on a Raspberry Pi. This is what I'm seeing at the moment:

enter image description here

See the '0' and '1' in 2015? They are too close together. Looks wrong.

My code that draws the text into an image buffer:

int FScale = 64;
int FShift = 6;
GArray<uint32> Glyphs;
for (OsChar *s = Str; *s; s++)
{
    FT_UInt index = FT_Get_Char_Index(Fnt, *s);
    if (index)
        Glyphs.Add(index);
}

// Measure the string...
GdcPt2 Sz;
int FontHt = Font->GetHeight();
int AscentF = (int) (Font->Ascent() * FScale);
int LoadMode = FT_LOAD_FORCE_AUTOHINT;
for (unsigned i=0; i<Glyphs.Length(); i++)
{
    error = FT_Load_Glyph(Fnt, Glyphs[i], LoadMode);
    if (error == 0)
    {
        int PyF = AscentF - Fnt->glyph->metrics.horiBearingY;

        Sz.x += Fnt->glyph->metrics.horiAdvance;
        Sz.y = max(Sz.y, PyF + Fnt->glyph->metrics.height);
    }
}

// Create the memory context to draw into
x = ((Sz.x + FScale - 1) >> FShift) + 1;
y = FontHt;

if (Img.Reset(new GMemDC(x, y, CsIndex8)))
{
    // Clear the context to black
    Img->Colour(0);
    Img->Rectangle();

    int CurX = 0;
    int FBaseline = Fnt->size->metrics.ascender;
    for (unsigned i=0; i<Glyphs.Length(); i++)
    {
        error = FT_Load_Glyph(Fnt, Glyphs[i], LoadMode);
        if (error == 0)
        {
            error = FT_Render_Glyph(Fnt->glyph, FT_RENDER_MODE_NORMAL);
            if (error == 0)
            {
                FT_Bitmap &bmp = Fnt->glyph->bitmap;
                if (bmp.buffer)
                {
                    int Px = (CurX + (FScale >> 1)) >> FShift;
                    int PyF = AscentF - Fnt->glyph->metrics.horiBearingY;
                    int Py = PyF >> FShift;

                    // copy bitmap into my image buffer at 'Px' x pos
                }

                if (i < Glyphs.Length() - 1)
                {
                    FT_Vector kerning;
                    FT_Get_Kerning(Fnt, Glyphs[i], Glyphs[i+1], FT_KERNING_DEFAULT, &kerning);
                    CurX += Fnt->glyph->metrics.horiAdvance + kerning.x;
                }
                else
                {
                    CurX += Fnt->glyph->metrics.horiAdvance;
                }
            }
        }
    }
}

The kerning doesn't seem to make any difference with any of the modes I supply. (kerning.x is always 0)

What am I doing wrong here?


Solution

  • The problem is that I wasn't accounting for the bitmap_top and bitmap_left adjustments in the glyph structure.

    After I calculate the Px and Py position I added this snippit of code:

    if (Fnt->glyph->format == FT_GLYPH_FORMAT_BITMAP)
    {
        Px += Fnt->glyph->bitmap_left;
        Py = (AscentF >> FShift) - Fnt->glyph->bitmap_top;
    }
    

    And now the '1' has moved into place correctly. This is what it looks like now:

    Fixed freetype render