Ale*_*ang 3 c# gdi bitmap hbitmap alpha-transparency
假设我从本机Windows函数中获取HBITMAP对象/句柄.我可以使用Bitmap.FromHbitmap(nativeHBitmap)将其转换为托管位图,但如果原生图像具有透明度信息(alpha通道),则此转换会丢失它.
有关此问题的Stack Overflow有几个问题.使用来自这个问题的第一个答案的信息(如何使用GDI +绘制ARGB位图?),我编写了一段我尝试过的代码并且它有效.
它基本上使用GetObject和BITMAP结构获取本机HBitmap宽度,高度和指向像素数据位置的指针,然后调用托管Bitmap构造函数:
Bitmap managedBitmap = new Bitmap(bitmapStruct.bmWidth, bitmapStruct.bmHeight,
bitmapStruct.bmWidth * 4, PixelFormat.Format32bppArgb, bitmapStruct.bmBits);
Run Code Online (Sandbox Code Playgroud)
据我所知(请纠正我,如果我错了),这不会将实际像素数据从原生HBitmap复制到托管位图,它只是将托管位图指向本机HBitmap的像素数据.
我不会在另一个图形(DC)或另一个位图上绘制位图,以避免不必要的内存复制,尤其是对于大位图.
我可以简单地将此位图分配给PictureBox控件或Form BackgroundImage属性.它工作正常,使用透明度正确显示位图.
当我不再使用位图时,我确保BackgroundImage属性不再指向位图,并且我同时配置了托管位图和本机HBitmap.
问题:你能告诉我这个推理和代码是否正确.我希望我不会得到一些意想不到的行为或错误.我希望我能正确释放所有内存和对象.
private void Example()
{
IntPtr nativeHBitmap = IntPtr.Zero;
/* Get the native HBitmap object from a Windows function here */
// Create the BITMAP structure and get info from our nativeHBitmap
NativeMethods.BITMAP bitmapStruct = new NativeMethods.BITMAP();
NativeMethods.GetObjectBitmap(nativeHBitmap, Marshal.SizeOf(bitmapStruct), ref bitmapStruct);
// Create the managed bitmap using the pointer to the pixel data of the native HBitmap
Bitmap managedBitmap = new Bitmap(
bitmapStruct.bmWidth, bitmapStruct.bmHeight, bitmapStruct.bmWidth * 4, PixelFormat.Format32bppArgb, bitmapStruct.bmBits);
// Show the bitmap
this.BackgroundImage = managedBitmap;
/* Run the program, use the image */
MessageBox.Show("running...");
// When the image is no longer needed, dispose both the managed Bitmap object and the native HBitmap
this.BackgroundImage = null;
managedBitmap.Dispose();
NativeMethods.DeleteObject(nativeHBitmap);
}
internal static class NativeMethods
{
[StructLayout(LayoutKind.Sequential)]
public struct BITMAP
{
public int bmType;
public int bmWidth;
public int bmHeight;
public int bmWidthBytes;
public ushort bmPlanes;
public ushort bmBitsPixel;
public IntPtr bmBits;
}
[DllImport("gdi32", CharSet = CharSet.Auto, EntryPoint = "GetObject")]
public static extern int GetObjectBitmap(IntPtr hObject, int nCount, ref BITMAP lpObject);
[DllImport("gdi32.dll")]
internal static extern bool DeleteObject(IntPtr hObject);
}
Run Code Online (Sandbox Code Playgroud)
以下代码适用于我,即使它HBITMAP是一个图标或bmp,当它是一个图标时它不会翻转图像,也可以使用不包含Alpha通道的位图:
private static Bitmap GetBitmapFromHBitmap(IntPtr nativeHBitmap)
{
Bitmap bmp = Bitmap.FromHbitmap(nativeHBitmap);
if (Bitmap.GetPixelFormatSize(bmp.PixelFormat) < 32)
return bmp;
BitmapData bmpData;
if (IsAlphaBitmap(bmp, out bmpData))
return GetlAlphaBitmapFromBitmapData(bmpData);
return bmp;
}
private static Bitmap GetlAlphaBitmapFromBitmapData(BitmapData bmpData)
{
return new Bitmap(
bmpData.Width,
bmpData.Height,
bmpData.Stride,
PixelFormat.Format32bppArgb,
bmpData.Scan0);
}
private static bool IsAlphaBitmap(Bitmap bmp, out BitmapData bmpData)
{
Rectangle bmBounds = new Rectangle(0, 0, bmp.Width, bmp.Height);
bmpData = bmp.LockBits(bmBounds, ImageLockMode.ReadOnly, bmp.PixelFormat);
try
{
for (int y = 0; y <= bmpData.Height - 1; y++)
{
for (int x = 0; x <= bmpData.Width - 1; x++)
{
Color pixelColor = Color.FromArgb(
Marshal.ReadInt32(bmpData.Scan0, (bmpData.Stride * y) + (4 * x)));
if (pixelColor.A > 0 & pixelColor.A < 255)
{
return true;
}
}
}
}
finally
{
bmp.UnlockBits(bmpData);
}
return false;
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
6018 次 |
| 最近记录: |