【发布时间】:2014-09-08 11:34:40
【问题描述】:
我在 C# 中使用封装的 C 库,需要将该库中的图像转换为位图并返回,但无需复制像素缓冲区。
转换为位图很简单:
Bitmap WrapAsBitmap(CImage image)
{
return new Bitmap(image.Width, image.Height, image.BytesPerLine, PixelFormat.Format24bppRgb, image.Data);
}
只需将原始像素缓冲区 (image.Data) 传递给 Bitmap 构造函数,就不需要复制。相反,我需要调用LockBits 和UnlockBits 来访问原始像素缓冲区的IntPtr:
CImage WrapAsCImage(Bitmap bitmap)
{
BitmapData data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, bitmap.PixelFormat);
var image = new CImage(bitmap.Width, bitmap.Height, data.Stride * 3, data.Scan0);
bitmap.UnlockBits(data);
return image;
}
现在,如您所见,如果data.Scan0 在托管内存中,这实际上是一种危险的方法,因为在使用新构造的image 之前,这些位已“解锁”。如果bitmap 是从WrapAsBitmap 方法构造的,那么没有问题,因为data.Scan0 指向不会被.NET 移动的非托管内存。因此,我想构建一个安全检查来检查data.Scan0 指针的位置(托管/非托管)。
我想到的另一个解决方案是从Bitmap 类继承并跟踪原始指针image.Data 以及Bitmap,但是Bitmap 类是密封的,所以我出局了运气。
简而言之:任何想法如何检测IntPtr 的位置(托管/非托管)?
【问题讨论】:
-
这里的
CImage是什么? -
一个包装类,用于包装来自 C 库的图像。此类的唯一相关成员显示在
WrapAsBitmap方法中 -
有可能(我不知道),你这里还有一个问题:CImage -> WrapAsBitmap -> WrapAsCImage -> CImage,现在你有两个 CImage 实例指向同一个内存。也许您需要在 WrapAsCImage 中复制内存?
-
@AlexFarber 我知道,但这不是问题
-
愚蠢的建议:使用 Image.Tag 属性怎么样?不是通用的,但如果使用得当,可能会起作用。