即使启用了ClearTypeHinting,WPF 中的文本仍然模糊?

7

我在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>

当您选择网格行时,DropShadowEffect 会导致文本渲染模糊(灰色抗锯齿)。

enter image description here

当我移除投影效果时,它看起来更清晰,因为现在使用了ClearType而不是灰色亚像素抗锯齿。

enter image description here

我尝试将RenderOptions.ClearTypeHint="Enabled"应用于上面所见的ContentPresenter,但没有效果。
如何强制WPF以Cleartype抗锯齿方式渲染显示的具有阴影效果的文本,而不是那种丑陋的模糊灰色亚像素抗锯齿?
一些人认为这是由于阴影导致的模糊--这不是真的。它之所以模糊,仅因为未使用ClearType。下面是在Firefox中同时使用阴影和ClearType时的外观:

enter image description here

清晰类型(ClearType)启用的文本是彩色的,但模糊的文本不是,因为它不使用清晰类型,而是使用灰色次像素抗锯齿,这不是清晰类型的工作方式:http://en.wikipedia.org/wiki/ClearType 问题是:我如何为此文本启用清晰类型?

在我眼里,看起来模糊是因为投影效果,而不是抗锯齿风格。 - Cody Gray
@CodyGray 抱歉,但您是错误的。 :) 这是因为没有使用ClearType而导致模糊。 - Tower
嗯...你能告诉我我的答案哪里有问题吗? - Justin XL
吹毛求疵:我想指出文本阴影渲染只是标准的抗锯齿,就像在Mac和Linux操作系统上使用的那样。它并没有什么“亚像素”的特点。使ClearType特殊(并且如此丰富多彩)的是它使用了亚像素渲染技术。 - Isabelle Wedin
6个回答

14

你可以尝试将TextOptions.TextFormattingMode设置为Display并将RenderOptions.BitmapScalingMode设置为NearestNeighbor,这样呈现的效果可能会更好。后者是WPF 3.5 SP1新引入的选项,我通常使用它来消除模糊。

<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>

以下是它的外观。

输入图像描述

这是在 FireFox 中的外观。

输入图像描述


仍然有点模糊,虽然比之前好了一些。我得出结论,没有解决方案。解决方法看起来或好或坏,这取决于显示器和可能还有其他因素。 - Tower
真的吗?从上面的截图来看,第一张图片对我来说看起来非常清晰...我甚至尝试了几个显示器(好的和坏的),它们都看起来相当清晰... - Justin XL
这是它的外观(直接复制粘贴后):http://d.pr/i/29CC 在你的截图和我的截图中,ClearType都没有被激活。由于某种原因,在你的电脑上,无ClearType的文本质量更好。在我的电脑上,任何无ClearType的文本都很混乱。然而,Firefox使用ClearType,一切看起来都很清晰。我选择了回答“不可能”,因为我得出结论,在WPF 4中不可能实现。我希望这会改变。 - Tower
这是一个截图:http://d.pr/i/QXsL(一旦我去掉效果,奇怪的模糊就会消失)。 - Tower
我刚刚注意到的一件事是,实际上是这个 TextOptions.TextRenderingMode="ClearType" 给了文本 ClearType,但我猜你可能已经尝试过了?另外一件我发现的事情是,在我的 Expression Blend 设计师视图中,TextBlock 看起来有点模糊,就像你的截图一样,但当我运行应用程序时它看起来很好。我想知道这是否可能是电脑设置问题? - Justin XL

6

根据MSDN页面创建带有阴影的文本DropShadowEffect对象无法与ClearType一起使用。

这些阴影效果不会通过Windows Presentation Foundation(WPF)文本呈现管道。因此,使用这些效果时将禁用ClearType。

毕竟,DropShadowEffect是位图效果,而不是文本效果。


