呈现大型视觉对象性能的一部分

时间:2019-03-27 17:15:34

标签: c# wpf

我有一个从某些输入文件生成图形的应用程序。用户可以选择从这些图形生成图像。该图是使用外部库创建的,该库可绘制到自定义视觉对象(继承自Canvas)中。

功能

我创建了一个自定义功能,可以在此画布上创建图像,并且到目前为止效果很好。当需要从非常大的图形中生成图像时,我遇到的问题与其性能有关。

此功能生成的图像一直很大,为了能够生成这些大图像,我生成了较小的“块”(可配置,但当前为2000x2000px,较大的块会丢失质量,较小的块会较慢)。创建这些“块”之后,我使用另一个外部库将它们合并(这最后一个工作正常,而且速度很快,问题不在这里)。

问题

正在发生的问题是,原始视觉效果越大,每个块渲染所花费的时间就越长。

问题在于图像越大,每个“块”渲染花费的时间越长。我将稍后在此处发布代码,但是我注意到使用“ DrawingVisual”(带有块信息)时的“ RenderTargetBitmap.Render()”方法。例如,此方法调用在Canvas为 74052.75px x 1119.4px ;整个图像创建时间大约需要20秒。

并没有那么糟,但是有一个要求,即必须创建一个大(更大)的图像,并且每个块需要5分钟的时间来生成,所以我估计是大约需要 60天

代码

这是我在每个“块”循环中使用的代码。修改了代码,以删除一些取消令牌和进度报告调用。我还添加了一条注释,以突出显示耗时400毫秒以上的呼叫。

for (int i = 0; i < rowCount; i++)
{
    for (int j = 0; j < colCount; j++)
    {
        int row = i, col = j; //this is done because task start could have a modified value on call
        Rect rect = new Rect(
            col * maxWidth,
            row * maxHeight,
            col + 1 < colCount ? maxWidth :
                surfaceWidth - (colCount - 1) * maxWidth,
            row + 1 < rowCount ? maxHeight :
                surfaceHeight - (rowCount - 1) * maxHeight);

        DrawingVisual visual = new DrawingVisual();

        using (var dc = visual.RenderOpen())
        {
            VisualBrush brush = new VisualBrush(element)
            {
                Viewbox = rect,
                ViewboxUnits = BrushMappingMode.Absolute,
                Stretch = Stretch.None
            };
            dc.DrawRectangle(brush,
                null,
                new Rect(0, 0, rect.Width, rect.Height));
        }

        RenderTargetBitmap bitmap = new RenderTargetBitmap(

            (int)(rect.Width * (imgdpi / DEFAULT_DPI)),
            (int)(rect.Height * (imgdpi / DEFAULT_DPI)),
            imgdpi,
            imgdpi,
            PixelFormat);

        //***********************//
        //THIS IS THE CALL THAT TAKES 400+ms
        //***********************//
        bitmap.Render(visual);


        PngBitmapEncoder encoder = new PngBitmapEncoder();
        encoder.Frames.Add(BitmapFrame.Create(bitmap));

        MemoryStream ms = new MemoryStream();
        encoder.Save(ms);

        //... Some additional code to work with the chunk asynchronously
    }
}

我尝试过的事情

我尝试了几件事:

  1. 调用Dispatcher.DisableProcessing:我当时认为UI可能在处理块时一直试图更新表面(我理解如果不进行修改就不会有太大问题) 。但这并没有改变处理时间。
  2. 在创建VisualBrush对象以为其分配较小的视口(块大小或更大)时。时间实际上增加了。
  3. 将CacheMode添加到画布:时间实际上增加了,并且图像看上去分辨率很低。
  4. 一些绝望的措施,毫无意义哈哈。

其他信息

由于我不太确定此Render功能在内部如何工作(并且我已经搜索了这些信息,但是我发现充其量只是肤浅的),所以我不确定原因是表面较大还是曲面中控件的数量(或两者的组合)。因此,以下是有关测试用例的其他信息,每个渲染用时为400ms:

  • 表面尺寸为: 74052.75px x 1119.4px
  • N。图的节点数: 1977
  • N。连接器数(箭头): 2052
  • 每个控件视觉资源都是使用资源在XAML中定义的。
  • 每个图节点是一个填充矩形,其中心是一个文本块。
  • 每个连接器是一条直线,其边缘之一带有三角形。

此外,由于不会产生如此大的图像,因此对普通用户也不会如此。我不介意所提供的解决方案是否牺牲了UI响应能力。

在注释部分添加了注释以澄清一些担忧

  • 图形在屏幕上显示给用户,可以通过它进行操作。
  • “另存为图像”功能只是将图形另存为图像文件的附加可选功能。 (这在正常负载下有效,速度问题出现在一个不必要的大图形上。)

非常感谢您能提供的帮助。

谢谢!

0 个答案:

没有答案