Draw text outline with Freetype

13.1k views Asked by At

I've implemented FreeType in my program, I can draw text with colors and style (Bold, Italic, Underline).

Now I would like to make an outline effect on my text. How can I do it?

Effect like that
(source: googlecode.com)

  • I've tried to draw the text two times, one larger in black in background and the second in white on foreground, result was wrong.
  • I've tried to draw the text two time, one in bold and the second in one on foreground, here again the result was wrong.

I would like to make a test again : Draw the "background" text in "outline" mode and the foreground text in regular mode. What do you think about it?


(source: googlecode.com)

2

There are 2 answers

1
Muzza On

Draw the text, then do a second pass over every pixel that was not fully coloured in. For each of those pixels calculate how far away it is from the nearest coloured pixel. If it's less than X where X is the desired width of your outline, colour it in using your outline colour.

It can be slow to do this for large text but it can be optimised and the results cached to make it run acceptably fast. This method allows complete freedom for all kinds of outline and drop shadow effects.

4
Pavulon On

Rendering text with 2 passes is the key, but you have to position the text correctly. First you should render whole outline and then on top of it render the text.

Rendering the outline:

// initialize stroker, so you can create outline font
FT_Stroker stroker;
FT_Stroker_New(library, &stroker);
//  2 * 64 result in 2px outline
FT_Stroker_Set(stroker, 2 * 64, FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0);
...
// generation of an outline for single glyph:
FT_UInt glyphIndex = FT_Get_Char_Index(face, glyphId);
FT_Load_Glyph(face, glyphIndex, FT_LOAD_DEFAULT);
FT_Glyph glyph;
FT_Get_Glyph(face->glyph, &glyph);
FT_Glyph_StrokeBorder(&glyph, stroker, false, true);
FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, nullptr, true);
FT_BitmapGlyph bitmapGlyph = reinterpret_cast<FT_BitmapGlyph>(glyph);
// blit the glyph here on your target surface.
// For positioning use bitmapGlyph->left, bitmapGlyph->top
// For iteration over the glyph data use bitmapGlyph->bitmap.buffer, bitmapGlyph->bitmap.width, bitmapGlyph->bitmap.rows, bitmapGlyph->bitmap.pitch. 

Next you have to render the text itself on the same data you've blitted the outline. Use the code above, but remove the FT_Glyph_StrokeBorder(&glyph, stroker, false, true); line. This way you will have the text on top of an outline.

To achieve this "Cartoon" text effect you will have to do 4 passes: 3 outlines + 1 text. Texturing or applying a gradient should be done during the blitting phase.