views:

517

answers:

1

There seem to be many picturebox questions out there, but I haven't found any that deal with changing the contents of a picturebox to a bitmap that was not simply loaded from file.

My application takes an array of bytes and generates a bitmap from them. I really want to avoid writing to a file as an intermediate processing step.

Because it is an array of bytes, and not 2-byte words, I needed to make an indexed bitmap with a grayscale palette.

I then converted the indexed bitmap to a normal one (24 bit rgb).

This is the code that is causing an error for me:

pictureBox1.Image = (System.Drawing.Image)bmp2;

When I view the form (the picturebox tries to draw), the thread will simply halt execution with a message: "invalid parameter at System.Drawing.Image.get_RawFormat()"

What am I doing wrong? How can I create a safe bitmap for the picturebox?

This is what creates "bmp2":

//creating the bitmap from the array
System.Drawing.Bitmap bmp1 = new System.Drawing.Bitmap(100, 100, 100, System.Drawing.Imaging.PixelFormat.Format8bppIndexed, MyIntPtr);

//creating a proper indexed palette
System.Drawing.Imaging.ColorPalette GrayPalette = bmp1.Palette;
for (int i = 0; i < GrayPalette.Entries.Length; i++)
{
    GrayPalette.Entries[i] = Color.FromArgb(i, i, i);
}
bmp1.Palette = GrayPalette;

//creating a non-indexed, 24bppRGB bitmap for picturebox compatibility
System.Drawing.Bitmap bmp2 = new Bitmap(bmp1.Width, bmp1.Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
Graphics gr = Graphics.FromImage(bmp2);
gr.DrawImage(bmp1, 0, 0);
gr.Dispose();

If I use bmp1.Save(@"testfile.bmp") I get a perfectly acceptable bitmap that appears to be without anomaly.

Why can't I use my bitmap as my picturebox.Image? Are there additional parameters of the picturebox I need to change prior to loading the new bitmap into it?

+2  A: 

Well, I've found the problem with what I was doing.

I'll try to explain what was wrong, but as a non-guru I am not sure how accurate I will be.

Apparently setting the image in a pictureBox does not copy memory anywhere. Later on in my application (a few functions away from the code snippet I showed) I was disposing of the variable "bmp1".

I was not aware that the memory associated with bmp1 was the same memory everywhere the function passes it, and in destroying it the error "invalid parameter at System.Drawing.Image.get_RawFormat()" was raised. I suppose it does this because every time the pictureBox is redrawn it uses it's "Image" property to, well, draw. Because I was disposing of the memory associated with the "Image" property I was killing all hopes of the picturebox_Paint event working properly.

I only hope that I don't have memory leaks now as a result of never disposing of any bitmaps I create.

Gorchestopher H
The GC should take care of the memory.
SLaks
@SLaks: The GC will take care of the memory, but it will not release the native resources used by the Bitmap object. There is a reason for the IDisposable interface, use it.
Ed Swangren
@EdSwangren : **Wrong**. `IDisposable` objects that own native resources will dispose the native resources in the finalizer. See the Dispose pattern.
SLaks
@SLaks: Yes, but the exact time when a finalizer is called is unspecified. If you are not calling dispose you are simply a lazy programmer. I shouldn't have said "won't", but if you want determinism, call dispose. There is a reason the dispose/close/etc. methods exist. I guess you are ok with potentially tying up resources to be released at some unspecified time in the future, I am not. That probably comes from me being a systems engineer where an error can cost a lot of money and possibly injure someone.
Ed Swangren
...of course, we don't use C# for... anything in my field, so meh.
Ed Swangren
@EdSwangren: I did not _at all_ mean to imply that you shouldn't call `Dispose`. I just meant that not calling `Dispose` shouldn't single-handedly create a massive memory leak.
SLaks
Yeah, you're right about that.
Ed Swangren