Color Matching

Within the MapDemo demo, while the USMAP01 bitmap is displayed, a WM_ LBUTTONDOWN message calls the ColorCheckMap function, which passes three parameters: the window handle (hwnd) and the two mouse-click coordinates derived from the lParam argument accompanying the mouse-button event message.

      case WM_LBUTTONDOWN:
         ...
            CoordCheckMap( hwnd, LOWORD( lParam ),
                                 HIWORD( lParam ) );
         break;

The mouse-click x-axis coordinate is reported in the low word of lParam, and the high word reports the y-axis coordinate.

The ColorCheckMap function appears to be a simple process, but it does require a bit of finesse to comply with Windows’ requirements.

void ColorCheckMap( HWND hwnd, WORD xCoord, WORD yCoord )
{
   HDC      hdc;
   DWORD    RColor;
   WORD     SColor;
   int      i;
   ...
   hdc = GetDC( hwnd );
   RColor = GetPixel( hdc, xCoord, yCoord );
         // need RGB palette-relative color value
   ReleaseDC( hwnd, hdc );

The GetPixel function returns a DWORD value containing the RGB color value for the selected pixel in the form 0x00rrggbb. However, while this is the color of the pixel itself, the data identifying the several states consists of the simpler palette-index values rather than their RGB equivalents. Ergo, the next task is to match the color returned to the bitmap’s palette, retrieving the palette index.

To accomplish this, the first requirement is to lock the pointer to the global palette information (pGLP) and then lock a handle to the logical palette (hGPal) before calling the CreatePalette and RealizePalette functions to temporarily re-create and activate the bitmap palette.

   LocalLock( hGLP );
   LocalLock( hGPal );
         // lock and create palette for reference
   hGPal = CreatePalette( pGLP );
   if( hGPal == NULL ) ErrorMsg( “Palette not found!” );
         // make palette active for device context
   RealizePalette( hdc );
         // get palette index for comparison
   SColor = GetNearestPaletteIndex( hGPal, (COLORREF) RColor );
         // unlock everything but don’t delete palette
   LocalUnlock( hGLP );
   LocalUnlock( hGPal );

Finally, after the palette is created (or re-created), the GetNearestPaletteIndex function returns the palette-index value as SColor. Of course, before finishing, the two memory locks on the global and re-created palettes should be released. Neither, however, should be freed from memory since they may be needed again.

Once the palette index has been retrieved, a pair of simple loops is all that is required to identify the corresponding state or, in the case of the upper New England states, to display the USMAP02 bitmap30.

   for( i=0; i<12; i++ )
      if( SColor == NewEngland[i] )
                // if this is any New England state, switch maps
         PostMessage( hwnd, WM_COMMAND, IDM_MAP2, 0L );
   for( i=0; i<=StateColors; i++ )
      if( SColor == CState[i].Color )
         LocationMsg( CState[i].State );
   MessageBeep( MB_ICONASTERISK );
}

Once the state or area is identified, a variety of other responses can be implemented as elaborately or simply as desired. In this demo, a simple pop-up dialog box with a “Welcome to the great state of xxxxxx” message appears, identifying the state selected.

The data matching the states and colors is provided by a simple structure listing these by name and palette index. An abbreviated sample follows:

ColorState CState[StateColors] =
{  “Arizona”,         2,       “New Mexico”,      7,
   “Oklahoma”,        9,       “Georgia”,        11,
   “Oregon”,         12,       “Colorado”,       13,
   “Missouri”,       15,       “South Carolina”, 16,
   “Texas”,          17,       “Hawaii”,         18,
   ...

© 1998 SYBEX Inc. All rights reserved.