It’s been a while since I’ve done anything with GDI+ (i.e. System.Drawing). System.Windows (i.e. WPF) is so much more powerful.
However, there’s one area where it seems the good old GDI+ can still surpass it’s shiny new successor: text.
There have been many complaints about text rendering in WPF. I wrote about some of them myself. You can find a lot of questions on the WPF forum (to name a few), but not a lot of answers.
The main issue is that small text is blurry and unreadable. When asked how to render aliased text in WPF, the answer was: it’s impossible. However, I recently encountered a whitepaper on windowsclient.net called “Text Clarity in WPF“, which suggests a way to do just that. It’s worth a read, even though the aliased text solution provided there is not usable (they use FormattedText, convert it to a Geometry and render the Geometry aliased using RenderOptions.SetEdgeMode() – which indeed renders aliased text, but it’s not quite legible.)
As you may have already guessed, my solution – GdiTextBlock – relies on GDI+. We render a bitmap that contains the text and display it. As you may know, rendering bitmaps in WPF also has it’s problems, which is why I use the Bitmap control in order to prevent bitmaps from becoming blurry as well.
Also, in order to maintain compatibility with WPF’s TextBlock, and to avoid forcing the consumers of the control to add a reference to the System.Drawing assembly, the properties and their types are all the same as TextBlock’s (in fact, the dependency properties are registered using DependencyProperty.AddOwner(), which also ensures that value inheritance down the visual tree works.) CoerceValueCallback is used in many places since GDI+ doesn’t support all the options available in WPF (e.g. FontStyles.Oblique, non-solid Foreground, TextAlignment.Justify.) While I’ve included a property called TextQuality, which allows you to set the TextRenderingHint, you’ll see that only the default (SingleBitPerPixelGridFit) provides legible results.
One last note about performance – this solution is not quite optimal. It creates a bitmap every measure pass. I haven’t done any real performance tests, so I can’t tell you what the real penalty is. Use it at your own discretion.
Update: Fixed a small bug and added size and color selectors to demo app.
Another Update: Fixed a leak when using InteropBitmap. See this post.
Attachment: GdiTextBlock.zip
One Response to Good Old GDI+ (or: Unblur Thy Text)
Tags
.NET 4 Animation AppFabric Async Axum Blog C# ClearType Cloud CLR CodeValue Contests Deep Zoom Experiments Generics Google Ink Lectures Modeling Performance Personal Pivot Prism Programming Languages Prolog Reflector RTL Sela Silverlight The Arbel Network Themes Threading Tips Visual Studio WCF Windows 7 Windows 2003 Windows Azure Windows Forms Windows Phone Windows Vista Windows XP WPF XAML ZuneArchives
- May 2013
- February 2013
- June 2012
- May 2012
- June 2011
- November 2010
- August 2010
- July 2010
- June 2010
- March 2010
- December 2009
- November 2009
- February 2009
- January 2009
- December 2008
- November 2008
- October 2008
- September 2008
- August 2008
- November 2007
- September 2007
- June 2007
- May 2007
- February 2007
- November 2006
- October 2006
- February 2006
- August 2005
- February 2005
- August 2004
- July 2004
- June 2004
- May 2004






I've been using InteropBitmap in my GdiTextBlock . The control creates a new GDI+ Bitmap every measure