Blurry text in WPF even with ClearTypeHinting enabled?
Asked Answered
C

6

7

I have a grid with this template and styles in WPF/XAML:

<Setter Property="TextOptions.TextFormattingMode" Value="Display" />
<Setter Property="RenderOptions.ClearTypeHint" Value="Enabled" />
<Setter Property="Template">
    <Setter.Value>
        <ControlTemplate TargetType="{x:Type DataGridCell}">
            <Border Padding="{TemplateBinding Padding}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
                <ContentPresenter x:Name="CellContent" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" RenderOptions.ClearTypeHint="Enabled" />
            </Border>
            <ControlTemplate.Triggers>
                <Trigger Property="IsSelected" Value="True">
                    <Setter TargetName="CellContent" Property="TextOptions.TextFormattingMode" Value="Display" />
                    <Setter TargetName="CellContent" Property="RenderOptions.ClearTypeHint" Value="Enabled" />
                    <Setter TargetName="CellContent" Property="Effect">
                        <Setter.Value>
                            <DropShadowEffect ShadowDepth="2" BlurRadius="2" Color="Black" RenderingBias="Quality" />
                        </Setter.Value>
                    </Setter>
                </Trigger>
            </ControlTemplate.Triggers>
        </ControlTemplate>
    </Setter.Value>
</Setter>

The DropShadowEffect I have when you select a grid row, seems to make the text rendering blurry (gray anti-aliasing):

enter image description here

When I remove the drop shadow effect, it looks clear because it now uses ClearType and not gray sub-pixel anti-aliasing:

enter image description here

I have tried applying RenderOptions.ClearTypeHint="Enabled" to the ContentPresenter as seen above, but it does not help.

How do I force WPF to render the text that gets displayed with drop shadow effect to retain Cleartype anti-aliasing, instead of that ugly blurry gray sub-pixel anti-aliasing?

Some believe it's blurry because of the drop shadow -- this is not true. It's blurry only because ClearType is not used. This is how it looks like in Firefox when shadow AND ClearType:

enter image description here

ClearType enabled text is colorful -- but that blurry text is not, because it does not use ClearType -- it uses gray sub-pixel anti-aliasing and that's not how ClearType works: http://en.wikipedia.org/wiki/ClearType

The question is: how do I enable ClearType for this text?

Cormick answered 15/4, 2012 at 10:26 Comment(4)
To my eyes, it looks blurry because of the drop-shadow effect, not because of the anti-aliasing style.Spevek
@CodyGray Sorry, but you are wrong. :) It's blurry because ClearType is not being used.Cormick
Hmm... Can you tell me what's wrong with my answer?Sneaker
Pedantry: I wanted to point out that the text shadow rendering is just standard anti-aliasing, like that used on Mac and Linux OS. There's nothing "sub-pixel" about it. What makes ClearType special (and so colorful) is that it uses sub-pixel rendering.Rhetorical
F
6

The DropShadowEffect object cannot work with ClearType. This is stated on the MSDN page How to: Create Text with a Shadow:

These shadow effects do not go through the Windows Presentation Foundation (WPF) text rendering pipeline. As a result, ClearType is disabled when using these effects.

After all, DropShadowEffect is a bitmap effect, not a text effect.

Furious answered 15/4, 2012 at 11:24 Comment(5)
So, are you saying I can't achieve a simple thing such as text shadow in WPF? Something we have in web browsers in CSS text-shadow: 1px 1px 1px #000? Are you sure there's no way around this?Cormick
@rFactor: I don't know of any alternative way of producing a text shadow in WPF. But somebody else might. Firefox has probably implemented a graphics engine specifically tailored for HTML and CSS. They could have implement the effect by first drawing the shadow using a blur bitmap effect on the text and then drawing the text a second time with ClearType enabled.Furious
@rFactor: a probable workaround here is to render the text twice, once in black slightly offset from the other.Howlet
@KentBoogaart how would this go exactly? I'll give you a warm hug if this works.Cormick
Has anybody tried using a TranslateTransform instead? It's a bit of a hassle but it might work.Katerinekates
S
14

