views:

38

answers:

1

I am trying to load images quickly into a picturebox and draw on them. I have a .13 second delay between the time I assign a bitmap to the picture box and when it shows up. And whenever I do a picturebox.refresh(), it is the same delay of .13 - .15 seconds before the paint method is called. Is there any way to get rid of this delay?

I am using C# in Visual Studio 2010. I load the images using FreeImage library.

Here is the code in my pictureBox_MouseMove event:
if (IsMouseDown || DrawLine.Checked || IsMovingBox)
{
Tracing.Trace("Update Picture Box");
pictureBox.Refresh();
}
Then I trace out a line when my paint event is called. The delay is between the two trace lines.

If I use a bitonal tiff image at 117kb the delay is .13 seconds. To load this image into memory takes .04 seconds. To replace my picturebox bitmap with this bitmap takes .01 seconds.

If I use a gray scale jpg image at 1125kb the delay is .14 seconds. To load this image into memory takes .26 seconds. To replace my picturebox bitmap with this bitmap takes .03 seconds.

+1  A: 

Assuming there are no other delays in your code that would prevent the UI thread from re-entering the message loop so that the OnPaint() method can be called: your Paint event handler gets called after PictureBox has drawn the Image. It isn't yet visible, PB uses double-buffering.

That image gets expensive to draw when it has to be resized to fit the PB's client area. Which is very likely in your case because your images are pretty large. It uses a high-quality bi-cubic filter to make the resized image look good. That's pretty expensive, albeit that the result is good.

To avoid that expense, resize the image yourself before assigning it to the Image property. Make it just as large as the PB's ClientSize.

That's going to make a big difference in itself. The next thing you can do is to create the scaled bitmap with the 32bppPArgb pixel format. It's the format that's about 10 times faster then any other because it matches the video adapter on most machines so no pixel format conversions are necessary.

Some code:

    private void loadImage(string path) {
        using (var srce = new Bitmap(path)) {
            var dest = new Bitmap(pictureBox1.Width, pictureBox1.Height, System.Drawing.Imaging.PixelFormat.Format32bppPArgb);
            using (var gr = Graphics.FromImage(dest)) {
                gr.DrawImage(srce, new Rectangle(Point.Empty, dest.Size));
            }
            if (pictureBox1.Image != null) pictureBox1.Dispose();
            pictureBox1.Image = dest;
        }
    }

You'll probably want to tinker with this so the image preserves its aspect ratio. Try it first as-is to make sure you do get the perf improvement.

Hans Passant
Hans, That may do it! Initial tests are definitely better! Fitting it into my code here and setting the aspect ratio correctly ...
Mark
Hans, That was perfect! Very nice! Thanks!
Mark