Application crash while Bitmap image assign to Picturebox in Winforms - c#

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.

Because you disposed the object inside if block. Remove that and it won't give error.
Picturebox1.Image.Dispose();
Hope helps,

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)
A: Why must “stride” in the System.Drawing.Bitmap constructor be a multiple of 4?
And, combined and optimised:
Make a deep clone of an image to load it without any linked resources
A: Free file locked by new Bitmap(filePath)
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();
}

Related

The program takes up a lot of RAM, when the button is pressed (winforms) [duplicate]

I'm a newby in C#. I have to repeatedly refresh a GUI picture box in a worker thread. The image is acquired from a camera polling a driver with a GetImage method that retrives the image to be displayed. Even if I allocate the bitmap using directive "using" and explicitly call G.C, memory seems to be never deallocated.
The worker thread is something like this:
while (true)
{
// request image with IR signal values (array of UInt16)
image = axLVCam.GetImage(0);
lut = axLVCam.GetLUT(1);
DrawPicture(image, lut);
//GC.Collect();
}
While the DrawPicture method is something like
public void DrawPicture(object image, object lut)
{
[...]
// We have an image - cast it to proper type
System.UInt16[,] im = image as System.UInt16[,];
float[] lutTempConversion = lut as float[];
int lngWidthIrImage = im.GetLength(0);
int lngHeightIrImage = im.GetLength(1);
using (Bitmap bmp = new Bitmap(lngWidthIrImage, lngHeightIrImage)) {
[...many operation on bitmap pixel...]
// Bitmap is ready - update image control
//SetControlPropertyThreadSafe(tempTxtBox, "Text", string.Format("{0:0.#}", lutTempConversion[im[160, 100]]));
//tempTxtBox.Text = string.Format("{0:00000}", im[160, 100]);
//System.Drawing.Image.FromHbitmap(bmp.GetHbitmap());
pic.Image = System.Drawing.Image.FromHbitmap(bmp.GetHbitmap());
}
}
Problems arises with the
pic.Image = System.Drawing.Image.FromHbitmap(bmp.GetHbitmap());
In fact commenting that line of code, garbage collection works as it would.
Better, the problem seems to be with
System.Drawing.Image.FromHbitmap(bmp.GetHbitmap())
Any advice to solve this memory leak?
Thanks a lot!
Image implements IDisposable, so you should call Dispose on each Image instance that you create, when it is no longer needed. You could try to replace this line in your code:
pic.Image = System.Drawing.Image.FromHbitmap(bmp.GetHbitmap());
With this:
if (pic.Image != null)
{
pic.Image.Dispose();
}
pic.Image = System.Drawing.Image.FromHbitmap(bmp.GetHbitmap());
This will dispose the previous image (if any) before the new one is assigned.
The thing is, you're making a GDI bitmap of bmp with GetHbitmap, which according to msdn:
You are responsible for calling the
GDI DeleteObject method to free the
memory used by the GDI bitmap object.
Then the FromHbitmap method makes a copy of the GDI bitmap; so you can release the incoming GDI bitmap using the GDI DeleteObject method immediately after creating the new Image.
So basically I would add:
[System.Runtime.InteropServices.DllImport("gdi32.dll")]
public static extern bool DeleteObject(IntPtr hObject);
...
IntPtr gdiBitmap = bmp.GetHbitmap();
// Release the copied GDI bitmap
if (pic.Image != null)
{
pic.Image.Dispose();
}
pic.Image = System.Drawing.Image.FromHbitmap(gdiBitmap);
// Release the current GDI bitmap
DeleteObject(gdiBitmap);
I am unsure if you need the GDI bitmap to perform some kind of transformation. In case you don't you can just assign the bitmap to the Image property of your PictureBox, and ignore the former solution:
// Since we're not using unmanaged resources anymore, explicitly disposing
// the Image only results in more immediate garbage collection, there wouldn't
// actually be a memory leak if you forget to dispose.
if (pic.Image != null)
{
pic.Image.Dispose();
}
pic.Image = bmp;
There are several ways to release an image from pbox. I strongly recommend the way is that do not use pbox.Image = Image.FromFile.... If you do not use FileStream and you want to read it from file use BitMap class. Like this:
Bitmap bmp = new Bitmap(fileName);
pbox.Image = bmp; // notice that we used bitmap class to initialize pbox.
... and then you want to release the image file bmp.Dispose();
Now you can delete, move or whatever you want to the file.

What does LockBits/UnlockBits do in c#?

