gpt4 book ai didi

c# - 在 C# 中使用 native HBitmap,同时保留 alpha channel /透明度

转载 作者:行者123 更新时间:2023-11-30 13:34:01 25 4
gpt4 key购买 nike

假设我从 native Windows 函数获取 HBITMAP 对象/句柄。我可以使用 Bitmap.FromHbitmap(nativeHBitmap) 将其转换为托管位图,但如果 native 图像具有透明度信息(alpha channel ),则此转换会丢失它。

Stack Overflow 上有几个关于此问题的问题。使用这个问题 ( How to draw ARGB bitmap using GDI+? ) 的第一个答案中的信息,我编写了一段我已经尝试过并且有效的代码。

它基本上使用GetObjectBITMAP 结构获取 native HBitmap 宽度、高度和指向像素数据位置的指针,然后调用托管Bitmap 构造函数:

Bitmap managedBitmap = new Bitmap(bitmapStruct.bmWidth, bitmapStruct.bmHeight,
bitmapStruct.bmWidth * 4, PixelFormat.Format32bppArgb, bitmapStruct.bmBits);

据我了解(如果我错了请纠正我),这不会将实际像素数据从 native HBitmap 复制到托管位图,它只是将托管位图指向 native HBitmap 的像素数据。

并且我不会在另一个 Graphics (DC) 或另一个位图上绘制位图,以避免不必要的内存复制,尤其是对于大位图。

我可以简单地将此位图分配给 PictureBox 控件或 Form BackgroundImage 属性。它有效,位图使用透明度正确显示。

当我不再使用该位图时,我确保 BackgroundImage 属性不再指向该位图,并且我处理托管位图和 native 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);
}

最佳答案

即使 HBITMAP 是图标或 bmp,以下代码对我也有效,当它是图标时它不会翻转图像,并且还适用于不包含 Alpha channel 的位图:

    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;
}

关于c# - 在 C# 中使用 native HBitmap,同时保留 alpha channel /透明度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4627376/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com