Rendering Text Using the .NET Framework

The .NET framework uses GDI+ for the System.Drawing namespace, and this namespace has a whole new way of drawing text. Rather than using the venerable TextOut and ExtTextOut functions, there’s Graphics.DrawString() and Graphics.MeasureString().

The problem with these is that text kerning is measured differently – more accurately – but in a way that is often incompatible with the way app developers want to use these functions.

Specifically, adding a character to a string can change the position of the characters before it. This means if you’re writing an editor and using Graphics.DrawString() to render text with a proportional font, the string will kind of jump around as the user types.

ExtTextOut wasn’t smart enough to do this sort of kerning, so you don’t have this problem. Unfortunately the .NET framework doesn’t have any text drawing function that you can fall back on, so the only way to get the old behaviour is through P/Invoke to the ExtTextOut function in GDI.

This means turning your simple DrawString call:

1
g.DrawString(line.Text, f, Brushes.Black, new Point(0, line.Y));

into

1
2
3
4
5
6
// Initialize destRect to something suitable
RectangleF destRect = new RECT();

IntPtr dc = g.GetHdc();
ExtTextOut(dc, 0, line.Y, 0, ref destRect, line.Text, (uint)line.Text.Length, null);
g.ReleaseHdc();

You also need to declare the signature of ExtTextOut for P/Invoke; the code for that is here (and the code for RECT is here).

Update: The .NET Framework 2.0 is now released. With 2.0 Microsoft acknowledged the need for the original functionality, and added a new class, TextRenderer. This class adds methods for DrawString and MeasureString, so the code snippet above can be replaced with:

1
TextRenderer.DrawText(g, line.Text, font, new Point(0, line.Y), Color.Black);

Much nicer.

2 Responses to “Rendering Text Using the .NET Framework”

  1. Arthur M Says:

    One of the big problems with DrawString function is its total ignorance to character based operations, that combined with string implementation in .NET (strcpy every time you do something with a string)…. I just wonder why is it wizards at Microsoft thought that nobody will need to work with characters now that we have strings :)

    the cost of invalidation and repainting in .net is huge comparing to other operations and if you choose to optimize your application for speed, there seems to be virtually no other way then to forget abotu GDI+ and use GDI instead. What am i missing here?

    arthurmnev at yahoo dot com

  2. Chris A Says:

    Oh dear god in heaven thank you! I’ve spent two days trying to figure out why on earth the text I was drawing in an TreeView.OnDrawNode override was too long to fit in the original bounds, with all the same parameters. Extremely frustrating.

Leave a Reply

Powered by WP Hashcash