2
votes

I have some problems with performance in my code… I need to render many-colored rectangles to my DrawingVisual.

The first version is simple:

using (DrawingContext dc = Canvas.RenderOpen())
{
   for (Int32 x = 0; x < widthCount; x++)
      for (Int32 y = 0; y < heightCount; y++)
      {
          Color c;
          Double value = mass[x, y];
          c = GetColorByValue(value);
          dc.DrawRectangle(new SolidColorBrush(c), null,
          new Rect(x * step - step / 2, y * step - step / 2, step, step));
       }
}

And it works normal in case of the quantity of rectangles is about 250x250 (and it gets 200Mb RAM). But if the number of them is 750x750 the process of rendering is too long and slow (gets more than 2.5Gb RAM)

The next step was using a bitmap like a buffer. But there is a problem with the size of my DrawingVisual. Visual is really large. So it is impossible to create a full-size bitmap because the constructor of RenderTargetBitmap throws the Exception “The image data generated an overflow during processing”.

Finally I created a small bitmap and stretched it to my visual. However the problem is the same (it works too slow and gets a lot of RAM).

What should I do to make the process of rendering elements to get adequate time and sources?

Regards!

Thanks!

1
Hard to tell. You should use the analysis tools in visual studio to identify what is causing you the most problems. - user1228
Well 250*250 = 62500 and takes 200Mb. 750*750 = 562500 and takes 10x the RAM. Seems about right. Half a million rectangles ??? - Phil
@Will As far as I understand the main problem is exactly rendering by wpf, because my code works to the end and the process of rendering takes the rest period of time. - Nick
@Phil It may seems stange, but the rectangles are many-colored, so they can’t be put in one Geometry... - Nick

1 Answers

2
votes

Yep! I have found the way to solve this problem! For the first time I used the bitmap as a buffer wrongly. But now I use it correctly. My code:

//temp visual
DrawingVisual tmpVisual = new DrawingVisual();
using (DrawingContext dc = tmpVisual.RenderOpen())
{
     for (Int32 x = 0; x < widthCount; x++)
          for (Int32 y = 0; y < heightCount; y++)
          {
              Color c;
              Double value = mass[x, y];
              c = GetColorByValue(value);
              dc.DrawRectangle(new SolidColorBrush(c), null,
                  new Rect(x * step - step / 2, y * step - step / 2, step, step));
          }
}

//resize visual
tmpVisual.Transform = new ScaleTransform(maxWidth/(widthCount * step),
                        maxHeight/(heightCount * step));

//visual to bitmap
RenderTargetBitmap bitmap = 
    new RenderTargetBitmap(maxWidth, maxHeight, 96, 96, PixelFormats.Pbgra32);
bitmap.Render(tmpVisual);

using (DrawingContext dc = Canvas.RenderOpen())
{
    Rect rect = new Rect(0, 0, widthCount * step, heightCount * step);
    dc.DrawImage(bitmap, rect);
}

I have created a temp visual, reduce it and rendered it to the bitmap. Finally I stretched it to my visual.

I thanks to this topic: Scaling WPF content before rendering to bitmap