If I use TextRenderer.DrawText() using the Graphics object provided in the OnPaintBackground my text looks perfect. If I create my own Bitmap and use the Graphics object obtained from my Bitmap my text looks terrible. It looks like it is anti-aliasing the text using black, not the bitmap's background color. I can avoid this problem if I use Graphics.DrawString(), but this method has horrible kerning problems. What should I do? How can I get TextRenderer.DrawText() to anti-alias properly using the Bitmap's contents?
Looks terrible:
Bitmap bmp = new Bitmap(100, 100, PixelFormat.Format32bppArgb);
using (Graphics g = Graphics.FromImage(bmp))
{
g.Clear(Color.Red);
TextFormatFlags tf = TextFormatFlags.Left;
TextRenderer.DrawText(g, @"C:\Development\Testing\blag", font, clip, Color.White, Color.Transparent, tf);
}
Looks good, but I want to render this onto a bitmap, NOT onto the control's surface:
protected override void OnPaintBackground(PaintEventArgs e)
{
e.Graphics.Clear(Color.Red);
TextFormatFlags tf = TextFormatFlags.Left;
TextRenderer.DrawText(e.Graphics, @"C:\Development\Testing\blag", font, clip, Color.White, Color.Transparent, tf);
}
What is the difference?
The answer is not to use
TextRenderer
. TextRenderer is a wrapper for the GDI (not GDI+) implementation of text rendering, which has lots of features, but doesn't interoperate well with in-memory DCs as you have discovered.Use
Graphics.DrawString
&Graphics.MeasureString
, but remember to pass it StringFormat.GenericTypographic to get accurate size and positioning.The reason TextRenderer was introduced initially was that GDI+ didn't support all the complex scripts that GDI's Uniscribe engine did. Over time however GDI+ support for complex scripts has been expanded, and these days there aren't any good reasons left to use TextRenderer (it's not even the faster of the two anymore, in fact quite the opposite it appears).
Really, though, unless you are running into serious, measurable performance issues just use
Graphics.DrawString
.If your bitmap is not the same size as your display area, it might just be a resizing issue, where .NET scales the bitmap to the display size and you get funny looking text.
Can you test with a bitmap created at the same size as your display area?
The answer is to use a
BuffersGraphicsContext
. This is the same system that .NET uses internally when you set theControlStyles.OptimizedDoubleBuffer
style on a control.See http://msdn.microsoft.com/en-us/library/b367a457.aspx for more information about double buffering in .NET.
I believe the problem is that the clear type text rendering doesn't work if the background is transparent. A few possible solutions.
Option 1. Fill the background of your bitmap with a color.
If you do this (as Tim Robinson did above in his code example by using g.Clear(Color.Red)) clear type will do the right thing. But your bitmap won't be completely transparent which might not be acceptable. If you use Graphics.MeasureText, you can fill just the rectangle around your text, if you like.
Option 2. Set TextRenderingHint = TextRenderingHintAntiAliasGridFit
This appears to turn off clear type. The text will be rendered at a lower quality than clear type on a background, but much better than the mess clear type on no background creates.
Option 3. Fill the text rectangle with white, draw the text and then find all the non-text pixels and put them back to transparent.
I know, it's a horrible hack, but it appears to work.
Another possible solution: Draw the whole thing to the screen, bitmap with text on top, and then write some code to 'screen capture' that portion of the screen. Not practical in all cases but you're right, DrawString creates weird text and DrawText onto a bitmap looks horrible.
Can you post the smallest program that suffers from this problem? I can't reproduce it like this -- the antialiasing looks fine: