我对.NET如何管理图像有点困惑,我有以下代码,从非托管HBitmap构建托管位图,以维护alpha通道。
public 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))
{
// MY QUESTION IS RELATED TO THIS
// IF CALL SUPPRESS_FINALIZE THE OBJECT
// IT WILL WORK, OTHERWISE IT FAILS
GC.SuppressFinalize(bmp);
return new Bitmap(
bmpData.Width,
bmpData.Height,
bmpData.Stride,
PixelFormat.Format32bppArgb,
bmpData.Scan0);
}
return bmp;
}
private static bool IsAlphaBitmap(Bitmap bmp, out BitmapData bmpData)
{
Rectangle bmpBounds = new Rectangle(0, 0, bmp.Width, bmp.Height);
bmpData = bmp.LockBits(bmpBounds, ImageLockMode.ReadOnly, bmp.PixelFormat);
try
{
return IsAlphaBitmap(bmpData);
}
finally
{
bmp.UnlockBits(bmpData);
}
}
private static bool IsAlphaBitmap(BitmapData bmpData)
{
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;
}
}
}
return false;
}
好的,我知道第GC.SuppressFinalize(bmp);
行是没有意义的,但是当我删除该行时,有时(每4或5次调用)我会得到以下异常:
尝试读取或写入受保护的内存。这通常是一个 表明其他内存已损坏。
我怀疑垃圾是在绘制返回位图之前收集bmp对象,因此它尝试访问框架处理的位。如果我从不收集bmp它可以工作,但它会导致内存泄漏(从不收集bmp引用)。
你知道我怎么能解决这个问题?
答案 0 :(得分:4)
查看Bitmap constructor you are using
的重新制作者调用者负责分配和释放scan0参数指定的内存块。 但是,在释放相关的位图之前,不应释放内存。
这意味着在释放bmpData
返回的Bitmap
实例之后,您需要确保保留GetBitmapFromHBitmap
指向的基础内存块。< / p>
您的问题是由于垃圾收集器检测到bmp
无法访问(未使用)而导致收集/最终确定肯定释放底层内存块,然而,即使您取消终结器,您仍然会调用UnlockBits
,这意味着bmpData
无论如何已经无效 - 它可能现在可以正常工作,但这完全是偶然的。为了使上面的代码正确,你需要找到一种机制,只要返回的bmpData
实例存在,bmp
(和扩展名Bitmap
)有效 - 即可能是对您的申请进行重大更改。
另外,请参阅Converting Bitmap PixelFormats in C#,了解完全不同的做法(我认为)您想要实现的目标,同时完全避免所有这些问题。