繁体   English   中英

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

[英]c++ Get raw pixel data from hbitmap

我对使用 p/invoke 调用还很陌生,我想知道是否有人可以指导我如何从 hbitmap 中检索原始像素数据(无符号字符 *)。

这是我的场景:

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

用于获取位图 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++ 方法参数可以是 unsigned char* 吗?

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

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

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

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

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

int Resize::ResizeImage(HBITMAP hBmp)

接下来从HBITMAP转换为像素:

std::vector<unsigned char> ToPixels(HBITMAP BitmapHandle, int &width, int &height)
{        
    BITMAP Bmp = {0};
    BITMAPINFO Info = {0};
    std::vector<unsigned char> Pixels = std::vector<unsigned char>();

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM