Comparing Two Bitmaps for Equality
Code snippet that compares two HBITMAP handles to see if the bitmaps they contain are the same
Introduction
Presented here is a simple method to compare two HBITMAP
handles to see if they contain the same bitmap. The code itself is nothing fancy, so I will just include it in the article text. No separate download or demo application is needed.
How to Compare Two Bitmaps for Equality
The first thing to do is compare the HBITMAP
handles themselves. If they are the same handle, then the two bitmaps are obviously equal. If one of the handles is NULL
, then they are obviously not equal. If the HBITMAP
handles are different and not NULL
, then use GetDIBits
to fill two BITMAPINFO
structures -- one for each bitmap -- and compare the BITMAPINFOHEADER
s. If the BITMAPINFOHEADER
s contain different data, then the bitmaps are different. If they contain the same data, then the next step is to compare the actual bitmap data bits.
The Code
/////////////////////////////////////////////////////////////////////////////
//
// CompareBitmaps
// Compares two HBITMAPs to see if they contain the same image
//
// Parameters :
// HBitmapLeft [in] : The HBITMAP handles that are to be compared
// HBitmapRight [in] :
//
// Returns :
// true if the bitmaps are the same
// false if they are different
//
/////////////////////////////////////////////////////////////////////////////
bool CompareBitmaps(HBITMAP HBitmapLeft, HBITMAP HBitmapRight)
{
if (HBitmapLeft == HBitmapRight)
{
return true;
}
if (NULL == HBitmapLeft || NULL == HBitmapRight)
{
return false;
}
bool bSame = false;
HDC hdc = GetDC(NULL);
BITMAPINFO BitmapInfoLeft = {0};
BITMAPINFO BitmapInfoRight = {0};
BitmapInfoLeft.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
BitmapInfoRight.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
if (0 != GetDIBits(hdc, HBitmapLeft, 0, 0, NULL, &BitmapInfoLeft, DIB_RGB_COLORS) &&
0 != GetDIBits(hdc, HBitmapRight, 0, 0, NULL, &BitmapInfoRight, DIB_RGB_COLORS))
{
// Compare the BITMAPINFOHEADERs of the two bitmaps
if (0 == memcmp(&BitmapInfoLeft.bmiHeader, &BitmapInfoRight.bmiHeader,
sizeof(BITMAPINFOHEADER)))
{
// The BITMAPINFOHEADERs are the same so now compare the actual bitmap bits
BYTE *pLeftBits = new BYTE<BitmapInfoLeft.bmiHeader.biSizeImage>;
BYTE *pRightBits = new BYTE<BitmapInfoRight.bmiHeader.biSizeImage>;
BYTE *pByteLeft = NULL;
BYTE *pByteRight = NULL;
PBITMAPINFO pBitmapInfoLeft = &BitmapInfoLeft;
PBITMAPINFO pBitmapInfoRight = &BitmapInfoRight;
// calculate the size in BYTEs of the additional
// memory needed for the bmiColor table
int AdditionalMemory = 0;
switch (BitmapInfoLeft.bmiHeader.biBitCount)
{
case 1:
AdditionalMemory = 1 * sizeof(RGBQUAD);
break;
case 4:
AdditionalMemory = 15 * sizeof(RGBQUAD);
break;
case 8:
AdditionalMemory = 255 * sizeof(RGBQUAD);
break;
case 16:
case 32:
AdditionalMemory = 2 * sizeof(RGBQUAD);
}
if (AdditionalMemory)
{
// we have to allocate room for the bmiColor table that will be
// attached to our BITMAPINFO variables
pByteLeft = new BYTE[sizeof(BITMAPINFO) + AdditionalMemory];
if (pByteLeft)
{
memset(pByteLeft, 0, sizeof(BITMAPINFO) + AdditionalMemory);
memcpy(pByteLeft, pBitmapInfoLeft, sizeof(BITMAPINFO));
pBitmapInfoLeft = (PBITMAPINFO)pByteLeft;
}
pByteRight = new BYTE[sizeof(BITMAPINFO) + AdditionalMemory];
if (pByteRight)
{
memset(pByteRight, 0, sizeof(BITMAPINFO) + AdditionalMemory);
memcpy(pByteRight, pBitmapInfoRight, sizeof(BITMAPINFO));
pBitmapInfoRight = (PBITMAPINFO)pByteRight;
}
}
if (pLeftBits && pRightBits && pBitmapInfoLeft && pBitmapInfoRight)
{
// zero out the bitmap bit buffers
memset(pLeftBits, 0, BitmapInfoLeft.bmiHeader.biSizeImage);
memset(pRightBits, 0, BitmapInfoRight.bmiHeader.biSizeImage);
// fill the bit buffers with the actual bitmap bits
if (0 != GetDIBits(hdc, HBitmapLeft, 0,
pBitmapInfoLeft->bmiHeader.biHeight, pLeftBits, pBitmapInfoLeft,
DIB_RGB_COLORS) && 0 != GetDIBits(hdc, HBitmapRight, 0,
pBitmapInfoRight->bmiHeader.biHeight, pRightBits, pBitmapInfoRight,
DIB_RGB_COLORS))
{
// compare the actual bitmap bits of the two bitmaps
bSame = 0 == memcmp(pLeftBits, pRightBits,
pBitmapInfoLeft->bmiHeader.biSizeImage);
}
}
// clean up
delete[] pLeftBits;
delete[] pRightBits;
delete[] pByteLeft;
delete[] pByteRight;
}
}
ReleaseDC(NULL, hdc);
return bSame;
}
History
- 19 December, 2006 -- Original version posted
- 12 March, 2008 -- Article edited and moved to The Code Project main article base