14,241,248 members

# Creating a color cursor from a bitmap

Rate this:
14 Oct 2003
An article explaining how to convert a color HBITMAP to HCURSOR

## Introduction

This article focuses on creating a color cursor from a HBITMAP. First it explains the steps performed by windows to display a cursor on the screen and how we can create the necessary information needed by windows to create our cursor. Then it explains the steps needed to convert a color HBITMAP to an HCURSOR. Finally it shows a utility class, which converts HBITMAP to HCURSOR.

## How Windows displays a cursor?

In Windows, transparency of the cursor is achieved by the use of two masks. One is called the AND mask and the other is called the XOR mask. In order to display a cursor in the screen, the system first performs a logical AND operation on the screen with the AND mask. In this process, the pixels in the screen corresponding to the 1 bits in the AND mask remains unchanged and the pixels corresponding to the 0 bits in the AND mask becomes modified. Then the system will perform a logical XOR operation on the screen with the XOR mask. In this process, the pixels in screen corresponding to the 0 bits in the XOR mask remains unchanged and the pixels corresponding to the non 0 bits gets modified.

###### Figure 2: A sample color bitmap to be converted as a cursor

Now lets try to realize the above cursor to its AND/XOR masks so that the system can display the cursor using these masks. First let us create the AND mask. The above cursor contains a red colored rectangle in the center. So all the other pixels should be transparent. Assuming that the size of the cursor is 8*8 and the size of the rectangle is 4*4 we shall define the AND mask as shown below.

1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 0 0 0 0 1 1
1 1 0 0 0 0 1 1
1 1 0 0 0 0 1 1
1 1 0 0 0 0 1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
###### Figure 3: AND mask for the sample color bitmap in Figure 2

In the above AND mask, the bits corresponding to the red rectangle are 0 and the rest of the bits are 1. This is because, we need only the red rectangle to be displayed as the cursor and the rest of the area should be transparent. When the system performs a logical AND operation of this mask to the screen, the pixels in the screen corresponding to the red rectangle becomes modified and the rest remains unchanged.

Now let us create the XOR mask for our cursor. As we need to display the red rectangle as cursor on the screen and the rest as transparent, we need to make the bits in the XOR mask corresponding to the red rectangle as Red (RGB (255,0,0)) and the rest as 0.

0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 R R R R 0 0
0 0 R R R R 0 0
0 0 R R R R 0 0
0 0 R R R R 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
###### Figure 4: XOR mask for the sample color bitmap in Figure 2

The R in the above XOR mask represents RGB (255,0,0). I.e., red color. When the system performs logical XOR of this XOR mask to the screen, the R pixels are updated in the screen and the pixels corresponding to the 0 bits remains unchanged.

So finally, after performing logical AND of the AND mask followed by logical XOR of the XOR mask to the screen, the screen under our cursor region look like as shown below.

S S S S S S S S
S S S S S S S S
S S R R R R S S
S S R R R R S S
S S R R R R S S
S S R R R R S S
S S S S S S S S
S S S S S S S S
###### Figure 5: State of the screen area under the cursor after applying AND and XOR masks

Where the S represents the original screen pixels and the R represents the red color pixels.

## Converting HBITMAP to HCURSOR

Now let us try to create these AND/XOR masks from an HBITMAP. The following code fragment will do it for you.

void CColorCursor::GetMaskBitmaps(HBITMAP hSourceBitmap,
COLORREF clrTransparent,
HBITMAP &hAndMaskBitmap,
HBITMAP &hXorMaskBitmap)
{
HDC hDC        = ::GetDC(NULL);
HDC hMainDC      = ::CreateCompatibleDC(hDC);
HDC hAndMaskDC      = ::CreateCompatibleDC(hDC);
HDC hXorMaskDC      = ::CreateCompatibleDC(hDC);

//Get the dimensions of the source bitmap
BITMAP bm;
::GetObject(hSourceBitmap,sizeof(BITMAP),&bm);

hAndMaskBitmap  = ::CreateCompatibleBitmap(hDC,bm.bmWidth,bm.bmHeight);
hXorMaskBitmap  = ::CreateCompatibleBitmap(hDC,bm.bmWidth,bm.bmHeight);

//Select the bitmaps to DC
HBITMAP hOldMainBitmap = (HBITMAP)::SelectObject(hMainDC,hSourceBitmap);
HBITMAP hOldAndMaskBitmap  = (HBITMAP)::SelectObject(hAndMaskDC,
hAndMaskBitmap);
HBITMAP hOldXorMaskBitmap  = (HBITMAP)::SelectObject(hXorMaskDC,
hXorMaskBitmap);

//Scan each pixel of the souce bitmap and create the masks
COLORREF MainBitPixel;
for(int x=0;x<bm.bmWidth;++x)
{
for(int y=0;y<bm.bmHeight;++y)
{
MainBitPixel = ::GetPixel(hMainDC,x,y);
if(MainBitPixel == clrTransparent)
{
::SetPixel(hAndMaskDC,x,y,RGB(255,255,255));
::SetPixel(hXorMaskDC,x,y,RGB(0,0,0));
}
else
{
::SetPixel(hAndMaskDC,x,y,RGB(0,0,0));
::SetPixel(hXorMaskDC,x,y,MainBitPixel);
}
}
}

::SelectObject(hMainDC,hOldMainBitmap);
::SelectObject(hAndMaskDC,hOldAndMaskBitmap);
::SelectObject(hXorMaskDC,hOldXorMaskBitmap);

::DeleteDC(hXorMaskDC);
::DeleteDC(hAndMaskDC);
::DeleteDC(hMainDC);

::ReleaseDC(NULL,hDC);
}

