WPF font quality - wpf

I'm developing a WPF app but I've noticed that at certain font sizes the text doesn't render as nicely as the samples you see in Control Panel -> Fonts. I'm using large Segoe UI fonts (FontSize="36"), and the effect is more noticeable on the upright lines, e.g. a letter "U" might be slightly thicker on one side than the other.
).
The font quality improves at certain font sizes, e.g. FontSize="48" (which I believe is the equivalent of 36pt), but using a limited number of font sizes isn't always practical.
I can improve the font quality by applying the following properties to the TextBlock:-
TextOptions.TextFormattingMode="Display" TextOptions.TextRenderingMode="ClearType"
Given the improvement in quality I'm curious to know why WPF doesn't do this for all text, or is it down to performance? I was thinking of creating a global style to apply this to all controls, or will this cause a problem?
(I tried uploading a screenshot but SO must store images at a low quality, and you couldn't really make out the font problem).

Here is the blog post that the WPF Text team wrote about this feature.
Note for the TextFormattingMode:
Ideal Ideal text metrics are the metrics which have been used to
format text since the introduction of WPF. These metrics result in
glyphs’ shapes maintaining high fidelity with their outlines from the
font file. The glyphs’ final placement is not taken into account when
creating glyph bitmaps or positioning the glyphs relative to each
other.
Display In this new formatting mode, WPF uses GDI
compatible text metrics. This ensures that every glyph has a width of
multiple whole pixels and is positioned on whole pixels. The use of
GDI compatible text metrics also means that glyph sizes and line
breaking is similar to GDI based frameworks. That said, glyph sizes
are not the only input into the line breaking algorithm used by WPF.
Even though we use the same metrics as GDI, our line breaking will not
be exactly the same.
Since these properties are new in .NET 4.0, they kept the original WPF algorithm as default, which is Ideal mode.
For the TextRenderingMode
Auto This mode will use ClearType unless system settings have been
set to specifically disable ClearType on the machine.
Aliased No antialiasing will be used to draw text.
Grayscale Grayscale antialiasing will be used to draw
text.
ClearType ClearType antialising will be used to draw text.
Since Auto is default, you will generally get ClearType rendering.
Now, because these are attached properties, and they inherit, you can just set them at the root Window. No need to create a bunch of Styles.

I have noticed small performance issues when dealing with large amounts of data (upwards of 10,000 items) when ClearType is turned on. Changing TextFormattingMode to Display has no visible performance impact.
This said, in all of my WPF apps I use global styles to improve text rendering, unless the performance impact is large enough to make the UI feel sticky.

Related

Cairo glyph caching

I'm using Cairo for text rendering on an embedded device. I've evaluated the 'toy' text API (i.e. cairo_show_text) and it works very well and is efficient. Unforunately it only supports the most basic operations and always discards the shape immediately.
What I need to do is draw simple text with fill and stroke. When I do this using the slightly more complicated API (cairo_text_path) it works but performance drops to unacceptable levels.
It's a bit difficult to find documentation but I did find this hint:
Be aware cairo_show_text() caches glyphs so is much more efficient if you work with a lot of text.
Where can I read about this glyph caching and how to it also for cairo_text_path? Ideally, is there a code example of this being done? I only need to support this simple use case.
cairo_text_path converts a text with all glyphs to a path and adds him to the context. Rendering this path is expensive because of many segments - dozens of moves, lines, curves for every single glyph.
Glyphs caching by cairo_show_text means that repeating glyphs/characters get rendered once and saved in a much cheaper format (like scanlines, triangles or bitmap) for later occurrences. Because the font doesn't change in-between, this recycling isn't a problem.
You could do this caching by yourself, rendering glyphs on image surfaces and using them as pattern, or simply use bitmap fonts from the beginning.

WinForms ToolStrip change font size automatically

I have a ToolStrip control docked to the top of a Windows Form. Throughout the program, I have the font sizes on controls not specified so that they inherit from the base form. That way I can set the font size larger when the user selects "Large Font Mode" and it automatically changes throughout. The ToolStrip seems completely unaffected by this and sticks to the default size.
Is there a way have the ToolStrip inherit the base font size? Or do I need to write something to go through and find all the ToolStrips and update their .Font property?
Picture for reference:
Little update - what led me down this road is that sales people got touch-capable 1080p 10" tablets running Win8. Before making any adjustments to the display settings, the ToolStrip was an impressive 3mm tall, very difficult for anyone with large hands to hit with any accuracy. The rest of the form was difficult to interact with too. Apple has suggested 7mm for touch targets, and even Microsoft suggests 9mm. Changing the settings in Control Panel > Display up to 160% resulted in touch targets of about 6.5mm, good enough to hit without making the rest of the form too big.

TextBlock inside a Viewbox - strange rendering

This is a question regarding a very simple construction - I have the following XAML:
<Viewbox Height="100" Stretch="Uniform">
<TextBlock FontFamily="Georgia">My Cool Text</TextBlock>
</Viewbox>
This is quite simple to understand. Yet when I start the program I get strange blurry text (there are no bitmap effects anywhere in my project).
(left side - the designer view in VS2010, right side - the running application)
Does anyone have ANY suggestions about why this is happening??
While Jefim has correctly answered his own question, I wanted to explain why you get this behaviour when using this particular set of features. Jefim suggests that this is a bug in WPF, but it's not. The problem arises as a result of asking for WPF to do something impossible. It has to pick a compromise when you've asked for this impossible thing, and the result is what you see above.
The explanation is a bit long for a comment, which is why I'm putting it in a separate answer.
This example uses two mutually contradictory features of WPF. Those features are:
The ability to render visuals consistently at any scale
The ability to render text in the same way GDI32 renders text
You can't use both features at once. GDI32 renders text in a way that cannot be scaled consistently: if a particular piece of text at a certain font size happens to be 200 pixels wide, if you multiply the font size by 3, and render the same text in the same font family at that new font size, in GDI32 it probably won't be 600 pixels - it'll be close, but it will typically not be quite right.
GDI32 messes with the shapes and widths of characters in order to enhance the clarity and sharpness of the text. Specifically, it bends letters out of shape so that their features align better with the pixels on your screen. And where necessary, it will adjust the width of individual characters to be an exact number of pixels wide. Since this letter bending is all based around actual pixels, it bends text in different ways at different font sizes.
While that gives you nice sharp looking text, it looks absolutely horrible if you try to change the scale gradually. If you try to animate the font size of some text rendered in this fashion, the thing will seem to shimmer and shudder, because the adjustments made in the name of clarity end up being slightly different at each font size. Even if you're not animating, it can still produce poor results - if you have a single typeface shown at a number of sizes, it can look quite different at each size; if your application has a zoom feature, the character of the text can seem to change significantly as you zoom in and out. (And so can the layout. If you use Microsoft Word, you may have noticed that you sometimes get odd-looking extra wide spaces between certain words. This is the result of Word fighting with GDI32 - Word attempts to keep the on-screen layout as close as possible to how things will look when printing, which means it sometimes clashes with GDI32's grid fitting.)
So WPF offers a different approach to text rendering: it can render text in a way that is as faithful as possible to the original design of the font. This distorts the text less, and it means that you don't get discontinuities as you scale.
The downside is that the text looks blurry, compared to how text rendered by GDI32 looks. (The distortions made by GDI32 are all aimed at improving clarity.)
So in WPF 4.0, Microsoft added the ability to render text in the way GDI32 would. That's what TextOptions.TextFormattingMode="Display" does.
By turning on that option, you are saying "I don't need consistent scaling, and I'd prefer clarity, so generate the same pixels you would have done in GDI32." If you then go on to apply scaling, having told WPF you didn't need scalability, you get crappy results. WPF carefully generated a bitmap representation of the text exactly to your specifications, and you then told it to render that text at a different scale. And so it looks like what it is: a scaled bitmap of some text that was generated for a different resolution.
You could argue that WPF could do something different here: if you apply a scale transform in GDI32 you'd see different behaviour - you'd see the inconsistency at different scales described earlier. If you really want that effect in WPF you can get it by modifying the font size directly. But WPF doesn't prioritise getting that same effect - its goals are to make it possible to get GDI32-style crisp text when you really need it, and to provide consistent scaling by default.
And what you're running into here is the "consistent scaling". Turning on GDI32-style text rendering doesn't break consistent scaling: applying a scale factor (either directly, via a ScaleTransform or indirectly via a Viewbox) will change the dimensions of the visual by exactly the specified scale factor. If it were to re-generate the text visuals by grid fitting to the newly scaled size, the text would come out at a different width. That would actually cause the Viewbox problems: it applies a scale factor based on the content's natural size, designed to make it fit the available space. But if it re-did the grid fit after scaling, that would actually change the width. Because of the inconsistencies inherent in how GDI32 text rendering works, it might not even be possible for the ViewBox to find a suitable scale - it's possible to come up with a piece of text which, when rendered in a particular font, will never come out at 200 pixels wide. For some font sizes, the rounding inherent in grid fitting might bump the size down to, say, 198, and it might stick at that as you make tiny increments in the font size, until you go past some threshold at which point it might jump to 202 pixels.
For a Viewbox attempting to force the text to fit into exactly 200 pixels, that would be a problem. But Viewbox doesn't work that way - it uses WPF's consistent scaling, downstream of the point at which you chose the font size to which GDI32-style text rendering is working. So Viewbox will always be able to do what it is designed to do, but that is task that's fundamentally incompatible with GDI32-style text rendering.
So in short, WPF renders the text for the font size you requested, and then scales the result.
So you have to pick just one feature - you can't have both because that's simply impossible. Either don't attempt to render text in a context in which an arbitrary scale factor may be applied (e.g. Viewbox) or don't turn on GDI32-style text rendering. Otherwise, you get that weird pixelated text that you've encountered.
Ok, bug found. My Window style has the following setter:
<Setter Property="TextOptions.TextFormattingMode" Value="Display"/>
If I set it back to "Ideal" (which is the default value) then it renders the text inside the viewbox correctly. I would say that this is a bug inside WPF. Basically, if you try this:
<Viewbox Height="100" Stretch="Uniform" TextOptions.TextFormattingMode="Display">
<TextBlock FontFamily="Georgia">My Cool Text</TextBlock>
</Viewbox>
You will get the same result as in my initial picture.

