Help and Support
 

powered byLive Search

How To Converting Colors Between RGB and HLS (HBS)

Article ID:29240
Last Review:November 21, 2006
Revision:3.3
This article was previously published under Q29240

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));
    }
				

APPLIES TO
Microsoft Windows Software Development Kit 3.1
Microsoft Win32 Application Programming Interface, when used with:
  Microsoft Windows NT Server 3.5
  Microsoft Windows NT Server 3.51
  Microsoft Windows NT Server 4.0 Standard Edition
  Microsoft Windows NT Workstation 3.5
  Microsoft Windows NT Workstation 3.51
  Microsoft Windows NT Workstation 4.0 Developer Edition

Back to the top

Keywords: 
kbhowto KB29240

Article Translations

 

Other Support Options

  • Need More Help?
    Contact a Support professional by Email, Online or Phone.
  • Customer Service
    For non-technical assistance with product purchases, subscriptions, online services, events, training courses, corporate sales, piracy issues, and more.
  • Newsgroups
    Pose a question to other users. Discussion groups and Forums about specific Microsoft products, technologies, and services.