访问 CBitmap 对象中的单个像素
Access individual pixels in CBitmap object
作为练习,我正在尝试编写一段代码,它可以在特定 x/y 位置从 MFC CBitmap 对象中采样单个像素。
class没有任何GetPixel
类型的接口,而且我看到的大部分资料都是通过CBitmap::GetBitMapBits
复制CBitmap位的全部内容,这似乎非常效率低下。
有没有办法通过指针访问字节数组并将其作为数组访问?
我的回答是 不好 因为 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);
应该完成这项工作。
您需要select CBitmap
成为 CDC (CDC::SelectObject) first. The device context has a CDC::GetPixel 成员。
如果 CBitmap
对象在使用直接访问之前与 device-independent bitmap (DIB, created by CreateDIBSection()
for instance), you can get a pointer to directly access the bitmap pixels (without copying) by calling GetObject()
. Make sure to call GdiFlush()
if you have accessed the bitmap pixels by any other GDI functions 关联。
如果CBitmap
与device-dependent bitmap(DDB,也称为兼容位图)关联,使用哪种方法取决于多少像素你想访问。
- 如果只需要访问少数像素,您可以走
CDC::SelectObject()
, CDC::GetPixel()
路线。如果您想读取更多像素,这将非常慢。
- 要访问大量像素,您可以使用
CBitmap::GetBitMapBits()
or 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
}
}
}
作为练习,我正在尝试编写一段代码,它可以在特定 x/y 位置从 MFC CBitmap 对象中采样单个像素。
class没有任何GetPixel
类型的接口,而且我看到的大部分资料都是通过CBitmap::GetBitMapBits
复制CBitmap位的全部内容,这似乎非常效率低下。
有没有办法通过指针访问字节数组并将其作为数组访问?
我的回答是 不好 因为 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);
应该完成这项工作。
您需要select CBitmap
成为 CDC (CDC::SelectObject) first. The device context has a CDC::GetPixel 成员。
如果 CBitmap
对象在使用直接访问之前与 device-independent bitmap (DIB, created by CreateDIBSection()
for instance), you can get a pointer to directly access the bitmap pixels (without copying) by calling GetObject()
. Make sure to call GdiFlush()
if you have accessed the bitmap pixels by any other GDI functions 关联。
如果CBitmap
与device-dependent bitmap(DDB,也称为兼容位图)关联,使用哪种方法取决于多少像素你想访问。
- 如果只需要访问少数像素,您可以走
CDC::SelectObject()
,CDC::GetPixel()
路线。如果您想读取更多像素,这将非常慢。 - 要访问大量像素,您可以使用
CBitmap::GetBitMapBits()
orGetDIBits()
。当您只需要访问部分位图像素时,后者可能更有效,因为它具有定义要复制的扫描线范围的参数。
无论哪种情况,当您需要逐像素访问时,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
}
}
}