0

I am new here. In my application i assign Bitmap image to picturebox. But after some time my application crash. I also maintan try catch and logs but application is just crash. Here is my code:

     System.Drawing.Bitmap ImageBMP = new System.Drawing.Bitmap(ImageWidth, ImageHeight, stride, PixelFormat.Format8bppIndexed, new IntPtr(scan0));
     if (Picturebox1!= null && Picturebox1.Image != null)
     {
           Picturebox1.Image.Dispose();
           Picturebox1.InitialImage = null;
     }
     Picturebox1.Image =ImageBMP;

Thanks in advance.

Siddhi Dave
  • 67
  • 1
  • 8
  • Crash on which line? Have you tried debugging it? Full stack trace please? – user202729 Jan 27 '18 at 06:01
  • While i assign bitmap image to picturebox. On this line : Picturebox1.Image =ImageBMP; – Siddhi Dave Jan 27 '18 at 06:02
  • Edit necessary info into your question. – user202729 Jan 27 '18 at 06:05
  • 1
    Those `stride` and `IntPtr(scan0)` are strange things. Where do they come from? From an Bitmap Data? `scan0` is an IntPtr(), so you pass `BitmapData.scan0`, not `IntPtr(BitmapData.scan0)` -- You can't Dispose() of a PictureBox Image. Set it to null + Refresh(), if you want to get rid of it. But, from what I see here, you don't need to bother, since you are assigning another one right after (when it doesn't fail). – Jimi Jan 27 '18 at 14:37
  • This seems like [an XY problem](http://www.perlmonks.org/?node=XY+Problem) to me. Why on earth are you messing around with raw pointers? – Nyerguds Jan 30 '18 at 09:19
  • @Jimi If the images are freshly deep-cloned for displaying them on the UI, and said objects are not used anywhere else, then you _can_ and _should_ dispose such UI images when replacing them, actually. They are wrapped GDI+ objects which need explicit disposal. – Nyerguds Jan 30 '18 at 09:27
  • @Nyerguds You dispose of the objects you create. Cloned or not. You don't assign graphics objects you manage to the .Image property of a PictureBox. You assign a copy: `pictureBox1.Image = new Bitmap(sourceBitmap)`. Otherwise => GDI+ locks. Just like what happens if you load a bitmap from a file: GDI+ locks the file. Problems come if you don't know/remember this and directly assign objects to a control. Then try to overcome the problem in exotic ways. Results are always (un)predictable. – Jimi Jan 30 '18 at 11:23
  • Uh. That's exactly what I said. Deep-cloned. Only [I tend to use a more advanced method of deep-cloning which doesn't lose its pixel format.](https://stackoverflow.com/a/48170549/395685), because I often work with 8-bit graphics. – Nyerguds Jan 30 '18 at 11:31
  • I added the solution for safely disposing UI images to my answer. – Nyerguds Apr 17 '18 at 06:11

2 Answers2

1

Because you disposed the object inside if block. Remove that and it won't give error.

Picturebox1.Image.Dispose();

Hope helps,

Berkay Yaylacı
  • 4,383
  • 2
  • 20
  • 37
  • While this is true, images _should_ be properly disposed when they are no longer used, especially if they are generated and replaced on-the-fly. I added the fix for that to my answer. – Nyerguds Apr 17 '18 at 06:09
0

You are using a raw pointer there. Where does that come from? It is advised to use managed arrays, unless you can be 100% sure that that pointer will remain valid.

If it comes from a LockBits operation on another image, it will not remain valid; it will stop being reliable from the moment the other image is unlocked.

If you are planning to clone or edit an 8bpp image, it is much safer to copy the contents of the images you're manipulating into normal managed Byte[] arrays, using LockBits and Marshal.Copy, and to copy them back into Bitmap objects the same way, rather than using pointers directly.

These pieces of code should set you on your way:

Get the backing byte array from an image:

/// <summary>
/// Gets the raw bytes from an image.
/// </summary>
/// <param name="sourceImage">The image to get the bytes from.</param>
/// <param name="stride">Stride of the retrieved image data.</param>
/// <returns>The raw bytes of the image</returns>
public static Byte[] GetImageData(Bitmap sourceImage, out Int32 stride)
{
    BitmapData sourceData = sourceImage.LockBits(new Rectangle(0, 0, sourceImage.Width, sourceImage.Height), ImageLockMode.ReadOnly, sourceImage.PixelFormat);
    stride = sourceData.Stride;
    Byte[] data = new Byte[stride * sourceImage.Height];
    Marshal.Copy(sourceData.Scan0, data, 0, data.Length);
    sourceImage.UnlockBits(sourceData);
    return data;
}

Create an image from a byte array: (rather than from a pointer)

And, combined and optimised:

Make a deep clone of an image to load it without any linked resources

Note, as for your disposing... you should never dispose an image still linked to the UI, since the next repaint of the UI will attempt to use the disposed image, which will inevitably cause a crash. The correct way to do this is to store the image reference in a variable, then make it null on the UI, and then dispose it:

 if (Picturebox1 != null && Picturebox1.Image != null)
 {
       Image img = Picturebox1.Image;
       Picturebox1.Image = null;
       img.Dispose();
 }
Nyerguds
  • 5,360
  • 1
  • 31
  • 63