Silverlight 3: Techniques for adjusting to screen resolution

My developer's box has a screen resolution of 1680 x 1050. I'm developing a full-screen Silverlight 3 application that I'm considering deploying to the Internet. So, I want to make sure the application looks good on a variety of screen resolutions. I just started testing on other boxes, the first one having a screen resolution of 1024 x 768. During the test I found some of the pages on the application were partially truncated. It seems the controls on the page didn't adjust for the lower screen resolution. So, I'm looking for some tips on how to make a Silverlight application, to the extent possible, adjust for screen resolution. For example, are there things one should or should not do on XAML to make adapting to screen resolution easier? Should I just optimize for a minimum screen resolution? Your thoughts and suggestions are welcomed.
You can easily enforce a minimum acceptable resolution by setting the MinHeight and MinWidth properties of your root visual. (Of course, this should be less than the minimum screen resolution to account for browser chrome.)
Try to specify absolute Width and Height only when necessary: for example, for images or icons of fixed dimensions, or for obvious cases like TextBoxes (whose width should reflect the average length of the data entered).
Grid panels are excellent for mixing scalable and fixed layout areas. The star sizing specification takes a bit of getting used to--it's not as simple as a percentage-based proportioning--but it's much more flexible, especially in combination with row/column min/max dimensions.
You don't really need to test on multiple resolutions unless you're interested in testing a range of dots per inch--just resize the browser to approximate different screens. Since there's always a bit of give and take depending on the user's browser configuration, you'll have to account for some variance anyway.
You can make your application scale with the Silverlight Toolkit ViewBox or make it strech with layout controls like the Grid, StackPanel, and WrapPanel. Make your main UserControl have a Width and Height of Auto (or remove the width and height entirely) and the size of the app will resize to the size of the parent div (the default HTML template uses 100%x100%). Then just resize the browser accordingly. IE8 has developer tools that can help you see your app resized to specific screen resolutions.
Testing on a variety of screen resolutions is always a good idea.
I covered the resizing of elements and making it resolution independent on another thread.
You can have a look here, there are multiple ways to sizing and resizing things automatically.

