访问CBitmap对象中的各个像素

时间:2017-05-03 13:13:02

标签: visual-c++ mfc gdi

作为练习,我试图编写一段代码,可以在特定的x / y位置从MFC CBitmap对象中采样单个像素。

该类没有任何GetPixel类型的接口,我看到的大部分信息都表明通过CBitmap::GetBitMapBits复制CBitmap位的全部内容,这似乎效率极低。

是否无法通过指针访问字节数组并将其作为数组访问?

3 个答案:

答案 0 :(得分:3)

您需要先在CDCCDC::SelectObject)中选择CBitmap。设备上下文有CDC::GetPixel成员。

答案 1 :(得分:1)

如果CBitmap对象与device-independent bitmap(DIB,例如由CreateDIBSection()创建)相关联,则可以获得指向直接访问位图像素(不复制)的指针致电GetObject()。如果您在使用直接访问权限之前访问了位图像素GdiFlush(),请务必致电by any other GDI functions

如果CBitmapdevice-dependent bitmap(DDB,也称为兼容位图)相关联,则使用哪种方法取决于您要访问的像素数。

  • 如果只需要访问极少数像素,您可以使用CDC::SelectObject()CDC::GetPixel()路线。如果您想要读取更多像素,这将非常慢。
  • 要访问大量像素,您可以使用CBitmap::GetBitMapBits()GetDIBits()。当您只需要访问部分位图像素时,后者可能更有效,因为它具有定义要复制的扫描线范围的参数。

在任何一种情况下,当你需要逐像素地访问时, DDB总是比DIB 慢。

以下示例检测CBitmap是否与DIB或DDB关联,并分支以对每种情况使用最有效的访问方法。

void DoAwesomeStuff( CBitmap& bitmap )
{
    DIBSECTION dib{ 0 };
    if( ::GetObject( bitmap, sizeof( dib ), &dib ) )
    {
        // GetObject() succeeded so we know that bmp is associated with a DIB.

        // Evaluate the information in dib thoroughly, to determine if you can handle
        // the bitmap format. You will propably restrict yourself to a few uncompressed 
        // formats.
        // In the following example I accept only uncompressed top-down bitmaps 
        // with 32bpp.
        if( dib.dsBmih.biCompression == BI_RGB && 
            dib.dsBmih.biHeight < 0 &&  // negative height indicates top-down bitmap
            dib.dsBmih.biPlanes == 1 && 
            dib.dsBmih.biBitCount == 32 )
        {
            DWORD* pPixels = reinterpret_cast<DWORD*>( dib.dsBm.bmBits );
            // TODO: Access the bitmap directly through the pPixels pointer. 
            // Make sure to check bounds to avoid segfault.
        }
    }
    else
    {
        // GetObject() failed because bmp is not a DIB or for some other reason.
        BITMAP bmp{ 0 };
        if( ::GetObject( bitmap, sizeof( bmp ), &bmp ) )
        {
            // GetObject() succeeded so we know that bmp is associated with a DDB.
            CDC dc;
            // Create a memory DC.
            dc.CreateCompatibleDC( nullptr );
            if( CBitmap* pOldBmp = dc.SelectObject( &bitmap ) )
            {
                // Get the bitmap pixel at given coordinates.
                // For accessing a large number of pixels, CBitmap::GetBitMapBits() 
                // or GetDIBits() will be more efficient.
                COLORREF pixel = dc.GetPixel( 42, 24 );

                // Standard cleanup: restore the bitmap that was originally 
                // selected into the DC.
                dc.SelectObject( pOldBmp );
            }
            else
            {
                // TODO: handle error               
            }
        }
        else
        {
            // TODO: handle error
        }
    }
}

答案 2 :(得分:0)

我的回答是 BAD ,因为GetPixel方法很慢。没有删除它,只是把文字翻过来,只为那些来这里的人看到他们不应该做的事情。

类似

的东西
CDC mem_dc;
mem_dc.CreateCompatibleDC(dc);
CBitmap* old_bitmap=(CBitmap*)mem_dc.SelectObject(&bmp);

COLORREF cr_xy=mem_dc.GetPixel(x,y);

mem_dc.SelectObject(old_bitmap);
DeleteDC(mem_dc);

应该做的工作。