VBspeed / Colors / RGBToHSL
VBspeed © 2000-10, updated: 21-Nov-2001
RGBToHSL RGB to HSL, Formula 1
See also RGBToHSL2


Function RGBToHSL
Converts from the RGB to the HSL color model, more specifically converts Red, Green, and Blue values to Hue, Saturation, and Luminance values. It's the inverse of HSLToRGB.
Hue is interpreted as an angle in the color circle (0-360 degree, where 0°=360°). Red is positioned at 0°, green at 120°, and blue at 240°.
Saturation is a measure of the "purity" of a hue (0 to 100%). As saturation is decreased, the hue becomes more gray. A saturation value of zero results in a grayscale value.
Luminance (aka Lightness, Brightness) is the amount of black or white in a color (0 to 100%). Increasing lightness adds white to the hue. Decreasing lightness adds black to the hue.
The Formulas: conversion math between RGB and HSL comes in various dialects. Sometimes Red is positioned at 60°, sometimes Luminance and Saturation are calculated quite differently. Shown below are the two main schemes. If you actually do image editing via HSL you will probably find the version 2 approach superior (look at how Luminance is arrived at in version 1 - not such a brilliant concept of "Luminance").
    lMax = Maximum(R, G, B): lMin = Minimum(R, G, B)

Formula 1 - RGBToHSL and HSLToRGB:
    Luminance = 100 * lMax / 255
    Saturation = 100 * ((lMax - lMin) / lMax)

Formula 2 - RGBToHSL2 and HSLToRGB2:
    Luminance = 100 * (lMax + lMin) / 510
    If Luminance <= 50 Then
      Saturation = 100 * (lMax - lMin) / (lMax + lMin)
    Else
      Saturation = 100 * (lMax - lMin) / (510 - (lMax + lMin))
    End If
The HSL model covers a total of 360 x 101 x 101 = 3,672,360 definable colors, much less (ca 4.5 times) than the 16,777,216 defined in the RGB space. The number of actually different colors is even smaller, for example all colors with Luminance=0 are perfect black (RGB 0,0,0). Because of the differences between the two color models, converting between RGB and HSB values is not a transitive operation, that is, given an RGB value converted to HSB, when converting back to RGB the result may be different from the original. And vice-versa.
:: More color model infos
:: Watch HSL in action
It's practical to define a Type to hold HSL. The definition then looks like this:
    Type HSL
      Hue         As Long
      Saturation  As Long
      Luminance   As Long
    End Type
    
    Function RGBToHSL(ByVal RGBValue As Long) As HSL
Of course one could easily stuff HSL into a smaller structure (Integer+Byte+Byte), but Longs work faster and are more tolerant.
Use these functions (VB5/6-compatible) to verify the correctness of your Formula 1 code and your Formula 2 code.
Since all color models are physio/psychologically defined, minimal differences are allowed and should not discourage you. Color is a product of your mind. (Some people say everything is.)(I mean: *think* everything is.)
Code
RGBToHSL01
Public Function RGBToHSL01(ByVal RGBValue As Long) As HSL
' by Branco Medeiros, 1999, branco@apis.com.br
'   (adapted from Java.awt.Color.java)
' adjusted to our definition by Donald, 20011116
  Dim lMin As Long, lMax As Long, lDelta As Long
  Dim R As Long, G As Long, B As Long
  Dim nTemp As Single

  R = RGBValue And &HFF
  G = (RGBValue And &HFF00&) \ &H100&
  B = (RGBValue And &HFF0000) \ &H10000
  
  lMax = IIf(R > G, IIf(R > B, R, B), IIf(G > B, G, B))
  lMin = IIf(R < G, IIf(R < B, R, B), IIf(G < B, G, B))
  
  RGBToHSL01.Luminance = (lMax * 100) / 255
  
  If lMax > 0 Then
    lDelta = lMax - lMin
    RGBToHSL01.Saturation = (lDelta / lMax) * 100
    If lDelta > 0 Then
      If lMax = R Then
        nTemp = (G - B) / lDelta
      ElseIf lMax = G Then
        nTemp = 2 + (B - R) / lDelta
      Else
        nTemp = 4 + (R - G) / lDelta
      End If
      RGBToHSL01.Hue = nTemp * 60
      If RGBToHSL01.Hue < 0 Then
        RGBToHSL01.Hue = RGBToHSL01.Hue + 360
      End If
    End If
  End If
  
