KnowledgeBase Archive

An Archive of Early Microsoft KnowledgeBase Articles

View on GitHub

Q29240: HOWTO: Converting Colors Between RGB and HLS (HBS)

Article: Q29240
Product(s): Microsoft Windows Software Development Kit
Version(s): WINDOWS:3.1,95; winnt:3.5,3.51,4.0
Operating System(s): 
Keyword(s): 
Last Modified: 11-MAY-2001

-------------------------------------------------------------------------------
The information in this article applies to:

- Microsoft Windows Software Development Kit (SDK) 3.1 
- Microsoft Win32 Application Programming Interface (API), used with:
   - Microsoft Windows NT Server versions 3.5, 3.51, 4.0 
   - Microsoft Windows NT Workstation versions 3.5, 3.51, 4.0 
-------------------------------------------------------------------------------

SUMMARY
=======

The code fragment below converts colors between RGB (Red, Green, Blue) and
HLS/HBS (Hue, Lightness, Saturation/Hue, Brightness, Saturation).

MORE INFORMATION
================


RGBtoHLS() takes a DWORD RGB value, translates it to HLS, and stores the results
in the global vars H, L, and S. HLStoRGB takes the current values of H, L, and S
and returns the equivalent value in an RGB DWORD. The vars H, L, and S are only
written to by:

1. RGBtoHLS (initialization)

2. The scroll bar handlers

A point of reference for the algorithms is Foley and Van Dam, "Fundamentals of
Interactive Computer Graphics," Pages 618-19. Their algorithm is in floating
point. CHART implements a less general (hardwired ranges) integral algorithm.