The above code creates two memory DC and two memory bitmaps for the AND/XOR masks. Then it examines the source bitmap pixels and creates the masks as we have explained in the theory part.

Now what we need is to use these masks and create a cursor using the well known CreateIconIndirect() SDK call as shown below.

ICONINFO iconinfo = {0};
iconinfo.fIcon        = FALSE;
iconinfo.xHotspot       = 0;
iconinfo.yHotspot       = 0;
iconinfo.hbmMask        = hAndMask;
iconinfo.hbmColor       = hXorMask;

HCURSOR hCursor = ::CreateIconIndirect(&iconinfo);

That's it. We have successfully created a color cursor from a bitmap.

## Using the code

It is always better to create a utility class for doing these things for us. So I created one called CColorCursor having the following interfaces.

static void GetMaskBitmaps(HBITMAP hSourceBitmap,COLORREF clrTransparent,
HBITMAP &hAndMaskBitmap,HBITMAP &hXorMaskBitmap);
static HCURSOR CreateCursorFromBitmap(HBITMAP hSourceBitmap,COLORREF
clrTransparent, DWORD   xHotspot,DWORD   yHotspot);

The first interface is called from the second one to create the masks. The first one is also made public because we can use it to get an idea of what is happening inside. I used the first interface in my test application to display the AND/XOR mask as shown in the first figure and the second one to create cursor directly.

Now we are approaching towards the end of this article. I will finish it by showing the usage of this utility class.

#include "ColorCursor.h"

....

HBITMAP hSourceBitmap  = c.
HCURSOR hCursor = CColorCursor::CreateCursorFromBitmap(
hSourceBitmap,RGB(0,0,0),0,0);

## A word of caution

The utility class explained above will try to create the cursor in the same size of the input source bitmap. But in Windows, there are some limitations for the size of the cursor. So it is always safe to pass bitmaps having standard size. Otherwise the result may be unpredictable.

## License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

## About the Author

 Web Developer India
No Biography provided

## Comments and Discussions

 First Prev Next
 Thank you! Ben Postma12-Aug-15 5:10 Ben Postma 12-Aug-15 5:10
 My vote of 5 kanalbrummer1-Sep-13 23:14 kanalbrummer 1-Sep-13 23:14
 Using this code to create drag and drop functionality in a custom control Ben Aldhouse20-Feb-13 21:44 Ben Aldhouse 20-Feb-13 21:44
 Color are not show correctly sometimes emilysu25-Jan-07 11:48 emilysu 25-Jan-07 11:48
 GetMaskBitmaps substitution without GetPixel/SetPixel. [modified] Yuri Machlin20-Jul-06 10:10 Yuri Machlin 20-Jul-06 10:10
 Re: GetMaskBitmaps substitution without GetPixel/SetPixel. NeWi26-Jan-07 9:29 NeWi 26-Jan-07 9:29
 Resource leak nikidawg64-Jan-06 12:08 nikidawg6 4-Jan-06 12:08
 Problem under win2k Triac28-Sep-04 1:33 Triac 28-Sep-04 1:33
 Can I use your code? Alanator6-Jun-04 17:52 Alanator 6-Jun-04 17:52
 Hi, I was wondering if I could use your CColorCursor class in commerical game code that I'm writing? Is it public domain? What are your restrictions Jiju? Thanks, Alan
 Re: Can I use your code? Jiju George T8-Jun-04 15:27 Jiju George T 8-Jun-04 15:27
 Re: Can I use your code? Alanator9-Jun-04 5:13 Alanator 9-Jun-04 5:13
 Create Color Cursor from Bitmap in Win98 Anonymous4-Feb-04 17:38 Anonymous 4-Feb-04 17:38
 Re: Create Color Cursor from Bitmap in Win98 Jiju George T4-Feb-04 18:53 Jiju George T 4-Feb-04 18:53
 Good job! WREY15-Oct-03 23:49 WREY 15-Oct-03 23:49
 Re: Cute! Ummm.................... Anonymous15-Oct-03 8:20 Anonymous 15-Oct-03 8:20
 Re: Cute! Ummm.................... Anonymous15-Oct-03 8:21 Anonymous 15-Oct-03 8:21
 Re: Cute! Ummm.................... WREY15-Oct-03 23:24 WREY 15-Oct-03 23:24
 Last Visit: 20-Jul-19 9:49     Last Update: 20-Jul-19 9:49 Refresh 1

General    News    Suggestion    Question    Bug    Answer    Joke    Praise    Rant    Admin

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

Article
Posted 14 Oct 2003

115.4K views
3.6K downloads
50 bookmarked