wpf - View 框内的 TextBlock - 奇怪的渲染

标签 wpf viewbox

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

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

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

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

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

最佳答案

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

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

本示例使用了 WPF 的两个相互矛盾的功能。这些特点是:

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

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

    GDI32 对字符的形状和宽度进行了处理,以增强文本的清晰度和清晰度。具体来说,它会将字母弯曲变形,使其特征与屏幕上的像素更好地对齐。并且在必要时,它会将单个字符的宽度调整为精确的像素宽度。由于这种字母弯曲完全基于实际像素,因此它以不同的方式以不同的字体大小弯曲文本。

    虽然这给了你漂亮清晰的文字,但如果你试图逐渐改变比例,它看起来绝对可怕。如果您尝试为以这种方式呈现的某些文本的字体大小设置动画,则该内容看起来会闪烁并颤抖,因为以清晰度的名义进行的调整最终会在每个字体大小上略有不同。即使你不做动画,它仍然会产生糟糕的结果——如果你有一个以多种尺寸显示的单一字体,它在每种尺寸下看起来都可能大不相同;如果您的应用程序具有缩放功能,当您放大和缩小时,文本的字符似乎会发生显着变化。 (布局也是如此。如果您使用 Microsoft Word,您可能已经注意到有时在某些单词之间会出现看起来很奇怪的超宽空格。这是 Word 与 GDI32 争斗的结果 - Word 试图保持屏幕上的布局尽可能接近打印时的外观,这意味着它有时会与 GDI32 的网格拟合发生冲突。)

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

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

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

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

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

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

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

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

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

    关于wpf - View 框内的 TextBlock - 奇怪的渲染,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4408726/

    相关文章:

    .net - 使用 SynchronizationContext 将事件发送回 WinForms 或 WPF 的 UI

    c# - 当我不知道它可能抛出的位置时如何记录异常?

    wpf - 在名称范围内找不到名称 ---在数据网格中显示动画时出错

    xml - SVG 缩放文本以适合容器

    WPF。如何只显示大 Canvas 的一部分?

    c# - 使用具有行+列坐标的值集合动态填充数据网格

    c# - 在窗口打开之前设置窗口的Parent

    SVG viewBox 放大中心 (Raphael)

    javascript - 在javaScript中更改svg的viewBox