Safely create System.Drawing.Bitmap from managed int[]
-
I am searching for a few days now, but I didn't find any examples of creating a System.Drawing.Bitmap without using unsafe code. I've an int[] with one pixel in BGRA per int. The pixel values are created in my program, so I don't have any loadable bitmap so far. I tried to create a bitmap via new Bitmap(Int32 width, Int32 heigth, int32 stride, System.Drawing.Imaging.PixelFormat format, IntPtr scan0); but I didn't get the IntPtr to refer to the data correctly. If anyone has an idea how to correctly create that bitmap, I'd appreciate your help. thanks in advance, Norbert
-
I am searching for a few days now, but I didn't find any examples of creating a System.Drawing.Bitmap without using unsafe code. I've an int[] with one pixel in BGRA per int. The pixel values are created in my program, so I don't have any loadable bitmap so far. I tried to create a bitmap via new Bitmap(Int32 width, Int32 heigth, int32 stride, System.Drawing.Imaging.PixelFormat format, IntPtr scan0); but I didn't get the IntPtr to refer to the data correctly. If anyone has an idea how to correctly create that bitmap, I'd appreciate your help. thanks in advance, Norbert
Hi, I have not done this for bitmaps yet, but passing a sound array to the unmanaged function PlaySound() requires a pointer to a data object (array) that can not be moved by the GC; see GCHandle and pinning in code snippet below.
// play sound from a sound resource Stream stream=type.Assembly.GetManifestResourceStream(resourceName); int len=(int)stream.Length; byte\[\] buf=new byte\[len\]; stream.Read(buf, 0, len); GCHandle handle=GCHandle.Alloc(buf); IntPtr ptr=Marshal.UnsafeAddrOfPinnedArrayElement(buf, 0); int res=sndPlaySound(ptr, 4); // SND\_MEMORY handle.Free();
I expect what you need is very similar to the above. Don't forget to free the handle when the pinning is no longer needed (otherwise the GC can not collect or even move it, possibly ending up in out-of-memory problems). :)
Luc Pattyn
-
Hi, I have not done this for bitmaps yet, but passing a sound array to the unmanaged function PlaySound() requires a pointer to a data object (array) that can not be moved by the GC; see GCHandle and pinning in code snippet below.
// play sound from a sound resource Stream stream=type.Assembly.GetManifestResourceStream(resourceName); int len=(int)stream.Length; byte\[\] buf=new byte\[len\]; stream.Read(buf, 0, len); GCHandle handle=GCHandle.Alloc(buf); IntPtr ptr=Marshal.UnsafeAddrOfPinnedArrayElement(buf, 0); int res=sndPlaySound(ptr, 4); // SND\_MEMORY handle.Free();
I expect what you need is very similar to the above. Don't forget to free the handle when the pinning is no longer needed (otherwise the GC can not collect or even move it, possibly ending up in out-of-memory problems). :)
Luc Pattyn
Thanks for your reply. I'm getting a valid (non zero) IntPtr with your help, so I can create a new System.Drawing.Bitmap. The saved image is not what I did expect, but that's a problem with the PixelFormat. So thank you very much for your help. Norbert
-
Thanks for your reply. I'm getting a valid (non zero) IntPtr with your help, so I can create a new System.Drawing.Bitmap. The saved image is not what I did expect, but that's a problem with the PixelFormat. So thank you very much for your help. Norbert
Hi Norbert, I've just found an article that may be relevant for you: http://www.codeproject.com/useritems/ImageConverter.asp[^] It seems to prove GCHandle is totally unnecessary for your needs ... Greetings,
Luc Pattyn
-
Hi Norbert, I've just found an article that may be relevant for you: http://www.codeproject.com/useritems/ImageConverter.asp[^] It seems to prove GCHandle is totally unnecessary for your needs ... Greetings,
Luc Pattyn
No it wasn't. I knew that article, but I didn't get that code working. Also the ImageConverter which is mentioned in the articles message board didn't work for me. My code, as nasty as it is by now looks like this:
using System.Runtime.InteropServices; using System.Drawing; ... public void saveImage(String filename) { List byteList = new List(); lock (this) { foreach (int color in m_data) { byteList.AddRange(System.BitConverter.GetBytes(color)); } } byte[] byteData = byteList.ToArray(); GCHandle handle = GCHandle.Alloc(byteData); ; try { IntPtr imgDataPtr = Marshal.UnsafeAddrOfPinnedArrayElement(byteData, 0); if(imgDataPtr != IntPtr.Zero) { Bitmap img = new Bitmap(this.Height, this.Width, byteData.Length, PixelFormat.Format32bppArgb, imgDataPtr); Random rnd = new Random(); img.Save(filename, System.Drawing.Imaging.ImageFormat.Tiff); } else { System.Diagnostics.Debugger.Break(); } } catch(Exception e) { System.Diagnostics.Debugger.Break(); } finally { handle.Free(); } }
The creation of the Bitmap always threw ArgumentExceptions, when the PixelFormat is anything else than Format32bppArgb. It took me quite a time to figure out, that PixelFormat was the parameter which caused the problem, since I don't see any obvious differences between Format32bppArgb and Canonical which are both 32 Bits / pixel and should at maximum cause some mixed up channels when stated wrong. So maybe I'd get the Bitmap creation running with one of the linked examples above, if I check again for the correct PixelFormat, but by now I think I better use that maybe unnecessarily complicated version you helped me to figure out. If I get a shorter and less complicated version running, I'll post it here. Norbert