如何在没有抗锯齿的情况下绘制多段线(在WPF中)



我正在尝试绘制一条不带抗锯齿的多段线

我认为答案可能与设置EdgeMode有关,但我尝试了各种元素,但都没有得到好的结果:

RenderOptions.SetEdgeMode(???, EdgeMode.Aliased)

让我们从头开始,因为似乎有一些地方需要改变。

折线绘制在StreamGeometry:上

using (StreamGeometryContext gc = virtGeom.Open())
{
gc.BeginFigure(firstPoint, false, false);
gc.PolyLineTo(virtPoints, true, true);
}

然后,它被绘制到DrawingVisualDrawingContext中,最终渲染到RenderTargetBitmap,该作为图像源。

任何想法都值得赞赏!

下面显示了一个完整的示例,用于演示抗锯齿。这不包括任何解决它的尝试,因为使用SetEdgeMode的各种尝试都没有产生任何改进。

主窗口.xaml

<Window x:Class="Antialias.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Antialias"
mc:Ignorable="d"
Title="MainWindow" Width="800" Height="400" Background="#FFCFCFCF" MouseDown="Window_MouseDown">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Image x:Name="Img" Width="320" Height="320"/>
<Image x:Name="Img2" Width="320" Height="320" Grid.Column="1"/>
</Grid>
</Window>

主窗口.xaml.cs

using System.Collections.Generic;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace Antialias
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Window_MouseDown(object sender, MouseButtonEventArgs e)
{
int w = (int)Img.Width;
int h = (int)Img.Height;
// Create RenderTargetBitmap and assign as image source
RenderTargetBitmap rtb = new RenderTargetBitmap(w, h, 96, 96, PixelFormats.Pbgra32);
Img.Source = rtb;
DrawingVisual dv = new DrawingVisual();
StreamGeometry geom = new StreamGeometry();
Pen pen = new Pen(Brushes.Red, 20)
{
StartLineCap = PenLineCap.Round,
EndLineCap = PenLineCap.Round,
LineJoin = PenLineJoin.Round
};
// Draw a simple line from top left to bottom right
Point startPoint = new Point(0, 0);
List<Point> points = new List<Point>()
{
new Point(w, h)
};
using (StreamGeometryContext gc = geom.Open())
{
gc.BeginFigure(startPoint, false, false);
gc.PolyLineTo(points, true, true);
}
// Apply white background and then draw geometry
using (DrawingContext dc = dv.RenderOpen())
{
dc.DrawRectangle(Brushes.White, null, new Rect(0, 0, w, h));
dc.DrawGeometry(null, pen, geom);
}
// Render to RTB
rtb.Render(dv);
// Part 2: Cut a clip (20 x 20) from the rendered bitmap and zoom in (using NearestNeighbor)
CroppedBitmap cbmp = new CroppedBitmap(rtb, new Int32Rect(0, 0, 20, 20));
RenderOptions.SetBitmapScalingMode(Img2, BitmapScalingMode.NearestNeighbor);
// Apply the zoomed sampled to the second image
Img2.Source = cbmp;
// Look for antialiasing (pixels part way between red and not white)
}
}
}

EdgeMode设置为别名的明显候选者是DrawingVisual,但设置它似乎没有什么区别:

// This had no effect!
RenderOptions.SetEdgeMode(dv, EdgeMode.Aliased);

DrawingVisual有一个受保护的属性VisualEdgeMode,该属性可能应该通过调用上面的来设置。在调试过程中,我在属性上放了一块手表,发现它没有设置

由于它是受保护的属性,您不能直接设置它,但您可以创建一个子类并以这种方式进行设置。最后,这就是对我有效的:

class DrawingVisualAliased : DrawingVisual
{
public DrawingVisualAliased() : base()
{
VisualEdgeMode = EdgeMode.Aliased;
}
}

不确定这是否是最好的方式。似乎应该通过调用RenderOptions来设置该属性。SetEdgeMode,所以可能还有其他不太正确的地方。

感谢@Rekshino督促我创建一个示例。这当然有助于能够处理这个问题的一个非常简化的版本,并有一个清晰的视觉表示

最新更新