作为练习,我试图编写一段代码,可以在特定的x / y位置从MFC CBitmap对象中采样单个像素。
该类没有任何GetPixel
类型的接口,我看到的大部分信息都表明通过CBitmap::GetBitMapBits
复制CBitmap位的全部内容,这似乎效率极低。
是否无法通过指针访问字节数组并将其作为数组访问?
答案 0 :(得分:3)
您需要先在CDC(CDC::SelectObject)中选择CBitmap
。设备上下文有CDC::GetPixel成员。
答案 1 :(得分:1)
如果CBitmap
对象与device-independent bitmap(DIB,例如由CreateDIBSection()
创建)相关联,则可以获得指向直接访问位图像素(不复制)的指针致电GetObject()
。如果您在使用直接访问权限之前访问了位图像素GdiFlush()
,请务必致电by any other GDI functions。
如果CBitmap
与device-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);
应该做的工作。