How about setting TextOptions.TextFormattingMode to Display as well as RenderOptions.BitmapScalingMode to NearestNeighbor? The latter is new in WPF 3.5 SP1 and I normally use it to remove the blur. :)

<TextBlock Text="Hello world" TextOptions.TextFormattingMode="Display"
           RenderOptions.BitmapScalingMode="NearestNeighbor"
           HorizontalAlignment="Center" TextWrapping="Wrap"
           VerticalAlignment="Center" Foreground="White" FontFamily="Microsoft Sans Serif">
    <TextBlock.Effect>
        <DropShadowEffect ShadowDepth="2" BlurRadius="2" Color="Black"
                          RenderingBias="Quality"/>
    </TextBlock.Effect>
</TextBlock>

Below is how it looks like.

enter image description here

And this is how it looks like in FireFox.

enter image description here

Sneaker answered 21/4, 2012 at 14:17 Comment(5)
Still slightly blurry, although better. I've come to conclusion that there's no solution. Workarounds look slightly better or worse, depending on monitor and probably something else too.Cormick
Really? From the screenshots above, the first one just looks crystal clear to me... I even tried a few monitors (good and bad ones), they all look pretty clear...Sneaker
This is how it looks (after direct copy and paste): d.pr/i/29CC both in your screenshot and mine, ClearType is not activated. For some reason on your computer it ClearType-less resulted in better quality. On my PC any ClearType-less text is mess. Firefox however uses ClearType and everything looks sharp. I chose the answer that said "it's not possible", because I've come to the conclusion that it's not possible with WPF 4. I'll hope this changes.Cormick
Here's a screenshot: d.pr/i/QXsL (the weird fuzziness goes away as soon as I take away the effect).Cormick
One thing I just noticed is, it's actually this TextOptions.TextRenderingMode="ClearType" that gives the text ClearType, but I guess you might have already tried this too? Another thing I've found is, the TextBlock in my expression blend designer view looks a bit fuzzy just like your screenshot, but when I run the app it looks fine. I wonder could this be a computer setting issue?Sneaker
F
6

The DropShadowEffect object cannot work with ClearType. This is stated on the MSDN page How to: Create Text with a Shadow:

These shadow effects do not go through the Windows Presentation Foundation (WPF) text rendering pipeline. As a result, ClearType is disabled when using these effects.

After all, DropShadowEffect is a bitmap effect, not a text effect.

Furious answered 15/4, 2012 at 11:24 Comment(5)
So, are you saying I can't achieve a simple thing such as text shadow in WPF? Something we have in web browsers in CSS text-shadow: 1px 1px 1px #000? Are you sure there's no way around this?Cormick
@rFactor: I don't know of any alternative way of producing a text shadow in WPF. But somebody else might. Firefox has probably implemented a graphics engine specifically tailored for HTML and CSS. They could have implement the effect by first drawing the shadow using a blur bitmap effect on the text and then drawing the text a second time with ClearType enabled.Furious
@rFactor: a probable workaround here is to render the text twice, once in black slightly offset from the other.Howlet
@KentBoogaart how would this go exactly? I'll give you a warm hug if this works.Cormick
Has anybody tried using a TranslateTransform instead? It's a bit of a hassle but it might work.Katerinekates
H
4

To achieve a similar result without using an effect, you can render the text twice, once slightly offset from the other:

<Grid>
    <TextBlock Text="Here is some sample text" Foreground="Black" Margin="1,1,0,0"/>
    <TextBlock Text="Here is some sample text" Foreground="White"/>
</Grid>

This yields the desired result:

enter image description here

enter image description here

You could also encapsulate this into a control (called ShadowTextBlock, perhaps) so that you don't have to go repeating yourself everywhere.