那么,您是说我无法在 WPF 中实现诸如文本阴影这样的简单事情吗?我们在 CSS 中的网页浏览器中都有 text-shadow: 1px 1px 1px #000 吗?您确定没有任何解决方法吗? - Tower
@rFactor:我不知道在WPF中产生文本阴影的其他替代方法。但是可能有其他人知道。Firefox可能已经实现了专门针对HTML和CSS的图形引擎。他们可以通过首先使用模糊位图效果在文本上绘制阴影,然后启用ClearType再次绘制文本来实现该效果。 - Codo
@rFactor:这里可能的解决方法是将文本渲染两次,一次为黑色,稍微偏移一下。 - Kent Boogaart
@KentBoogaart 这个要怎么做呢?如果这个能行,我会给你一个温暖的拥抱。 - Tower
有人尝试过使用TranslateTransform吗?虽然有点麻烦,但可能会起作用。 - Pieter

4
为了在不使用效果的情况下实现类似的效果,您可以将文本渲染两次,每次略微偏移:
<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>

这将产生所期望的结果: enter image description here enter image description here 你还可以将其封装成一个控件(称为ShadowTextBlock, 或许),这样你就不必在每个地方都重复自己。

我认为它看起来相当粗糙,有什么方法可以使它变得清晰和平滑?并且,如何在使用ContentPresenter时做到这一点,因为你不能“复制”它? - Tower
@rFactor:尝试调整颜色。将黑色改为灰色可以降低对比度。 - Kent Boogaart
无论我如何调整它,它总是看起来很糟糕。这是一个好的展示(请尝试使用Firefox):http://jsfiddle.net/kaisellgren/2YEer/1/ - Tower

3

将两个想法结合起来怎么样?使用 DropShadowEffect 绘制文本,并在其上叠加相同的文本,不应用效果,就像这里第三行所示:

text

还不完美,而且我觉得有点粗体。但或许你可以接受。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>

2
这个问题无法解决,因为ClearType对其渲染的内容非常敏感。为了让ClearType看起来正确,它需要进行每个组件的alpha混合,这意味着红色、绿色和蓝色必须有单独的alpha值(通常alpha适用于所有三种颜色)。这意味着ClearType必须绘制在一个不透明的位图中(所有alpha值都为255)(您会注意到窗口标题栏仍然使用ClearType,但它们使用一些超级秘密技巧来实现)。
理解这一点的下一步是,WPF效果首先渲染到屏幕外的位图中,然后与下面的内容结合(在本例中,是纯白色或蓝色如果被选中)。
因此,文本首先被渲染到一个清晰、透明的位图中。由于它不知道最终会在它下面,所以它必须使用灰度而不是ClearType进行渲染。然后,将效果应用于该位图。然后将位图绘制到屏幕上,即使它位于没有透明度的纯色之上,也不可能得到ClearType。
作为一个可能的解决方法,尝试使用两个文本副本。首先,将效果应用于“较低”版本的文本(通过“较低”,我是指它应该具有较低的Z索引值,并且如果它在XAML中是“第一个”,那就是这种情况)。然后,在其上方绘制正常文本(将获得ClearType)。我认为这会起作用,但我还没有尝试过,您可能需要进行实验,直到获得所需的视觉效果。

所以我猜这就解释了为什么即使是带有阴影的 Border 对象也会“破坏”其中的文本。虽然它并不总是这样,这很奇怪。 - Simon_Weaver

1
我知道这篇文章很旧,但如果有人遇到模糊文本的问题,边框阴影可能是罪魁祸首。我有自定义面板带有投影,只有当面板并排放置时文本才会变得模糊。我从这个为什么WPF中的所有内容都是模糊的?帖子中找到了答案。对我来说,解决方案是ecreif的回答而不是被接受的答案。将此添加到您的控件中。
    UseLayoutRounding="True"
    RenderOptions.BitmapScalingMode="NearestNeighbor"
    SnapsToDevicePixels="True
    RenderOptions.ClearTypeHint="Enabled"

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接