0

I am having some trouble understanding why Graphics.ScaleTransform decreases so much the performance of the Graphics.FillRegion.

I am developing an application where I draw Regions in the PictureBox's paint event. This procedure works as expected, with a very good performance and without any kind of delay. The problem arises when I use the ScaleTransform method together with a custom Zooming tool.

So far my code looks like this:

protected void drawPicBox(object sender, PaintEventArgs e)
{
     e.Graphics.SetClip(new Rectangle(picBox_x_padding,
                                      picBox_y_padding,
                                     (picBox_x_padding == 0.0) ? picBoxImage.Width : picBoxImage.Width - 2 * .picBox_x_padding,
                                     (picBox_y_padding == 0.0) ? picBoxImage.Height : picBoxImage.Height - 2 * picBox_y_padding));
    if (zoom_rate > 1.0)
    {
         e.Graphics.ScaleTransform(zoom_rate, zoom_rate);
    }
    e.Graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
    e.Graphics.CompositingQuality = CompositingQuality.HighSpeed;
    e.Graphics.PixelOffsetMode = PixelOffsetMode.HighSpeed;
    e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
    foreach (var item in regions)
    {
         // Paint the semantic group
         e.Graphics.FillRegion(new SolidBrush(item.Color), item.Region);
    }
}

While no zoom is set (zoom_rate == 1.0), the algorithm works reasonably well (~20ms) in terms of elapsed time, but as soon as the zoom_rate is over 1.0 and the graphics scaling is performed, the elapsed time starts to go up at a factor of approximately 30ms per 0.2 of zoom_rate increase.

For my application, this is not acceptable at all because after zooming too much the image displayed in the Picture box (Image size never superior to 1200px on each dimension), the elapsed time starts to go over 200ms, which makes the process really tedious to handle.

I do not know if I'm missing something, but I would appreciate any kind of suggestion in terms of how can I deal with this problem.

Thank you in advance!

MarioAF
  • 23
  • 4
  • Have you tried drawing to an offscreen bitmap buffer, and then drawing the bitmap to the picturebox? `FillRegion` is probably switching to a less efficient floating-point mode under scaling. That should let you draw the regions once, when they change, and not every frame – Bradley Uffner Apr 01 '21 at 14:10
  • Yeah, I've considered it, but I would like if possible to avoid that because drawing the graphics to a sort of hidden bitmap carries a loss in the resolution of the regions (borders look sharper than when drawing directly in the PictureBox's paint event). – MarioAF Apr 01 '21 at 14:16
  • 1
    The main issue is your choice of regions for drawing purposes. This is not what they are meant to do!! They are meant to restrict drawing of controls. Regions do not support antialiasing and always boil down to rectangles. This is why the don't scale well and also why large region get so slow. I have pointed you to this [dicussion](https://stackoverflow.com/questions/43139118/region-isvisiblepointf-has-very-slow-performance-for-large-floating-point-valu/43180365?r=SearchResults&s=6|12.0605#43180365) yesterday and it applies to anything you do with regions. – TaW Apr 01 '21 at 14:18
  • 2
    I strongly advise against following this path, no matter how much work you have put into it and how well it seems to work. Instead go for GraphicsPaths, which are much more flexible, support all sort of nice GDI features like anti-aliased pens and beziers and can scale like any vector graphics. – TaW Apr 01 '21 at 14:19
  • I'm starting to think that what I'm trying to achieve with regions is way above what they are usually intended for, as you are pointing me @TaW. – MarioAF Apr 01 '21 at 14:20
  • Building on what TaW already said (which is of course *the Truth* :), if you need to fill a section of your graphic objects, you can build a GraphicsPath the defines the region (small `R`, not a Region, but a Path) you want to create, fill it with whatever means (semi-transparent colors / gradients are ok). A simple method to apply is to generate a transparent Bitmap and use the Bitmap as the source of a `TextureBrush` (which supports Matrix multipliers and standard transformations). This creates anti-aliased *impressions* and works pretty fast. – Jimi Apr 01 '21 at 15:03
  • See: [How to crop an elliptical region of an Image with smooth borders](https://stackoverflow.com/a/61554272/7444103). To scale/rotate/translate, apply transformations to just Rectangles or Paths, then paint inside these shapes. It's then just basic math and applying graphics transformations to these shapes is much (much) faster than transforming graphics objects. See: [Zoom and translate an Image from the mouse location](https://stackoverflow.com/a/61964222/7444103). Very simple functions generate and combine all the transformations there (Rotate, Scale, Translate and relative Zoom). – Jimi Apr 01 '21 at 15:06
  • Thank you very much for your suggestions! I really appreciate them. I'll definitely consider all the possibilities and see what is the best option. – MarioAF Apr 01 '21 at 19:59

0 Answers0