Click here to Skip to main content
Licence CPOL
First Posted 19 Dec 2006
Views 44,072
Bookmarked 32 times

Comparing Two Bitmaps for Equality

By | 19 Dec 2006 | Article
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 BITMAPINFOHEADERs. If the BITMAPINFOHEADERs 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

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

PJ Arends



Canada Canada

Member



Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board. (secure sign-in)
 
Search this forum  
 FAQ
    Noise  Layout  Per page   
  Refresh
GeneralSmall Addition - detect minor changes PinmemberAlexander Shilonosov0:16 10 Jun '10  
Newsported to C [modified] PinmemberMikke813:49 28 Jan '10  
Questionam I doing somthing wrong? It crashes. PinmemberMember 13723394:09 11 Mar '08  
GeneralRe: am I doing somthing wrong? It crashes. PinmemberPJ Arends4:43 12 Mar '08  
GeneralExtending this Idea Pinmemberceejeeb0:36 27 Jan '07  
GeneralRe: Extending this Idea PinmemberPJ Arends9:52 27 Jan '07  
GeneralRe: Extending this Idea Pinmemberceejeeb2:43 28 Jan '07  
GeneralRe: Extending this Idea PinmemberPJ Arends9:17 28 Jan '07  
GeneralRe: Extending this Idea Pinmemberceejeeb0:35 5 Feb '07  
GeneralRe: Extending this Idea PinmemberPJ Arends9:58 6 Feb '07  
GeneralRe: Extending this Idea Pinmemberceejeeb3:55 7 Feb '07  
GeneralRe: Extending this Idea PinmemberPJ Arends7:43 7 Feb '07  
GetPixel() and SetPixel are slow, do doubt. But they are an easy way of doing it. To access the bitmap data directly is a lot more work for the programmer, but it definitely will run faster.
 
If you are going to go this way you have to take into account the colour depth of the bitmap. For colour depths of less than 16 bits per pixel your bitmap will have a colour table that the bitmap data indexes into. See GetDIBColorTable() and SetDIBColorTable().
 
For 16, 24 and 32 bit colour depths the data contains the actual colour values. The thing to remember about these is that every row in the bitmap data is DWORD aligned. 32 bits are the easiest to work with as in them every 32 bits is another colour and the DWORD alignment is automatic. 16 bits will have a dummy colour value at the end of every row if the width of the bitmap is an odd number, and 24 bits will have 1, 2 or 3 dummy bytes at the end of a row depending on the width of the bitmap. If you need to access the the individual red, green, blue, and alpha components of each colour than you also have to take into account the colour masks, but as long as both your images have the same colour depth that should not be neccesary.
 
See GetDIBits() and SetDIBits()
 
If you have any more questions you may get more and better answers if you ask them on the Visual C++ message board.
 
Good Luck!
 

You may be right
I may be crazy
-- Billy Joel --


Within you lies the power for good, use it!!!

GeneralRe: Extending this Idea PinmemberRafal Struzyk7:09 11 Jul '07  
GeneralRe: Extending this Idea PinmemberPJ Arends18:56 23 Mar '07  
GeneralGreat but far too simple PinmemberIntVestor6:53 21 Dec '06  
GeneralRe: Great but far too simple PinmemberPJ Arends7:04 21 Dec '06  
GeneralRe: Great but far too simple PinmemberLampros G5:41 10 Jan '07  

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Mobile
Web01 | 2.5.120529.1 | Last Updated 19 Dec 2006
Article Copyright 2006 by PJ Arends
Everything else Copyright © CodeProject, 1999-2012
Terms of Use
Layout: fixed | fluid