11

I'm creating an application (Windows Form) that allows the user to take a screenshot based on the locations they choose (drag to select area). I wanted to add a little "preview pane" thats zoomed in so the user can select the area they want more precisely (larger pixels). On a mousemove event i have a the following code...

private void falseDesktop_MouseMove(object sender, MouseEventArgs e)
    {
        zoomBox.Image = showZoomBox(e.Location);
        zoomBox.Invalidate();
        bmpCrop.Dispose();
    }

private Image showZoomBox(Point curLocation)
    {
        Point start = new Point(curLocation.X - 50, curLocation.Y - 50);
        Size size = new Size(100, 90);
        Rectangle rect = new Rectangle(start, size);
        Image selection = cropImage(falseDesktop.Image, rect);
        return selection;
    }

private static Bitmap bmpCrop;
private static Image cropImage(Image img, Rectangle cropArea)
    {
        if (cropArea.Width != 0 && cropArea.Height != 0)
        {
            Bitmap bmpImage = new Bitmap(img);
            bmpCrop = bmpImage.Clone(cropArea, bmpImage.PixelFormat);
            bmpImage.Dispose();
            return (Image)(bmpCrop);
        }
        return null;
    }

The line that fails and has the Out of Memory exception is:

bmpCrop = bmpImage.Clone(cropArea, bmpImage.PixelFormat);

Basically what this does is it takes a 100x90 rectangle around the mouse pointer and pulls that into the zoomBox, which is a picturebox control. However, in the process, i get an Out Of Memory error. What is it that i am doing incorrectly here?

Thanks for your assistance.

Alex
  • 2,114
  • 9
  • 25
  • 34
  • On what line is your exception being thrown? – Steve Danner Nov 30 '10 at 21:04
  • 1
    Are you ever disposing bmpCrop? – CodesInChaos Nov 30 '10 at 21:09
  • 1
    And why are you creating a new cropped image on **each mouse move** instead of reusing an existing image? – CodesInChaos Nov 30 '10 at 21:10
  • @Steve, edit: stated the line thats being thrown to the OP @CodeInChaos, I do dispose of it right after the zoomBox.Invalidate(); Sorry i excluded it, will add to op. – Alex Nov 30 '10 at 21:11
  • @CodeInChaos, because i need the updated image/position of the mouse. – Alex Nov 30 '10 at 21:12
  • That's the wrong place to dispose it since there is no one-to-one relationship between `Invalidate` calls and paint events. You should dispose it directly before assigning a new value to the `cropImage` field. Or better reuse the old bitmap and just fill it with the new content. – CodesInChaos Nov 30 '10 at 21:13

6 Answers6

20

Out of memory in C# imaging, is usually sign of wrong rect or point - a bit of red herring. I bet start has negative X or Y when error happens or the Size.Hight + Y or Size.Width + X is bigger than Hight or width of the image.

Aliostad
  • 80,612
  • 21
  • 160
  • 208
  • Looking at the code that certainly is possible. start.x is curPos.X - 50 (same for y value). So what happens when curPos.x or curPos.y of less than 50? – Gerald Davis Nov 30 '10 at 21:12
  • I checked that, and i think you might be right, i was trying from the edge of the screen.... So what i did was tried it from the middle and that error went away yet another came up. Parameter is Not Valid. in my Program.cs -- Line Application.Run(); (i have no actual form thats being used, its just a notification icon application. – Alex Nov 30 '10 at 21:19
9

MSDN explains that an OutOfMemoryException means

rect is outside of the source bitmap bounds

where rect is the first parameter to the Bitmap.Clone method.

So check that the cropArea parameter is not larger than your image.

In GDI+ an OutOfMemoryException does not really mean "out of memory"; the GDI+ error code OufOfMemory has been overloaded to mean different things. The reasons for this are historic and a well described by Hans Passant in another answer.

Community
  • 1
  • 1
Dirk Vollmar
  • 172,527
  • 53
  • 255
  • 316
  • In that case I would expect .net to do the checking of the passed in rectangle before passing the code on the GDI+ and throw an appropriate exception if the rectangle is invalid. – CodesInChaos Nov 30 '10 at 21:22
  • In my case My form had small window but the image had large width $ height than form. While the from's BackgroundImageLayout mode was Tile. Upon setting BackgroundImageLayout to center my problem was gone. – Umair Sep 16 '21 at 09:38
4

Use the Bitmap object like this:

using (Bitmap bmpImage = new Bitmap(img))
{
    // Do something with the Bitmap object
}
Gilad Pomer
  • 185
  • 4
  • 7
0

you should check if curLocation.X is larger than 50, otherwise your rectangle will start in the negative area (and of course curLocation.Y)

user287107
  • 9,286
  • 1
  • 31
  • 47
  • Yeah i need to add that to my code, however that was still not the cause of the issue. – Alex Nov 30 '10 at 21:12
0

If the zoom box goes off the edge of the desktop area, then when you try to crop, you are asking the system to make a new image that includes pixels outside of the video memory area. Make sure to limit your zoom box so that none of its extents is less than 0 or greater than the screen edges.

Klay
  • 1,971
  • 5
  • 26
  • 40
-2

If you are creating new bitmaps over and over, you might need to call GC.Collect(); which will force C# to garbage collect

Samuel
  • 16,923
  • 6
  • 62
  • 75