2014-02-26 91 views
6

我對使用p/invoke調用相當陌生,並且想知道是否有人可以指導我如何從hbitmap中檢索原始像素數據(unsigned char *)。C++從hbitmap獲取原始像素數據

這是我的情景:

我加載在C#.NET位圖對象,併發送它的IntPtr到我的非託管C++方法。一旦我在C++側收到hbitmap ptr,我想訪問Bitmaps的像素數據。我已經做了一個方法,接受一個無符號的char *,它表示來自c#的原始像素數據,但是我發現從c#中提取字節[]是相當緩慢的。這就是爲什麼我想發送Bitmap ptr而不是將Bitmap轉換爲byte []並將其發送給我的C++方法。

用於獲取位圖的IntPtr

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

C#代碼用於導入C++方法將接收HBITMAP處理程序

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

問題

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

C++方法C#代碼

1)由於我在IntPrt中發送,我的C++方法參數可以是一個unsigned char *嗎?

2)如果不是,我如何從C++訪問位圖的原始數據?

回答

4

GetHbitmap方法不檢索像素數據。它產生一個類型爲HBITMAP的GDI位圖句柄。您的非託管代碼會將其作爲HBITMAP類型的參數接收。您可以使用GDI調用獲取像素數據。但它本身不是原始像素。

事實上,我很肯定你是以錯誤的方式攻擊這個問題的。您可能正在採取這種方式,因爲GetPixelSetPixel速度很慢。這是真的。事實上,他們的GDI等值也是如此。你需要做的是使用LockBits。這將允許您以有效的方式對C#中的整個像素數據進行操作。這個主題的一個很好的描述可以在這裏找到:http://bobpowell.net/lockingbits.aspx。請注意,爲了提高效率,這是一種C#代碼,其中不安全的代碼和指針通常是最佳解決方案。

如果由於某種原因,您仍希望使用C++代碼對像素數據進行操作,那麼仍然可以使用LockBits作爲獲取指向像素數據的指針的最簡單方法。這當然比非託管GDI等價物容易得多。

+0

感謝大衛,這正是我發現還!我發佈我的代碼作爲答案,希望可以幫助其他人尋找相同的解決方案。 – Matthew

+0

你當然可以這樣做。但它也應該可以生成高效的託管代碼。使用不安全和指針。 –

0

顯然從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++方法仍接受無符號字符*作爲參數)

3

首先,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; 
} 
+0

感謝您的回覆,我會嘗試比較使用此方法和我發佈的解決方案的性能差異。 – Matthew