在WPF中无缝拼接矩形,同时保持亚像素精度?

时间:2010-05-27 13:14:22

标签: c# wpf tiles aliasing

我遇到问题Tiling rectangles seamlessly in WPF中描述的问题,但我对那里给出的答案并不满意。

我正在绘制一个条形图,通过绘制彼此相邻的许多矩形。根据包含它们的画布的比例,由于子像素渲染,其中一些画面之间可见小间隙。

我从上面的问题中了解到如何使我的矩形与屏幕像素相符,从而消除了这种影响。

不幸的是,我的图表可能会显示比像素更多的条形图。除了微小的间隙(表现为颜色饱和度的周期性变化)之外,这种方法效果很好。如果我用屏幕像素捕捉每个条形图,大多数条形图都消失了,所以我正在寻找另一个解决方案。

提前致谢!

2 个答案:

答案 0 :(得分:2)

问题原因

子像素形状在像素内使用Alpha混合。不幸的是,没有alpha混合算法会导致矩形在邻接时无缝混合。

例如,如果:

  • 背景颜色为白色
  • 前景色为黑色,
  • 你有两个矩形,每个矩形覆盖一个像素的一半

每个矩形将被涂成黑色,不透明度为50%。第一个将白色像素转换为灰色。第二种将其转换为深灰色,但不是黑色。如果这些矩形在相邻像素中继续变黑,则会在黑色中看到深灰色像素。

两种解决方案

解决此问题的方法有两种:

  1. 使用单个几何图形来定义所有矩形,或
  2. 强制初始渲染处于足够高的分辨率,用户不会看到问题。
  3. 如何使用单一几何

    如果你只有一组矩形,你可以创建一个简单的控件,用一个包含组合形状的PathGeometry绘制整个矩形集。为了说明这个想法,如果你有两个不同高度的矩形,就像这样:

    <Rectangle Canvas.Left="0" Canvas.Top="0" Width="1.5" Height="2" Fill="Red" />
    <Rectangle Canvas.Left="1.5" Canvas.Top="0" Width="1.5" Height="4" Fill="Red" />
    

    您可以使用单个PathGeometry渲染它,如下所示:

    <Path Data="M0,0 L0,2 L1.5,2 L1.5,4 L3,4 L3,0 Z" Fill="Red" />
    

    实现这一目标的一种实用方法是:

    • 使用透明画笔绘制矩形,使其可以点击但不可见
    • 按Z顺序在矩形下方添加路径控件
    • 使用构造几何体的转换器将Path控件的Data属性绑定到数据源。

    如果您使用布局系统来定位矩形,您可能希望通过为每个矩形创建一个Adorner来使用AdornerLayer,然后在渲染装饰时计算第一个矩形的组合路径并使其余部分不可见。

    以上假设很容易从源数据生成PathGeometry。对于更复杂的场景,Path控件可以被子类化以搜索其父级的可视树以获取指定的形状,并使用通用的几何算法来计算表示它们的并集而没有额外边缘的PathGeometry。

    如果你的矩形有多种颜色,你可以使用每种颜色一个多个Path控件,或者你可以构造一个Drawing对象并显示它。

    以下是构造PathGeometry的代码结构:

    var geo = new PathGeometry();
    var figure = new PathFigure();
    var segment = new PolyLineSegment();
    segment.Points.Add(...);
    segment.Points.Add(...);
    segment.Points.Add(...);
    segment.Points.Add(...);
    segment.Points.Add(...);
    figure.Segments.Add(segment);
    geo.Figures.Add(figure);
    

    如何强制初始渲染为高分辨率

    强制以更高分辨率渲染:

    1. 在内部构建比您想要显示的图表大几倍的图表,例如将其包装在ViewBox中。
    2. 使用VisualBrush或RenderTargetBitmap强制您的图表单独呈现
    3. 将使用VisualBrush绘制的Rectangle添加到UI
    4. 请注意,通常WPF在使用ViewBrush时以实际分辨率渲染是很聪明的,但是实际图表实际显示在屏幕上的较大尺寸可能会被欺骗,但是后来被父控件剪切了所以你实际上并没有看到太大的版本。

      当然,RenderTargetBitmap不存在此问题,因为您指定了所需的分辨率,但知道何时重新渲染位图可能会非常棘手。如果您只对数据更改进行重新渲染,则可以使用事件,但如果您希望任何可视更改触发重新渲染,则会更加困难。

答案 1 :(得分:1)

Target 4.0, use layout rounding(带演示的博文)。