Click here to Skip to main content
Licence CPOL
First Posted 19 Dec 2006
Views 44,052
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  
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  
True, but if two bitmaps are different by a single pixel then they are by definition not equal. For my problem this is what I needed, I needed to know if they were different, not just similiar. One is getting into rather complicated territory when it comes to checking for similiarity between images. Whole industries are based on that kind of stuff.
IntVestor wrote:
Yet again great article.

ThanksSmile | :)
 

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


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

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