Why everything in WPF is blurry?

Can someone explain why everything in WPF is blurry? Is this something that can be fixed?
The reason for this is the anti-aliasing system which spreads the line over multiple pixels if it doesn't align with physical device pixels.
WPF is resoultion independent. This means you specify the size of an user interface element in inches, not in pixels. A logical unit in WPF is 1/96 of an inch. This scale is chosen, because most screens have a resolution of 96dpi. So in most cases 1 logical unit matches to 1 physical pixel. But if the screen resolution changes, this rule is no longer valid.
All WPF controls provide a property SnapsToDevicePixels. If set to true, the control ensures the all edges are drawn excactly on physical device pixels. But unfortunately this feature is only available on control level.
Source: Draw lines excactly on physical device pixels
Quick Fix:
Use these options on every Container from root to your blurry control
UseLayoutRounding="True"
RenderOptions.BitmapScalingMode="NearestNeighbor"
SnapsToDevicePixels="True"
RenderOptions.ClearTypeHint="Enabled"
Explanation:
UseLayoutRounding=true fixes subpixel layout problems. They often occur because e.g. Effects resize controls to be something between pixels.
RenderOptions.BitmapScalingMode=NearestNeighbor fixes blurry sampling of bitmaps. Bitmaps are used when effects or other techniques are used. When they are reapplied to the container or control they might end up inbetween pixels and therefore interpolate the pixels of the bitmap.
SnapsToDevicePixels="True" fixes vertical and horizontal polygons, lines and rectangles being rendered inbetween pixels
RenderOptions.ClearTypeHint="Enabled" reenables cleartype on text. It is disabled very easily by effects or whenever the renderer does not know the exact background of a text.
You should use it on every Container because sometimes, e.g. by data templates these options are defaulted again for the sub controls.
I spent a couple of hours trying to figure out the cause of the blurriness on custom panels. On these custom panels we are using a drop shadow border effect. The drop shadow was the culprit. It actually causes blurry text if the panels are placed side by side. I don't have a high enough reputation to make a comment so I am answering the question.
UseLayoutRounding="True"
was the fix for my problems as answered by ecreif. although I did not need the other lines of code in his answer, I added them anyways.
The following worked for us when facing similar issue:-
Right Click and open the Properties Window for the executable.
Under "Compatibility" tab, click on "Change High DPI Settings" button then check the "Override High DPI scaling behavior" checkbox at "Application" drop-down selection.
Click on Apply/Ok buttons to save the settings then relaunch app.
P.S.: These settings could be deployed to User system via Windows Registry entry.

Resources