[英]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 調用從中獲取像素數據。 但它本身並不是原始像素。
事實上,我很確定您正在以錯誤的方式解決這個問題。 您可能正朝着這個方向前進,因為GetPixel
和SetPixel
很慢。 這很真實。 事實上,它們的 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.