I have a method in c# that the only thing it does its LockBits, and then UnlockBits, and the images(input/output, transformed to byte arrays) are different. The one from output has less 100 and something bytes than the one from the input. This happens only with .jpg files. And checking the files in HxD I came to the understanding that it´s removing a part of the header, the exif signature to be exact. But I don't know how and why.
Does someone know what this is doing?
Here's the code:
public Image Validate (image){
BitmapData original = null;
Bitmap originalBMP = null;
try{
originalBMP = image as Bitmap;
original = originalBMP.LockBits(new Rectangle(0, 0,
originalBMP.Width, originalBMP.Height),
ImageLockMode.ReadWrite,
originalBMP.PixelFormat);
originalBMP.UnlockBits(original);
}catch{}
return image;
}
Calling Bitmap.LockBits() followed by Bitmap.UnlockBits() does nothing.
The behavior you observe is because of loading a JPEG image, and then saving it again. JPEG uses a lossy algorithm. So what happens:
You load the JPEG from disk
The JPEG data gets decoded into individual pixels with color information, i.e. a bitmap
You save the bitmap again in the JPEG format, resulting in a different file than #1
You also potentially lose metadata that was present in the JPEG file in doing so. So yes, the file is different and probably smaller, because every time you do this, you lose some pixel data or metadata.
Lockbits/Unlockbits are used to allow the program to manipulate the image data in memory. Nothing more, nothing less. See also the documentation for those methods.
Use the LockBits method to lock an existing bitmap in system memory so that it can be changed programmatically. You can change the color of an image with the SetPixel method, although the LockBits method offers better performance for large-scale changes.
A Rectangle structure that specifies the portion of the Bitmap to lock.
Example:
private void LockUnlockBitsExample(PaintEventArgs e)
{
// Create a new bitmap.
Bitmap bmp = new Bitmap("c:\\fakePhoto.jpg");
// Lock the bitmap's bits.
Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
System.Drawing.Imaging.BitmapData bmpData =
bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite,
bmp.PixelFormat);
// Get the address of the first line.
IntPtr ptr = bmpData.Scan0;
// Declare an array to hold the bytes of the bitmap.
int bytes = Math.Abs(bmpData.Stride) * bmp.Height;
byte[] rgbValues = new byte[bytes];
// Copy the RGB values into the array.
System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes);
// Set every third value to 255. A 24bpp bitmap will look red.
for (int counter = 2; counter < rgbValues.Length; counter += 3)
rgbValues[counter] = 255;
// Copy the RGB values back to the bitmap
System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, bytes);
// Unlock the bits.
bmp.UnlockBits(bmpData);
// Draw the modified image.
e.Graphics.DrawImage(bmp, 0, 150);
}

How do I store a non-persistent array of images for my canvas to get backgrounds from?

I have an image that can and must only exist in RAM and not be directly derived off of ANYTHING that came from my hard disk or from the internet.
This is because I am testing my own (rather awful) compression functions and must be able to read my own image format. This means that image data must be stored outside persistent memory.
Most tutorials for setting background images for canvas objects require me to create an Image object (Image is abstract) and the only subclasses that I found so far have URI objects, which to me imply that they reference objects that exist in persistent space, which is far from what I want to do.
Ideally, I would like to be able to store, in a non-persistent manner, images that are represented by arrays of pixels, with a width and a length.
public partial class MyClass : Window {
System.Drawing.Bitmap[] frames;
int curFrame;
private void Refresh()
{
//FrameCanvas is a simple Canvas object.
//I wanted to set its background to reflect the data stored
//in the
FrameCanvas.Background = new ImageBrush(frames[curFrame]);
//this causes an error saying that it can't turn a bitmap
//to windows.media.imagesource
//this code won't compile because of that
}
}
There are two ways to create a BitmapSource from data in memory.
Decode a bitmap frame, e.g. a PNG or JPEG:
byte[] buffer = ...
BitmapSource bitmap;
using (var memoryStream = new MemoryStream(buffer))
{
bitmap = BitmapFrame.Create(
memoryStream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
}
Or create a bitmap from raw pixel data:
PixelFormat format = ...
var stride = (width * format.BitsPerPixel + 7) / 8;
bitmap = BitmapSource.Create(
width, height,
dpi, dpi,
format, null,
buffer, stride);
See BitmapSource.Create for details.
Then assign the bitmap to the ImageBrush like this:
FrameCanvas.Background = new ImageBrush(bitmap);

Read and write directly to Unlocked Bitmap unmanaged memory (Scan0)

Is that ok to Write and Read directly from a unlocked Bitmap unmanaged memory?
Can I keep using the BitmapData after I UnlockBits of the Bitmap? I did a test app where I can read the pixel of the Bitmap of a PictureBox at mouse position while another thread is writing pixels to the same Bitmap.
EDIT 1: As Boing have pointed out in his answer: "Scan0 does not point to the actual pixel data of the Bitmap object; rather, it points to a temporary buffer that represents a portion of the pixel data in the Bitmap object." from MSDN.
But once I get the Scan0, I'm able to read/write to the Bitmap without the need of Lockbits or UnlockBits! I'm doing this a lot of times in a thread. Accordingly to MSDN, it should not happen, because Scan0 points to a COPY of the Bitmap data! Well, in C# all the test shows that it is not a copy. In C++ I don't know if it works as it should.
EDIT 2: Using the rotate method some times makes the OS to free the Bitmap pixel data copy. Conclusion, it is not safe to read/write an unlocked Bitmap Scan0. Thanks Boing for your answer and comments!
Below is how I get the BitmapData and read and write the pixel value.
/// <summary>
/// Locks and unlocks the Bitmap to get the BitmapData.
/// </summary>
/// <param name="bmp">Bitmap</param>
/// <returns>BitmapData</returns>
public static BitmapData GetBitmapData(Bitmap bmp)
{
BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, bmp.PixelFormat);
bmp.UnlockBits(bmpData);
return bmpData;
}
/// <summary>
/// Get pixel directly from unamanged pixel data based on the Scan0 pointer.
/// </summary>
/// <param name="bmpData">BitmapData of the Bitmap to get the pixel</param>
/// <param name="p">Pixel position</param>
/// <param name="channel">Channel</param>
/// <returns>Pixel value</returns>
public static byte GetPixel(BitmapData bmpData, Point p, int channel)
{
if ((p.X > bmpData.Width - 1) || (p.Y > bmpData.Height - 1))
throw new ArgumentException("GetPixel Point p is outside image bounds!");
int bitsPerPixel = ((int)bmpData.PixelFormat >> 8) & 0xFF;
int bpp = bitsPerPixel / 8;
byte data;
int id = p.Y * bmpData.Stride + p.X * bpp;
unsafe
{
byte* pData = (byte*)bmpData.Scan0;
data = pData[id + channel];
}
return data;
}
//Non UI Thread
private void DrawtoBitmapLoop()
{
while (_drawBitmap)
{
_drawPoint = new Point(_drawPoint.X + 10, _drawPoint.Y + 10);
if (_drawPoint.X > _backImageData.Width - 20)
_drawPoint.X = 0;
if (_drawPoint.Y > _backImageData.Height - 20)
_drawPoint.Y = 0;
DrawToScan0(_backImageData, _drawPoint, 1);
Thread.Sleep(10);
}
}
private static void DrawToScan0(BitmapData bmpData, Point start, int channel = 0)
{
int x = start.X;
int y = start.Y;
int bitsPerPixel = ((int)bmpData.PixelFormat >> 8) & 0xFF;
int bpp = bitsPerPixel / 8;
for (int i = 0; i < 10; i++)
{
unsafe
{
byte* p = (byte*)bmpData.Scan0;
int id = bmpData.Stride * y + channel + (x + i) * bpp;
p[id] = 255;
}
}
}
No, you cannot. The official explanation is clear about that.
Scan0 does not point to the actual pixel data of the Bitmap object; rather, it points to a temporary buffer that represents a portion of the pixel data in the Bitmap object. The code writes the value 0xff00ff00 (green) to 1500 locations in the temporary buffer. Later, the call to Bitmap::UnlockBits copies those values to the Bitmap object itself.
I would agree that there is a "bug" in UnLockBits(), because every non ImageLockModeUserInputBuf BitmapData should have its field reset (especially scan0) after the 'release/unlock'.
Scan0 GDI managed buffers may still be accessible after UnLockBits, but this is pure luck you do not get a invalid memory reference hard fault. The graphic subsystem may need this memory space to backup another Bitmap, or the same Bitmap but for another rectangle or in another pixelformat.
Scan0 don't represent the internal data of the bitmap, but a COPY, writen to by GDI while LockBits(...| ImageLockModeRead...) and read from by GDI while UnLockBits() (.. if LockBitswith(.. | ImageLockModeWrite ..)
That is what BitmapData abstraction is. Now maybe if you use a rectangle equals to the bitmap size AND a pixelmode matching the one of your display card, GDI may return the actual pixel storage address of the bitmap into scan0 (and not a copy), but you should never rely on that (or make a program that only work on your own computer).
EDIT 1: I allready explained above why you are lucky to be able to use scan0 outside the lock. Because you use the original bmp PixelFormat and that GDI is optimized in that case to give you the pointer and not a copy. This pointer is valid until the OS will decide to free it. The only time there is a garantee is between LockBits and UnLockBits. Period.
Here is the code to add to yours, put it in a Form to test it somewhat seriously. I can make it crash with a kind-of "neutral" call with Rotate180FlipX by hammering the button.
The bitmap internals are private. Period.
The OS may decide any moment to change its representation without even you making "action" on it (like minimizing the window, and zillions other possibilities).
EDIT 2: Your question:is there any practical difference locking a bitmap using ReadOnly or WriteOnly mode when no user buffer is given?
With or without user buffer, there IS a difference. One copy on LockBits(if readonly) AND/OR one copy on UnlockBits(if writeonly). Choose carefully to not do unwanted copies. Hint: stop thinking you are working in the same pixelformat, logically you do not. A write only buffer in 64bpp is received totally filled with noise (or untouched if it is also user buffer). You had better completely fill it before the unlock. (not just poking at some pixels). The naming of enum is misleading because WriteOnly | ReadOnly == ReadWrite
Accessing one pixel at a time using LockBits is BAD. Nobody wants to do that. What you do is to create/modify many*many pixel (using pointer/scan0) and commit them in quazy ATOMIC operation (Lock/Marhsal.Copy/UnLock) to the bitmap (and Invalidate()/redraw if you want to see something)
public MainForm()
{
InitializeComponent();
pictureBox.SizeMode = PictureBoxSizeMode.StretchImage;
// use a .gif for 8bpp
Bitmap bmp = (Bitmap)Bitmap.FromFile(#"C:\Users\Public\Pictures\Sample Pictures\Forest Flowers.jpg");
pictureBox.Image = bmp;
_backImageData = GetBitmapData(bmp);
_drawBitmap = true;
_thread= new Thread(DrawtoBitmapLoop);
_thread.IsBackground= true;
_thread.Start();
button.Text = "Let's get real";
button.Click += (object sender, EventArgs e) =>
{
// OK on my system, it does not rreallocate but ...
bmp.RotateFlip(RotateFlipType.Rotate180FlipX);
// ** FAIL with Rotate180FlipY on my system**
};
}
Thread _thread;
bool _drawBitmap;
BitmapData _backImageData;
//Non UI Thread
private void DrawtoBitmapLoop()
{
while (_drawBitmap)
{
ScrollColors(_backImageData);
this.Invoke((ThreadStart)(() =>
{
if (!this.IsDisposed)
this.pictureBox.Invalidate();
}));
Thread.Sleep(100);
}
}
private unsafe static void ScrollColors(BitmapData bmpData)
{
byte* ptr = (byte*)bmpData.Scan0;
ptr--;
byte* last = &ptr[(bmpData.Stride) * bmpData.Height];
while (++ptr <= last)
{
*ptr = (byte)((*ptr << 7) | (*ptr >> 1));
}
}

Event accessing Bitmap while its locked

I am trying to capture webcam frames from AForge.Net in C#. Unfortunetaly I get an ArgumentException at _CurrentFrame.LockBits. I suppose there is a problem with my event writing to the locked Bitmap!? Sometimes I also get "A generic error occurred in GDI+" at UnlockBits.
public bool GetFrame(ref Draw.STexture Frame)
{
BitmapData bd = _CurrentFrame.LockBits(new Rectangle(0, 0, _CurrentFrame.Width, _CurrentFrame.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
byte[] data = new byte[4 * _CurrentFrame.Width * _CurrentFrame.Height];
Marshal.Copy(bd.Scan0, data, 0, data.Length);
//Do something with data here
_CurrentFrame.UnlockBits(bd);
_CurrentFrame.Dispose();
}
private void OnFrame(object sender, NewFrameEventArgs e)
{
if (_CurrentFrame != null)
_CurrentFrame.Dispose();
_CurrentFrame = (Bitmap)e.Frame.Clone();
}
The Bitmap.Clone() method is dangerous, it creates a shallow copy of the bitmap. That copy stores the pointer to the pixel data instead of copying the pixels. In most camera drivers, that pointer will only be valid while the callback (event) runs. If you try to use it later then you'll be accessing invalid pixel data, making an exception on LockBits highly likely.
Either do the processing while the event runs or create a deep copy with the Bitmap(Image) constructor. That copy tends to be expensive of course.

Categories