private unsafe Bitmap BmpFrame() { Bitmap?bitmap = null; if (_iconData != null && _bestBitDepth == 32) { // GDI+ doesnt handle 32 bpp icons with alpha properly // we load the icon ourself from the byte table bitmap = new Bitmap(Size.Width, Size.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb); Debug.Assert(_bestImageOffset >= 0 && (_bestImageOffset + _bestBytesInRes) <= _iconData.Length, "Illegal offset/length for the Icon data"); unsafe { BitmapData bmpdata = bitmap.LockBits(new Rectangle(0, 0, Size.Width, Size.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); try { uint *pixelPtr = (uint *)bmpdata.Scan0.ToPointer(); // jumping the image header int newOffset = (int)(_bestImageOffset + sizeof(NativeMethods.BITMAPINFOHEADER)); // there is no color table that we need to skip since we're 32bpp int lineLength = Size.Width * 4; int width = Size.Width; for (int j = (Size.Height - 1) * 4; j >= 0; j -= 4) { Marshal.Copy(_iconData, newOffset + j * width, (IntPtr)pixelPtr, lineLength); pixelPtr += width; } // note: we ignore the mask that's available after the pixel table } finally { bitmap.UnlockBits(bmpdata); } } } else if (_bestBitDepth == 0 || _bestBitDepth == 32) { // This may be a 32bpp icon or an icon without any data. SafeNativeMethods.ICONINFO info = default; SafeNativeMethods.GetIconInfo(new HandleRef(this, _handle), ref info); SafeNativeMethods.BITMAP bmp = default; try { if (info.hbmColor != IntPtr.Zero) { SafeNativeMethods.GetObject(new HandleRef(null, info.hbmColor), sizeof(SafeNativeMethods.BITMAP), ref bmp); if (bmp.bmBitsPixel == 32) { Bitmap? tmpBitmap = null; BitmapData?bmpData = null; BitmapData?targetData = null; try { tmpBitmap = Image.FromHbitmap(info.hbmColor); // In GDI+ the bits are there but the bitmap was created with no alpha channel // so copy the bits by hand to a new bitmap // we also need to go around a limitation in the way the ICON is stored (ie if it's another bpp // but stored in 32bpp all pixels are transparent and not opaque) // (Here you mostly need to remain calm....) bmpData = tmpBitmap.LockBits(new Rectangle(0, 0, tmpBitmap.Width, tmpBitmap.Height), ImageLockMode.ReadOnly, tmpBitmap.PixelFormat); // we need do the following if the image has alpha because otherwise the image is fully transparent even though it has data if (BitmapHasAlpha(bmpData)) { bitmap = new Bitmap(bmpData.Width, bmpData.Height, PixelFormat.Format32bppArgb); targetData = bitmap.LockBits(new Rectangle(0, 0, bmpData.Width, bmpData.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); CopyBitmapData(bmpData, targetData); } } finally { if (tmpBitmap != null && bmpData != null) { tmpBitmap.UnlockBits(bmpData); } if (bitmap != null && targetData != null) { bitmap.UnlockBits(targetData); } } tmpBitmap.Dispose(); } } } finally { if (info.hbmColor != IntPtr.Zero) { Interop.Gdi32.DeleteObject(info.hbmColor); } if (info.hbmMask != IntPtr.Zero) { Interop.Gdi32.DeleteObject(info.hbmMask); } } } if (bitmap == null) { // last chance... all the other cases (ie non 32 bpp icons coming from a handle or from the bitmapData) // we have to do this rather than just return Bitmap.FromHIcon because // the bitmap returned from that, even though it's 32bpp, just paints where the mask allows it // seems like another GDI+ weirdness. might be interesting to investigate further. In the meantime // this looks like the right thing to do and is not more expansive that what was present before. Size size = Size; bitmap = new Bitmap(size.Width, size.Height); // initialized to transparent Graphics?graphics = null; using (graphics = Graphics.FromImage(bitmap)) { try { using (Bitmap tmpBitmap = Bitmap.FromHicon(Handle)) { graphics.DrawImage(tmpBitmap, new Rectangle(0, 0, size.Width, size.Height)); } } catch (ArgumentException) { // Sometimes FromHicon will crash with no real reason. // The backup plan is to just draw the image like we used to. // NOTE: FromHIcon is also where we have the buffer overrun // if width and height are mismatched. Draw(graphics, new Rectangle(0, 0, size.Width, size.Height)); } } // GDI+ fills the surface with a sentinel color for GetDC, but does // not correctly clean it up again, so we have to do it. Color fakeTransparencyColor = Color.FromArgb(0x0d, 0x0b, 0x0c); bitmap.MakeTransparent(fakeTransparencyColor); } Debug.Assert(bitmap != null, "Bitmap cannot be null"); return(bitmap); }
public unsafe Bitmap ToBitmap() { Bitmap image = null; if ((this.iconData != null) && (this.bestBitDepth == 0x20)) { image = new Bitmap(this.Size.Width, this.Size.Height, PixelFormat.Format32bppArgb); BitmapData bitmapdata = image.LockBits(new Rectangle(0, 0, this.Size.Width, this.Size.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); try { uint* numPtr = (uint*) bitmapdata.Scan0.ToPointer(); int num = this.bestImageOffset + Marshal.SizeOf(typeof(SafeNativeMethods.BITMAPINFOHEADER)); int length = this.Size.Width * 4; int width = this.Size.Width; for (int i = (this.Size.Height - 1) * 4; i >= 0; i -= 4) { Marshal.Copy(this.iconData, num + (i * width), (IntPtr) numPtr, length); numPtr += width; } } finally { image.UnlockBits(bitmapdata); } } else if ((this.bestBitDepth == 0) || (this.bestBitDepth == 0x20)) { SafeNativeMethods.ICONINFO info = new SafeNativeMethods.ICONINFO(); SafeNativeMethods.GetIconInfo(new HandleRef(this, this.handle), info); SafeNativeMethods.BITMAP bm = new SafeNativeMethods.BITMAP(); try { if (info.hbmColor != IntPtr.Zero) { SafeNativeMethods.GetObject(new HandleRef(null, info.hbmColor), Marshal.SizeOf(typeof(SafeNativeMethods.BITMAP)), bm); if (bm.bmBitsPixel == 0x20) { Bitmap bitmap3 = null; BitmapData bmpData = null; BitmapData targetData = null; System.Drawing.IntSecurity.ObjectFromWin32Handle.Assert(); try { bitmap3 = Image.FromHbitmap(info.hbmColor); bmpData = bitmap3.LockBits(new Rectangle(0, 0, bitmap3.Width, bitmap3.Height), ImageLockMode.ReadOnly, bitmap3.PixelFormat); if (BitmapHasAlpha(bmpData)) { image = new Bitmap(bmpData.Width, bmpData.Height, PixelFormat.Format32bppArgb); targetData = image.LockBits(new Rectangle(0, 0, bmpData.Width, bmpData.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); this.CopyBitmapData(bmpData, targetData); } } finally { CodeAccessPermission.RevertAssert(); if ((bitmap3 != null) && (bmpData != null)) { bitmap3.UnlockBits(bmpData); } if ((image != null) && (targetData != null)) { image.UnlockBits(targetData); } } bitmap3.Dispose(); } } } finally { if (info.hbmColor != IntPtr.Zero) { SafeNativeMethods.IntDeleteObject(new HandleRef(null, info.hbmColor)); } if (info.hbmMask != IntPtr.Zero) { SafeNativeMethods.IntDeleteObject(new HandleRef(null, info.hbmMask)); } } } if (image == null) { System.Drawing.Size size = this.Size; image = new Bitmap(size.Width, size.Height); using (Graphics graphics = null) { graphics = Graphics.FromImage(image); System.Drawing.IntSecurity.ObjectFromWin32Handle.Assert(); try { using (Bitmap bitmap4 = Bitmap.FromHicon(this.Handle)) { graphics.DrawImage(bitmap4, new Rectangle(0, 0, size.Width, size.Height)); } } catch (ArgumentException) { this.Draw(graphics, new Rectangle(0, 0, size.Width, size.Height)); } finally { CodeAccessPermission.RevertAssert(); } } Color transparentColor = Color.FromArgb(13, 11, 12); image.MakeTransparent(transparentColor); } return image; }
public Bitmap ToBitmap() { Bitmap bitmap = null; if(iconData != null && bestBitDepth == 32) { // GDI+ doesnt handle 32 bpp icons with alpha properly // we load the icon ourself from the byte table bitmap = new Bitmap(Size.Width, Size.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb); Debug.Assert(bestImageOffset >= 0 && (bestImageOffset + 40 + (Size.Width * Size.Height - 1)*4) <= iconData.Length, "Illegal offset/length for the Icon data"); unsafe { System.Drawing.Imaging.BitmapData bmpdata = bitmap.LockBits(new Rectangle(0, 0, Size.Width, Size.Height), System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); try { uint * pixelPtr = (uint*)bmpdata.Scan0.ToPointer(); // jumping the image header int newOffset = bestImageOffset + Marshal.SizeOf(typeof(SafeNativeMethods.BITMAPINFOHEADER)); // there is no color table that we need to skip since we're 32bpp int lineLength = Size.Width * 4; int width = Size.Width; for(int j=(Size.Height-1)*4;j>=0;j-=4) { Marshal.Copy(iconData, newOffset + j * width, (IntPtr)pixelPtr, lineLength); pixelPtr+=width; } // note: we ignore the mask that's available after the pixel table } finally { bitmap.UnlockBits(bmpdata); } } } else if(bestBitDepth == 0 || bestBitDepth == 32){ // we don't know or we are 32bpp for sure //we don't have any icon data, let's fish out the data from the handle that we got... // we have to fish out the data for this icon if the icon is a 32bpp icon SafeNativeMethods.ICONINFO info = new SafeNativeMethods.ICONINFO(); SafeNativeMethods.GetIconInfo(new HandleRef(this, handle), info); SafeNativeMethods.BITMAP bmp = new SafeNativeMethods.BITMAP(); try { if (info.hbmColor != IntPtr.Zero) { SafeNativeMethods.GetObject(new HandleRef(null, info.hbmColor), Marshal.SizeOf(typeof(SafeNativeMethods.BITMAP)), bmp); if(bmp.bmBitsPixel ==32) { Bitmap tmpBitmap = null; BitmapData bmpData = null; BitmapData targetData = null; // SECREVIEW : This assert is safe here, all data passed to unmanaged code is created by us. The scope is ok too, // most operations in it demand this permission. // IntSecurity.ObjectFromWin32Handle.Assert(); try { tmpBitmap = Bitmap.FromHbitmap(info.hbmColor); // bmpData = tmpBitmap.LockBits(new Rectangle(0,0, tmpBitmap.Width, tmpBitmap.Height), ImageLockMode.ReadOnly, tmpBitmap.PixelFormat); // we need do the following if the image has alpha because otherwise the image is fully transparent even though it has data if(BitmapHasAlpha(bmpData)) { bitmap = new Bitmap(bmpData.Width, bmpData.Height, PixelFormat.Format32bppArgb); targetData = bitmap.LockBits(new Rectangle(0, 0, bmpData.Width, bmpData.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); // SECREVIEW : both bmpData and targetData point to memory owned by this Icon object so the following call // is safe. // CopyBitmapData(bmpData, targetData); } } finally { CodeAccessPermission.RevertAssert(); if(tmpBitmap != null && bmpData != null) { tmpBitmap.UnlockBits(bmpData); } if(bitmap != null && targetData != null) { bitmap.UnlockBits(targetData); } } tmpBitmap.Dispose(); } } } finally { if(info.hbmColor != IntPtr.Zero) SafeNativeMethods.IntDeleteObject(new HandleRef(null, info.hbmColor)); if(info.hbmMask != IntPtr.Zero) SafeNativeMethods.IntDeleteObject(new HandleRef(null, info.hbmMask)); } } if(bitmap == null) { // last chance... all the other cases (ie non 32 bpp icons coming from a handle or from the bitmapData) // we have to do this rather than just return Bitmap.FromHIcon because // the bitmap returned from that, even though it's 32bpp, just paints where the mask allows it // seems like another GDI+ weirdness. might be interesting to investigate further. In the meantime // this looks like the right thing to do and is not more expansive that what was present before. Size size = Size; bitmap = new Bitmap(size.Width, size.Height); // initialized to transparent Graphics graphics = null; try { graphics = Graphics.FromImage(bitmap); // SECREVIEW : This assert is safe here, no user data is involved here. // IntSecurity.ObjectFromWin32Handle.Assert(); try{ using(Bitmap tmpBitmap = Bitmap.FromHicon(this.Handle)) { graphics.DrawImage(tmpBitmap, new Rectangle(0, 0, size.Width, size.Height)); } } catch(ArgumentException) { // GDI+ weirdness episode MMMCLXXXXIVI, sometime FromHicon crash with no real reason, // see VSWhidbey 518812 // backup plan is to just draw the image like we used to. // NOTE: FromHIcon is also where we have the buffer overrun // if width and height are mismatched Draw(graphics, new Rectangle(0, 0, size.Width, size.Height)); } finally{ CodeAccessPermission.RevertAssert(); } } finally { if (graphics != null) { graphics.Dispose(); } } // gpr: GDI+ is filling the surface with a sentinel color for GetDC, // but is not correctly cleaning it up again, so we have to for it. Color fakeTransparencyColor = Color.FromArgb(0x0d, 0x0b, 0x0c); bitmap.MakeTransparent(fakeTransparencyColor); } Debug.Assert(bitmap != null, "Bitmap cannot be null"); return bitmap; }
public unsafe Bitmap ToBitmap() { Bitmap image = null; if ((this.iconData != null) && (this.bestBitDepth == 0x20)) { image = new Bitmap(this.Size.Width, this.Size.Height, PixelFormat.Format32bppArgb); BitmapData bitmapdata = image.LockBits(new Rectangle(0, 0, this.Size.Width, this.Size.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); try { uint *numPtr = (uint *)bitmapdata.Scan0.ToPointer(); int num = this.bestImageOffset + Marshal.SizeOf(typeof(SafeNativeMethods.BITMAPINFOHEADER)); int length = this.Size.Width * 4; int width = this.Size.Width; for (int i = (this.Size.Height - 1) * 4; i >= 0; i -= 4) { Marshal.Copy(this.iconData, num + (i * width), (IntPtr)numPtr, length); numPtr += width; } } finally { image.UnlockBits(bitmapdata); } } else if ((this.bestBitDepth == 0) || (this.bestBitDepth == 0x20)) { SafeNativeMethods.ICONINFO info = new SafeNativeMethods.ICONINFO(); SafeNativeMethods.GetIconInfo(new HandleRef(this, this.handle), info); SafeNativeMethods.BITMAP bm = new SafeNativeMethods.BITMAP(); try { if (info.hbmColor != IntPtr.Zero) { SafeNativeMethods.GetObject(new HandleRef(null, info.hbmColor), Marshal.SizeOf(typeof(SafeNativeMethods.BITMAP)), bm); if (bm.bmBitsPixel == 0x20) { Bitmap bitmap3 = null; BitmapData bmpData = null; BitmapData targetData = null; System.Drawing.IntSecurity.ObjectFromWin32Handle.Assert(); try { bitmap3 = Image.FromHbitmap(info.hbmColor); bmpData = bitmap3.LockBits(new Rectangle(0, 0, bitmap3.Width, bitmap3.Height), ImageLockMode.ReadOnly, bitmap3.PixelFormat); if (BitmapHasAlpha(bmpData)) { image = new Bitmap(bmpData.Width, bmpData.Height, PixelFormat.Format32bppArgb); targetData = image.LockBits(new Rectangle(0, 0, bmpData.Width, bmpData.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); this.CopyBitmapData(bmpData, targetData); } } finally { CodeAccessPermission.RevertAssert(); if ((bitmap3 != null) && (bmpData != null)) { bitmap3.UnlockBits(bmpData); } if ((image != null) && (targetData != null)) { image.UnlockBits(targetData); } } bitmap3.Dispose(); } } } finally { if (info.hbmColor != IntPtr.Zero) { SafeNativeMethods.IntDeleteObject(new HandleRef(null, info.hbmColor)); } if (info.hbmMask != IntPtr.Zero) { SafeNativeMethods.IntDeleteObject(new HandleRef(null, info.hbmMask)); } } } if (image == null) { System.Drawing.Size size = this.Size; image = new Bitmap(size.Width, size.Height); using (Graphics graphics = null) { graphics = Graphics.FromImage(image); System.Drawing.IntSecurity.ObjectFromWin32Handle.Assert(); try { using (Bitmap bitmap4 = Bitmap.FromHicon(this.Handle)) { graphics.DrawImage(bitmap4, new Rectangle(0, 0, size.Width, size.Height)); } } catch (ArgumentException) { this.Draw(graphics, new Rectangle(0, 0, size.Width, size.Height)); } finally { CodeAccessPermission.RevertAssert(); } } Color transparentColor = Color.FromArgb(13, 11, 12); image.MakeTransparent(transparentColor); } return(image); }