There are potential round-off errors throughout this sample. ((0.5 + x)/y)
without floating point is phrased ((x + (y/2))/y), yielding a very small
round-off error. This makes many of the following divisions look strange.

     */ 
     #define  HLSMAX   RANGE /* H,L, and S vary over 0-HLSMAX */ 
     #define  RGBMAX   255   /* R,G, and B vary over 0-RGBMAX */ 
                             /* HLSMAX BEST IF DIVISIBLE BY 6 */ 
                             /* RGBMAX, HLSMAX must each fit in a byte. */ 

     /* Hue is undefined if Saturation is 0 (grey-scale) */ 
     /* This value determines where the Hue scrollbar is */ 
     /* initially set for achromatic colors */ 
     #define UNDEFINED (HLSMAX*2/3)

     void  RGBtoHLS(lRGBColor)

     DWORD lRGBColor;
     {
        WORD R,G,B;          /* input RGB values */ 
        BYTE cMax,cMin;      /* max and min RGB values */ 
     WORD  Rdelta,Gdelta,Bdelta; /* intermediate value: % of spread from max

     */ 
        /* get R, G, and B out of DWORD */ 
        R = GetRValue(lRGBColor);
        G = GetGValue(lRGBColor);
        B = GetBValue(lRGBColor);

        /* calculate lightness */ 
        cMax = max( max(R,G), B);
        cMin = min( min(R,G), B);
        L = ( ((cMax+cMin)*HLSMAX) + RGBMAX )/(2*RGBMAX);

        if (cMax == cMin) {           /* r=g=b --> achromatic case */ 
           S = 0;                     /* saturation */ 
           H = UNDEFINED;             /* hue */ 
        }
        else {                        /* chromatic case */ 
           /* saturation */ 
           if (L <= (HLSMAX/2))
              S = ( ((cMax-cMin)*HLSMAX) + ((cMax+cMin)/2) ) / (cMax+cMin);
           else
              S = ( ((cMax-cMin)*HLSMAX) + ((2*RGBMAX-cMax-cMin)/2) )
                 / (2*RGBMAX-cMax-cMin);

           /* hue */ 
        Rdelta = ( ((cMax-R)*(HLSMAX/6)) + ((cMax-cMin)/2) ) / (cMax-cMin);
        Gdelta = ( ((cMax-G)*(HLSMAX/6)) + ((cMax-cMin)/2) ) / (cMax-cMin);
        Bdelta = ( ((cMax-B)*(HLSMAX/6)) + ((cMax-cMin)/2) ) / (cMax-cMin);

           if (R == cMax)
              H = Bdelta - Gdelta;
           else if (G == cMax)
              H = (HLSMAX/3) + Rdelta - Bdelta;
           else /* B == cMax */ 
              H = ((2*HLSMAX)/3) + Gdelta - Rdelta;

           if (H < 0)
              H += HLSMAX;
           if (H > HLSMAX)
              H -= HLSMAX;
        }
     }
     /* utility routine for HLStoRGB */ 
     WORD HueToRGB(n1,n2,hue)
     WORD n1;
     WORD n2;
     WORD hue;
     {
        /* range check: note values passed add/subtract thirds of range */ 
        if (hue < 0)
           hue += HLSMAX;
   
        if (hue > HLSMAX)
           hue -= HLSMAX;

        /* return r,g, or b value from this tridrant */ 
        if (hue < (HLSMAX/6))
            return ( n1 + (((n2-n1)*hue+(HLSMAX/12))/(HLSMAX/6)) );
        if (hue < (HLSMAX/2))
           return ( n2 );
        if (hue < ((HLSMAX*2)/3))
           return ( n1 +    (((n2-n1)*(((HLSMAX*2)/3)-hue)+(HLSMAX/12))/(HLSMAX/6))
     );
        else
           return ( n1 );
     }

     DWORD HLStoRGB(hue,lum,sat)
     WORD hue;
     WORD lum;
     WORD sat;
      {
         WORD R,G,B;                /* RGB component values */ 
        WORD  Magic1,Magic2;       /* calculated magic numbers (really!) */ 

        if (sat == 0) {            /* achromatic case */ 
           R=G=B=(lum*RGBMAX)/HLSMAX;
           if (hue != UNDEFINED) {
              /* ERROR */ 
            }
         }
        else  {                    /* chromatic case */ 
           /* set up magic numbers */ 
           if (lum <= (HLSMAX/2))
              Magic2 = (lum*(HLSMAX + sat) + (HLSMAX/2))/HLSMAX;
           else
              Magic2 = lum + sat - ((lum*sat) + (HLSMAX/2))/HLSMAX;
           Magic1 = 2*lum-Magic2;

           /* get RGB, change units from HLSMAX to RGBMAX */ 
           R = (HueToRGB(Magic1,Magic2,hue+(HLSMAX/3))*RGBMAX +
     (HLSMAX/2))/HLSMAX;
           G = (HueToRGB(Magic1,Magic2,hue)*RGBMAX + (HLSMAX/2)) / HLSMAX;
           B = (HueToRGB(Magic1,Magic2,hue-(HLSMAX/3))*RGBMAX +
     (HLSMAX/2))/HLSMAX;
        }
        return(RGB(R,G,B));
      }

Additional query words: 3.00 3.10 3.50 4.00 color RGB HLS HBS win16sdk

======================================================================
Keywords          :  
Technology        : kbAudDeveloper kbSDKSearch kbWin32sSearch kbWin32API kbWinSDKSearch
Version           : WINDOWS:3.1,95; winnt:3.5,3.51,4.0
Issue type        : kbhowto

=============================================================================

THE INFORMATION PROVIDED IN THE MICROSOFT KNOWLEDGE BASE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. MICROSOFT DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, INCLUDING THE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROSOFT CORPORATION OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER INCLUDING DIRECT, INDIRECT, INCIDENTAL, CONSEQUENTIAL, LOSS OF BUSINESS PROFITS OR SPECIAL DAMAGES, EVEN IF MICROSOFT CORPORATION OR ITS SUPPLIERS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES SO THE FOREGOING LIMITATION MAY NOT APPLY.

Copyright Microsoft Corporation 1986-2002.