Warm tip: This article is reproduced from serverfault.com, please click

其他-如何在图像(WPF)上绘制折线

(其他 - How can I draw a Polyline onto an Image (WPF))

发布于 2020-11-27 22:48:57

我已经尝试了几种不同的方法,但是似乎无法获得有效的组合。

在C#,Visual Studio中创建WPF应用。

System.Windows.Shapes.Polyline可以很好地实时绘制到Canvas中,但是我希望能够以更高的分辨率绘制到非可视组件上,然后再渲染到Image上。

如果我在用户界面中可见的Canvas上创建折线,则可以正常工作:

// Make rendertarget size of full page
RenderTargetBitmap rtb = new RenderTargetBitmap((int)wPage, (int)hPage, 96, 96, PixelFormats.Default);
// Render the polyline
rtb.Render(lineVirt); 
// Apply to background image
imgBG.Source = rtb;

但是,如果在UI上不可见的Canvas上创建折线,则图像不会呈现任何内容。这可能已经足够公平了。我的猜测是该组件认识到它是不可见的,因此不会费心渲染。

我曾考虑过将Canvas放置在UI中放置在其他控件下的某个位置,但这似乎是一种可怕的黑客手段。

本质上,我需要的是一种干净快速的方法来在图像上绘制指定宽度和颜色的多点线。我以为Polyline可以很好地工作,但似乎只能在可见的容器中工作。

我有什么选择?

Questioner
xtempore
Viewed
11
Clemens 2020-11-28 18:35:52

你根本不需要渲染的Canvas或任何其他可见的Panel。

只需使用Visual层上可用的基本图形基元即可。

DrawGeometry下面方法Geometry使用位图的渲染大小(即将其DPI考虑在内的大小)绘制到BitmapSource上,并返回生成的BitmapSource。

public static BitmapSource DrawGeometry(
    BitmapSource source, Pen pen, Geometry geometry)
{
    var visual = new DrawingVisual();
    var rect = new Rect(0, 0, source.Width, source.Height);

    using (var dc = visual.RenderOpen())
    {
        dc.DrawImage(source, rect);
        dc.DrawGeometry(null, pen, geometry);
    }

    var target = new RenderTargetBitmap(
        (int)rect.Width, (int)rect.Height, 96, 96, PixelFormats.Default);

    target.Render(visual);
    return target;
}

为了绘制位图的像素单位并因此忽略其DPI,请按如下所示修改方法:

var rect = new Rect(0, 0, source.PixelWidth, source.PixelHeight);

using (var dc = visual.RenderOpen())
{
    dc.DrawRectangle(new ImageBrush(source), null, rect);
    dc.DrawGeometry(null, pen, geometry);
}

以下方法使用上述方法绘制多段线作为IEnumerable<Point>

public static BitmapSource DrawPolyline(
    BitmapSource source, Pen pen, IEnumerable<Point> points)
{
    var geometry = new PathGeometry();

    if (points.Count() >= 2)
    {
        var figure = new PathFigure { StartPoint = points.First() };
        figure.Segments.Add(new PolyLineSegment(points.Skip(1), true));
        geometry.Figures.Add(figure);
    }

    return DrawGeometry(source, pen, geometry);
}

它会像

var source = new BitmapImage(new Uri(...));

var pen = new Pen
{
    Brush = Brushes.Blue,
    Thickness = 2,
};

var points = new List<Point>
{
    new Point(100, 100),
    new Point(1000, 100),
    new Point(1000, 1000),
    new Point(100, 1000),
    new Point(100, 100),
};

image.Source = DrawPolyline(source, pen, points);