9

这是一个关于一个非常简单的构造的问题 - 我有以下 XAML:

    <Viewbox Height="100" Stretch="Uniform">
        <TextBlock FontFamily="Georgia">My Cool Text</TextBlock>
    </Viewbox>

这很容易理解。然而,当我启动程序时,我得到了奇怪的模糊文本(我的项目中没有任何位图效果)。替代文字

(左侧 - VS2010 中的设计器视图,右侧 - 正在运行的应用程序)

有人对为什么会发生这种情况有任何建议吗?

4

2 回答 2

29

虽然 Jefim 已经正确回答了他自己的问题,但我想解释一下为什么在使用这组特定功能时会出现这种行为。Jefim 认为这是 WPF 中的一个错误,但事实并非如此。问题是由于要求 WPF 做一些不可能的事情而出现的。当你要求这个不可能的事情时,它必须选择妥协,结果就是你在上面看到的。

评论的解释有点长,这就是为什么我将它放在单独的答案中。

这个例子使用了 WPF 的两个相互矛盾的特性。这些特点是:

  1. 能够以任何比例一致地呈现视觉效果
  2. 以与 GDI32 呈现文本相同的方式呈现文本的能力

您不能同时使用这两个功能。GDI32 以无法一致缩放的方式呈现文本:如果特定字体大小的特定文本恰好是 200 像素宽,如果将字体大小乘以 3,并在同一字体系列中呈现相同的文本新的字体大小,在 GDI32 中它可能不会是 600 像素 - 它会接近,但通常不会完全正确。

GDI32 会混淆字符的形状和宽度,以提高文本的清晰度和清晰度。具体来说,它会使字母变形,以便它们的特征与屏幕上的像素更好地对齐。必要时,它会将单个字符的宽度调整为精确的像素宽度。由于此字母弯曲完全基于实际像素,因此它以不同的字体大小以不同的方式弯曲文本。

虽然这会给您提供漂亮清晰的文本,但如果您尝试逐渐更改比例,它看起来绝对可怕。如果您尝试对以这种方式呈现的某些文本的字体大小进行动画处理,那么事情似乎会闪烁和颤抖,因为以清晰度为名所做的调整最终会在每种字体大小上略有不同。即使你没有制作动画,它仍然会产生很差的结果——如果你有一个字体以多种尺寸显示,那么在每种尺寸下它看起来可能会有很大的不同;如果您的应用程序具有缩放功能,则文本的字符在您放大和缩小时似乎会发生显着变化。(布局也可以。如果您使用 Microsoft Word,您可能已经注意到有时在某些单词之间会出现看起来很奇怪的超宽空格。

因此 WPF 提供了一种不同的文本渲染方法:它可以以尽可能忠实于字体原始设计的方式渲染文本。这会减少文本的扭曲,这意味着您在缩放时不会出现不连续性。

缺点是文本看起来模糊,与 GDI32 呈现的文本相比。(GDI32 所做的扭曲都是为了提高清晰度。)

因此,在 WPF 4.0 中,Microsoft 添加了以 GDI32 的方式呈现文本的功能。就是TextOptions.TextFormattingMode="Display"这样。

通过打开该选项,您是在说“我不需要一致的缩放,我更喜欢清晰度,所以生成与在 GDI32 中相同的像素。” 如果您继续应用缩放,并告诉 WPF 您不需要可缩放性,您会得到糟糕的结果。WPF 仔细生成了完全符合您的规范的文本的位图表示,然后您告诉它以不同的比例呈现该文本。所以它看起来就像是:为不同分辨率生成的某些文本的缩放位图。

您可能会争辩说 WPF 在这里可以做一些不同的事情:如果您在 GDI32 中应用比例变换,您会看到不同的行为 - 您会看到前面描述的不同比例的不一致。如果你真的想要 WPF 中的那种效果,你可以通过直接修改字体大小来获得它。但是 WPF 并不优先考虑获得相同的效果 - 它的目标是在您真正需要时获得 GDI32 风格的清晰文本,并在默认情况下提供一致的缩放。

你在这里遇到的是“一致的缩放”。打开 GDI32 样式的文本渲染不会破坏一致的缩放:应用缩放因子(直接,通过 aScaleTransform或间接通过 a Viewbox)将完全按照指定的缩放因子更改视觉对象的尺寸。如果要通过适合新缩放大小的网格重新生成文本视觉效果,文本将以不同的宽度出现。这实际上会导致Viewbox问题:它根据内容的自然大小应用比例因子,旨在使其适合可用空间。但是如果它在缩放后重新调整网格,那实际上会改变宽度。由于 GDI32 文本渲染工作方式固有的不一致,它甚至可能无法用于ViewBox找到合适的比例 - 可以想出一段文本,当以特定字体呈现时,它永远不会出现 200 像素宽。对于某些字体大小,网格拟合中固有的舍入可能会将大小降低到 198,并且当您对字体大小进行微小增量时它可能会一直保持不变,直到您超过某个阈值时它可能会跳跃到 202 像素。

对于Viewbox试图强制文本恰好适合 200 像素的尝试,这将是一个问题。但Viewbox不是这样工作的 - 它使用 WPF 的一致缩放,在您选择 GDI32 样式文本呈现工作的字体大小的点的下游。所以Viewbox总是能够做它被设计做的事情,但这是与 GDI32 样式文本渲染根本不兼容的任务。

简而言之,WPF 会根据您请求的字体大小呈现文本,然后缩放结果。

所以你必须选择一个特性——你不能同时拥有这两个特性,因为那根本不可能。要么不要尝试在可以应用任意比例因子的上下文中渲染文本(例如Viewbox),要么不要打开 GDI32 样式的文本渲染。否则,你会得到你遇到的那种奇怪的像素化文本。

于 2010-12-10T14:43:46.473 回答
10

好的,发现错误。我的 Window 样式具有以下设置器:

    <Setter Property="TextOptions.TextFormattingMode" Value="Display"/>

如果我将它设置回“理想”(这是默认值),那么它会正确呈现视图框中的文本。我会说这是 WPF 中的一个错误。基本上,如果你试试这个:

<Viewbox Height="100" Stretch="Uniform" TextOptions.TextFormattingMode="Display">
    <TextBlock FontFamily="Georgia">My Cool Text</TextBlock>
</Viewbox>

您将得到与我最初图片中相同的结果。

于 2010-12-10T13:35:24.453 回答