Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

System.Drawing Parameter is not valid

Tags:

c#

.net

aforge

I'm currently using AForge dll to render the video on the picture box for the live view. I do have a video frame function to whether WriteFrame or Screenshot the current picturebox frame as a JPG.

But i met a problem when sometime the program will prompt out an error of Parameter is not valid or Object is been used elsewhere. I did try to find solution to solve it and i pretty sure i did dispose on the image and the clone image, but the problem still exist.

Could you assist me on what i had done wrong with my program?

void videoSource_NewFrame(object sender, NewFrameEventArgs eventArgs)
        {
            //your code using bmp object
            if (D1Pic.BackColor == Color.Green)
            {
                video = (Bitmap)eventArgs.Frame.Clone();
                if (livePreview.Image != null)
                {
                    //Dispose the resources
                    this.Invoke(new MethodInvoker(delegate() { livePreview.Image.Dispose(); }));
                }
                livePreview.Image = (Bitmap)eventArgs.Frame.Clone();
                imgclone = (Image)livePreview.Image.Clone();
                FileWriter.WriteVideoFrame(video);
            }
            else
            {
                video = (Bitmap)eventArgs.Frame.Clone();
                if (livePreview.Image != null)
                {
                    //Dispose the resources
                    this.Invoke(new MethodInvoker(delegate() { livePreview.Image.Dispose(); }));
                    this.Invoke(new MethodInvoker(delegate() { video.Dispose(); }));
                }
                livePreview.Image = (Bitmap)eventArgs.Frame.Clone();
                imgclone = (Image)livePreview.Image.Clone();
            }
            video.Dispose();
            livePreview.Refresh();

Here are the stack trace error :

{"Parameter is not valid."}
   at System.Drawing.Image.get_Width()
   at System.Windows.Forms.PictureBox.ImageRectangleFromSizeMode(PictureBoxSizeMode mode)
   at System.Windows.Forms.PictureBox.OnPaint(PaintEventArgs pe)
   at System.Windows.Forms.Control.PaintWithErrorHandling(PaintEventArgs e, Int16 layer)
   at System.Windows.Forms.Control.WmPaint(Message& m)
   at System.Windows.Forms.Control.WndProc(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
   at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)

UPDATED CODE :

 var newFrame = (Bitmap)eventArgs.Frame.Clone();
                this.Invoke(new MethodInvoker(delegate()
                {
                    if (livePreview.Image != null)
                    {
                        livePreview.Image.Dispose();
                    }
                    livePreview.Image = newFrame;
                }));
                imgclone = (Bitmap)eventArgs.Frame.Clone();

                //Write frame into video
                if (D1Pic.BackColor == Color.Green)
                {
                    video = (Bitmap)eventArgs.Frame.Clone();
                    FileWriter.WriteVideoFrame(video);
                }
like image 625
Marcus Avatar asked Sep 05 '25 17:09

Marcus


1 Answers

You are calling livePreview.Image.Dispose() in the UI thread, but you're not setting livePreview.Image to null afterwards.

So between the time that you dispose livePreview.Image and the time that you assign a new image to it, livePreview.Image points to a disposed object.

So I think occasionally your picturebox tries to draw itself during this time, and fails when it attempts to access its (disposed) Image property.

The solution would be:

if (livePreview.Image != null)
{
    //Dispose the resources
    this.Invoke(new MethodInvoker(delegate() { 
        livePreview.Image.Dispose(); 
        livePreview.Image = null;
    }));
}

Or even better, assign the new image in the same step:

var newFrame = (Bitmap)eventArgs.Frame.Clone();
this.Invoke(new MethodInvoker(delegate() { 
    if (livePreview.Image != null)
    {
        livePreview.Image.Dispose(); 
    }
    livePreview.Image = newFrame;
}));

In general, you need to understand what's happening with your various Bitmap objects. Anything that keeps a reference to a Bitmap that has been disposed will be a problem.

like image 186
Blorgbeard Avatar answered Sep 07 '25 09:09

Blorgbeard