Archives
-
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
ComboBox
for 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
#0987c3
. - The color picker in Photoshop tells me that the color of most icon pixels is… also
#0987c3
!
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.TextFormattingMode
andTextOptions.TextRenderingMode
. You apply them directly on an element, e.g., aTextBlock
or set them on a window.TextOptions.TextFormattingMode
The property
TextOptions.TextFormattingMode
can be set toDisplay
orIdeal
(which is the default).- With
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. - With
Display
, the text rendering favors of aligning letters to pixels. This is especially important for small text on normal density screens.
TextOptions.TextRenderingMode
The property
TextOptions.TextRenderingMode
controls the way rendered text will be anti-aliased. Possible values areAliased
(which we will see can be confusing),Auto
(the default),ClearType
, andGrayscale
.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):
Display
Aliased
Display
Auto
Display
ClearType
Display
Grayscale
Ideal
Aliased
Ideal
Auto
Ideal
ClearType
Ideal
Grayscale
So many options…
In a first round, I eliminated:
Display
&Aliased
(no anti-aliasing),Ideal
&ClearType
(the combination that caused me to write this article in the first place),Ideal
&Auto
(which in my simple scenario looks the same asIdeal
&ClearType
), andDisplay
&ClearType
(even though it looks better thanIdeal
&ClearType
)
Which left me with the following options:
Display
Grayscale
Ideal
Aliased
Ideal
Grayscale
In the end, I decided to use
Ideal
&Aliased
because 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 withIdeal
, the settingAliased
is actually anti-aliased…I set
TextOptions.TextFormattingMode="Display"
on my application window but did not specifyTextOptions.TextRenderingMode
there.For the dropdown list, I set
TextOptions.TextFormattingMode="Ideal"
andTextOptions.TextRenderingMode="Aliased"
on theContentPresenter
of 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
Display
&Grayscale
andIdeal
&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:
Display
Grayscale
Ideal
Grayscale
Note the way the “m” is rendered and how more vertical lines are aligned to full pixels in
Display
mode.A good example for small sample sizes leading to wrong conclusions…
- The XAML says the text color is