簡體   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