WPF, Text Rendering and the Blues
I am currently working on a small webcam utility written in C#/WPF that I intend to release as freeware later this year.
On the main window, I use a
ComboBoxfor selecting a webcam in a dropdown list, with the toggle button of the control styled to look like a heading:
When you move the mouse pointer over the toggle button, the text and the glyph turn blue – nothing special.
The application does not have a main menu, only a settings menu that you open by clicking a gear icon:
The icon also turns blue when the pointer hovers over the general area:
But wait a second… is this the same blue? A quick check:
- The XAML says the text color is
- The color picker in Photoshop tells me that the color of most icon pixels is… also
What is going on?
On a screenshot zoomed to 300%, the gear icon looks like this:
And this is the text at 300% size:
The colored pixels to the left and the right of the characters are caused by ClearType. You will also notice that many pixels “inside” the character shapes also have a different color. This is because less pixels than one might expect are fully covered in blue – which means that more pixels have their color modified by ClearType.
What did I do wrong?
It is not what I did do, but what I did not do. I did not tweak WPF’s text rendering to suit my needs. Which sounds curious, because writing a desktop application that looks good at typical application font sizes is not exactly an exotic usage scenario.
When WPF was developed, it was designed to be device-independent and ready for a future of high pixel density displays (“HiDPI”). So WPF rendered text exactly as specified by the font metrics, which on normal density displays led to blurry characters. It took until .NET 4 for WPF to offer a way to render small text with an emphasis on readability instead of correctness (read this old article by Scott Hanselman for a look way back in time).
What to do
As a WPF developer, you can influence the text rendering by using the attached properties
TextOptions.TextRenderingMode. You apply them directly on an element, e.g., a
TextBlockor set them on a window.
TextOptions.TextFormattingModecan be set to
Ideal(which is the default).
Ideal, text is rendered according to the font's metrics. Which is fine for large text, but not so much for small text on a non-HiDPI display.
Display, the text rendering favors of aligning letters to pixels. This is especially important for small text on normal density screens.
TextOptions.TextRenderingModecontrols the way rendered text will be anti-aliased. Possible values are
Aliased(which we will see can be confusing),
To show off the possible combinations, I placed the gear icon directly in front of the text (where it does not make any sense, just for comparing colors):
So many options…
In a first round, I eliminated:
ClearType(the combination that caused me to write this article in the first place),
Auto(which in my simple scenario looks the same as
ClearType(even though it looks better than
Which left me with the following options:
In the end, I decided to use
Aliasedbecause I wanted the bolder text without a larger font size. And Segoe UI in “real” bold does not look good at this font size. Interesting that with
Ideal, the setting
Aliasedis actually anti-aliased…
TextOptions.TextFormattingMode="Display"on my application window but did not specify
For the dropdown list, I set
ContentPresenterof the toggle button.
A note on “Display” vs. “Ideal” used with “Grayscale”
While writing this blog post, I had to juggle a larger number of image files than usual. When I saw the letter “P” in the enlarged versions of
Grayscale, I first suspected I had mixed up the screenshots. But that was not the case; it is just a coincidence that the “H” and the “P” look sharper.
This becomes clear when you look at a different text:
Note the way the “m” is rendered and how more vertical lines are aligned to full pixels in
A good example for small sample sizes leading to wrong conclusions…
- The XAML says the text color is