End Function
RGBToHSL02
Public Function RGBToHSL02(ByVal RGBValue As Long) As HSL
' by Donald (Sterex 1996), donald@xbeat.net, 20011116
  Dim R As Long, G As Long, B As Long
  Dim lMax As Long, lMin As Long
  Dim q As Single

  R = RGBValue And &HFF
  G = (RGBValue And &HFF00&) \ &H100&
  B = (RGBValue And &HFF0000) \ &H10000

  If R > G Then
    lMax = R: lMin = G
  Else
    lMax = G: lMin = R
  End If
  If B > lMax Then
    lMax = B
  ElseIf B < lMin Then
    lMin = B
  End If

  RGBToHSL02.Luminance = lMax * 100 / 255
  
  If lMax > lMin Then
    RGBToHSL02.Saturation = (lMax - lMin) * 100 / lMax
    q = 60 / (lMax - lMin)
    Select Case lMax
    Case R
      If B > G Then
        RGBToHSL02.Hue = q * (G - B) + 360
      Else
        RGBToHSL02.Hue = q * (G - B)
      End If
    Case G
      RGBToHSL02.Hue = q * (B - R) + 120
    Case B
      RGBToHSL02.Hue = q * (R - G) + 240
    End Select
  End If
  
End Function
RGBToHSL03
Public Function RGBToHSL03(ByVal RGBValue As Long) As HSL
  ' by Paul - wpsjr1@syix.com, 20011120
  Dim R As Long, G As Long, B As Long
  Dim lMax As Long, lMin As Long
  Dim q As Single
  Dim lDifference As Long
  Static Lum(255) As Long
  Static QTab(255) As Single
  Static init As Long
  
  If init = 0 Then
    For init = 2 To 255 ' 0 and 1 are both 0
      Lum(init) = init * 100 / 255
    Next
    For init = 1 To 255
      QTab(init) = 60 / init
    Next init
  End If

  R = RGBValue And &HFF
  G = (RGBValue And &HFF00&) \ &H100&
  B = (RGBValue And &HFF0000) \ &H10000

  If R > G Then
    lMax = R: lMin = G
  Else
    lMax = G: lMin = R
  End If
  If B > lMax Then
    lMax = B
  ElseIf B < lMin Then
    lMin = B
  End If

  RGBToHSL03.Luminance = Lum(lMax)
  
  lDifference = lMax - lMin
  If lDifference Then
    ' do a 65K 2D lookup table here for more speed if needed
    RGBToHSL03.Saturation = (lDifference) * 100 / lMax
    q = QTab(lDifference)
    Select Case lMax
    Case R
      If B > G Then
        RGBToHSL03.Hue = q * (G - B) + 360
      Else
        RGBToHSL03.Hue = q * (G - B)
      End If
    Case G
      RGBToHSL03.Hue = q * (B - R) + 120
    Case B
      RGBToHSL03.Hue = q * (R - G) + 240
    End Select
  End If
End Function
Calls
1RGBValue = &HE61C94
2RGBValue = &H1CE694
3RGBValue = &H1C1C1C
4RGBValue = &H0&
Charts
 VB5 Charts
CodeAuthorDopingNotes
RGBtoHSL01 Branco  
RGBtoHSL02 Donald  
RGBtoHSL03 Paul  
Call 1
311.577.834µs
21.491.007µs
11.000.677µs
Call 2
311.737.828µs
21.511.005µs
11.000.667µs
Call 3
329.057.473µs
21.890.486µs
11.000.257µs
Call 4
328.237.278µs
21.560.403µs
11.000.258µs
 VB6 Charts
CodeAuthorDopingNotes
RGBtoHSL01 Branco  
RGBtoHSL02 Donald  
RGBtoHSL03 Paul  
Call 1
313.059.015µs
21.521.047µs
11.000.691µs
Call 2
312.849.013µs
21.441.013µs
11.000.702µs
Call 3
333.168.660µs
21.890.493µs
11.000.261µs
Call 4
332.208.395µs
21.570.410µs
11.000.261µs
Notes & Conclusions
RGBToHSL01 has a severe problem, and the name of it is "IIf" aka "TWVBFEW" (the worst VB function ever written). But that's another story.
RGBToHSL03 demonstrates the power of LUTs (Look Up Tables).
Got comments? How to read all those numbers

top




VBspeed © 2000-10 by Donald Lessau