Howlet answered 15/4, 2012 at 16:25 Comment(3)
I think it looks rather jaggy, any way to make it crisp and smooth? And how do you do this with ContentPresenter as you can't "duplicate" it?Cormick
@rFactor: try playing with the colors. A gray instead of black would reduce the contrast.Howlet
No matter how I try to adjust it, it always looks bad. This is an example how good it can look (Try Firefox): jsfiddle.net/kaisellgren/2YEer/1Cormick
P
3

What about combining the two ideas. Draw the text with DropShadowEffect, and overlay it with the same text drawn without effect, like shown in the third line here:

text

Still not perfect, and i find it a little bold. But perhaps something you could live with. The XAML:

<StackPanel Background="LightSteelBlue" RenderOptions.ClearTypeHint="Enabled" SnapsToDevicePixels="True" >
    <Grid Margin="5">
        <TextBlock Foreground="Black" Text="Here is some sample text" Margin="1"/>
        <TextBlock Foreground="White" Text="Here is some sample text"/>
    </Grid>
    <TextBlock Margin="5" Foreground="White" Text="Here is some sample text">
        <TextBlock.Effect>
            <DropShadowEffect ShadowDepth="2" BlurRadius="2" Color="Black" RenderingBias="Quality"/>
        </TextBlock.Effect>
    </TextBlock>
    <Grid Margin="5">
        <TextBlock Foreground="White" Text="Here is some sample text">
            <TextBlock.Effect>
                <DropShadowEffect ShadowDepth="2" BlurRadius="2" Color="Black" RenderingBias="Quality"/>
            </TextBlock.Effect>
        </TextBlock>
        <TextBlock Foreground="White" Text="Here is some sample text"/>
    </Grid>
</StackPanel>
Pamphylia answered 19/4, 2012 at 20:49 Comment(0)
G
2

The reason this doesn't work, and the reason you won't be able to get it to work, has to do with ClearType's sensitivity to what it's rendering on top of. For ClearType to look correct it essentially needs to do per-component alpha blending. That is, a separate alpha value for red, green, and blue (normally alpha applies to all 3). What this means is that ClearType absolutely must be rendered into a bitmap that is already opaque (all alpha values are 255) (you'll notice that window title bars still have ClearType, but they use some super secret tricks to do this).

The next step to understanding this is that WPF effects first render into an off-screen bitmap, and are then combined with what's beneath (in this case, solid white, or maybe blue if it's selected).

So, the text is first rendered into a clear, transparent bitmap. Since it has no idea what will eventually be below it, it must render using grayscale instead of ClearType. Then, the effect is applied to that bitmap. Then the bitmap is drawn to where you expect it to be on-screen, and there's no chance of getting ClearType even if it's on top of a solid color with no transparency.

As a possible workaround, try using 2 copies of the text. First, apply the effect to the "lower" version of the text (by "lower" I mean it should have a lower Z-index value, and that is the case if it is "first" in the XAML). Then, draw normal text on top of it (which will get ClearType). I think this will work but I haven't tried it, and you'll probably have to experiment until you get the desired visual outcome.

Gentlewoman answered 25/4, 2012 at 21:5 Comment(1)
so I guess this explains why even a Border object with a dropshadow 'breaks' text inside. although it doesn't always which is weirdImprecation
B
1

I know this post is old but if anyone is having problems with blurry text, a border drop shadow could be the culprit. I have custom panels with a drop shadow and only when the panels were placed side by side was the text blurry. I found the answer from this Why everything in WPF is blurry? post. The solution for me was ecreif's answer and not the accepted answer. Add this to your control

    UseLayoutRounding="True"
    RenderOptions.BitmapScalingMode="NearestNeighbor"
    SnapsToDevicePixels="True
    RenderOptions.ClearTypeHint="Enabled"
Bracknell answered 12/7, 2019 at 16:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.