c ++从hbitmap获取原始像素数据

我是一个相当新的使用p / invoke调用,我想知道是否有人可以指导我如何从hbitmap检索原始像素数据(unsigned char *)。

这是我的情景:

我在C#端加载一个.NET Bitmap对象,并将它的IntPtr发送到我的非托管c ++方法。 一旦我在C ++端收到hbitmap ptr,我想访问Bitmaps的像素数据。 我已经创建了一个接受unsigned char *的方法,它表示来自c#的原始像素数据但是我发现从c#中提取byte []相当慢。 这就是为什么我想发送Bitmap ptr而不是将Bitmap转换为byte []并将其发送到我的C ++方法。

用于获取Bitmap IntPtr的C#代码

Bitmap srcBitmap = new Bitmap(m_testImage); IntPtr hbitmap = srcBitmap.GetHbitmap(); 

用于导入c ++方法的C#代码

 [SuppressUnmanagedCodeSecurityAttribute()] [DllImport("MyDll.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] public static extern int ResizeImage(IntPtr srcImg); 

将接收Hbitmap处理程序的C ++方法

 int Resize::ResizeImage(unsigned char* srcImg){ //access srcImgs raw pixel data (preferably in unsigned char* format) //do work with that return status; } 

问题:

1)因为我发送的是IntPrt,我的C ++方法参数可以是无符号的char *吗?

2)如果没有,我如何从c ++访问位图的原始数据?

GetHbitmap方法不检索像素数据。 它产生一个HBITMAP类型的GDI位图句柄。 您的非托管代码会将其作为HBITMAP类型的参数接收。 您可以使用GDI调用从中获取像素数据。 但它本身并不是原始像素。

事实上,我很确定你是以错误的方式攻击这个问题。 你可能正朝着这个方向前进,因为GetPixelSetPixel很慢。 这是真的。 实际上,他们的GDI等价物也是如此。 你需要做的是使用LockBits 。 这将允许您以有效的方式操作C#中的整个像素数据。 可以在这里找到关于该主题的良好描述: http : //bobpowell.net/lockingbits.aspx 。 请注意,为了提高效率,这是一种C#代码,其中不安全的代码和指针通常是最佳解决方案。

无论出于何种原因,如果您仍希望使用C ++代码对像素数据进行操作,那么您仍然可以使用LockBits作为获取指向像素数据的指针的最简单方法。 它肯定比非托管GDI等价物容易得多。

首先, HBITMAP不应该是unsigned char* 。 如果要将HBITMAP传递给C ++,则参数应为HBITMAP

int Resize::ResizeImage(HBITMAP hBmp)

接下来将HBITMAP转换为像素:

 std::vector ToPixels(HBITMAP BitmapHandle, int &width, int &height) { BITMAP Bmp = {0}; BITMAPINFO Info = {0}; std::vector Pixels = std::vector(); HDC DC = CreateCompatibleDC(NULL); std::memset(&Info, 0, sizeof(BITMAPINFO)); //not necessary really.. HBITMAP OldBitmap = (HBITMAP)SelectObject(DC, BitmapHandle); GetObject(BitmapHandle, sizeof(Bmp), &Bmp); Info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); Info.bmiHeader.biWidth = width = Bmp.bmWidth; Info.bmiHeader.biHeight = height = Bmp.bmHeight; Info.bmiHeader.biPlanes = 1; Info.bmiHeader.biBitCount = Bmp.bmBitsPixel; Info.bmiHeader.biCompression = BI_RGB; Info.bmiHeader.biSizeImage = ((width * Bmp.bmBitsPixel + 31) / 32) * 4 * height; Pixels.resize(Info.bmiHeader.biSizeImage); GetDIBits(DC, BitmapHandle, 0, height, &Pixels[0], &Info, DIB_RGB_COLORS); SelectObject(DC, OldBitmap); height = std::abs(height); DeleteDC(DC); return Pixels; } 

显然从Scan0发送指针等同于我正在搜索的内容。 我可以通过发送从bitmapData.Scan0方法检索到的IntPtr来按预期操作数据。

 Bitmap srcBitmap = new Bitmap(m_testImage); Rectangle rect = new Rectangle(0, 0, srcBitmap.Width, srcBitmap.Height); BitmapData bmpData = srcBitmap.LockBits(rect, ImageLockMode.ReadWrite, srcBitmap.PixelFormat); //Get ptr to pixel data of image IntPtr ptr = bmpData.Scan0; //Call c++ method int status = myDll.ResizeImage(ptr); srcBitmap.UnlockBits(bmpData); 

为了进一步帮助澄清,我从最初的post中改变的唯一代码是第一个代码块。 其余的都保持不变。 (C ++方法仍然接受unsigned char *作为参数)