-
Feb 5th, 2025, 01:31 AM
#1
RGB to HSB with *Byte* values??
I'm trying to convert a standard RGB color value to HSB as understood by the Windows Ribbon. The macro is:
Code:
typedef DWORD UI_HSBCOLOR;
__inline UI_HSBCOLOR UI_HSB(BYTE hue, BYTE saturation, BYTE brightness)
{
return hue | (saturation << 8) | (brightness << 16);
}
The problem is every conversion method I can find is based on float (Single) between 0 and 1.0, while obviously a Byte is 0-255.
There's a Windows API to convert to HSL (ColorRGBToHLS), but that's apparently different. And every conversion method for HSL to HSB is also based on float.
The documentation is also useless and uses floats... https://learn.microsoft.com/en-us/wi...ert-rgb-to-hsb
It's beyond obnoxious that their documentation is basically "you have to use photo editing software to find hard coded hex values".
Any idea how to properly convert RGB to HSB based on 0-255 Byte values?
-
Feb 5th, 2025, 02:06 AM
#2
Re: RGB to HSB with *Byte* values??
Copilot says:
To convert HSB (Hue, Saturation, Brightness) values from floats (ranging from 0.0 to 1.0) to bytes (ranging from 0 to 255) without converting to RGB, you simply need to scale the float values to the byte range.
Conversion Formula
byte byteValue = (byte)(floatValue * 255);
-
Feb 5th, 2025, 05:00 AM
#3
Re: RGB to HSB with *Byte* values??
Copilot says is a step up from drunk schizophrenic ranting on corner says, but only barely
-
Feb 5th, 2025, 05:58 AM
#4
Re: RGB to HSB with *Byte* values??
Ok I found a C++ saple; can someone better with the language double check I got it right? Especially the differences in how division behaves?
Code:
' void CTheme::RGBToHSB(COLORREF rgb, BYTE& hue, BYTE& saturation, BYTE& brightness)
Private Sub RGBToHSB(ByVal rgb As Long, hue As Byte, saturation As Byte, brightness As Byte)
' {
' BYTE r = GetRValue(rgb);
Dim r As Byte = GetRValue(rgb)
' BYTE g = GetGValue(rgb);
Dim g As Byte = GetGValue(rgb)
' BYTE b = GetBValue(rgb);
Dim b As Byte = GetBValue(rgb)
' BYTE minRGB = min(min(r, g), b);
Dim minRGB As Byte = min(min(r, g), b)
' BYTE maxRGB = max(max(r, g), b);
Dim maxRGB As Byte = max(max(r, g), b)
' BYTE delta = maxRGB - minRGB;
Dim delta As Byte = maxRGB - minRGB
' double l = maxRGB;
Dim l As Double = maxRGB
' double s = 0.0;
Dim s As Double = 0.0
' double h = 0.0;
Dim h As Double = 0.0
' if (maxRGB == 0)
' {
' hue = 0;
' saturation = 0;
' brightness = 0;
' return;
' }
If maxRGB = 0 Then
hue = 0
saturation = 0
brightness = 0
Exit Sub
End If
' if (maxRGB)
' s = (255.0 * delta) / maxRGB;
If (maxRGB) Then s = (255.0 * delta) \ maxRGB
' if (static_cast<BYTE>(s) != 0)
' {
If CByte(s) <> 0 Then
' if (r == maxRGB)
' h = 0 + 43 * static_cast<double>(g - b) / delta;
If (r = maxRGB) Then
h = 0 + 43 * CDbl(g - b) \ delta
' else if (g == maxRGB)
' h = 85 + 43 * static_cast<double>(b - r) / delta;
ElseIf (g = maxRGB) Then
h = 85 + 43 * CDbl(b - r) \ delta
' else if (b == maxRGB)
' h = 171 + 43 * static_cast<double>(r - g) / delta;
ElseIf (b = maxRGB) Then
h = 171 + 43 * CDbl(r - g) \ delta
End If
' }
' else
' h = 0.0;
Else
h = 0.0
End If
' hue = static_cast<BYTE>(h);
' saturation = static_cast<BYTE>(s);
' brightness = static_cast<BYTE>(l);
hue = CByte(h)
saturation = CByte(s)
brightness = CByte(l)
' }
End Sub
'helper macros:
Public Function min(ByVal x As Long, ByVal y As Long) As Long: Return If(x < y, x, y): End Function
Public Function max(ByVal x As Long, ByVal y As Long) As Long: Return If(x > y, x, y): End Function
Public Function GetRValue(ByVal rgb As Long) As Long: Return RGB_R(rgb): End Function
Public Function GetGValue(ByVal rgb As Long) As Long: Return RGB_G(rgb): End Function
Public Function GetBValue(ByVal rgb As Long) As Long: Return RGB_B(rgb): End Function
Last edited by fafalone; Feb 5th, 2025 at 06:02 AM.
-
Feb 5th, 2025, 08:09 AM
#5
Re: RGB to HSB with *Byte* values??
Personally, I was going to say precisely what CoPilot said. In VB6 terms:
Code:
Dim bbH as Byte
bbH = CByte(fH * 255&)
Where fH is a float (single or double) from 0 to 1 (inclusive) that represents HUE. You'd do the same for Saturation and Lightness or Brightness. This will work for either HSL or HSB values that are 0 to 1.
I've done precisely this many times through the years.
One trick is to realize that, when represented from 0 to 1, the 1 is included, so we must multiply by 255, not 256. That's a common mistake.
To convert back to the 0 to 1 range, simply divide by 255! (a float), with the / operator.
Also, I'm not sure I've ever seen either HSL or HSB represented as hex. With respect to colors, that seems to be almost exclusively an RGB thing. However, one does have to be careful as to whether or not it's represented as Code-BGR (as it is for OLE colors), ABGR, BGR, ARGB, or RGB, which are all other alternative hex representations in various situations.
Last edited by Elroy; Feb 5th, 2025 at 08:18 AM.
Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.
-
Feb 5th, 2025, 08:51 AM
#6
Re: RGB to HSB with *Byte* values??
Do you want to use purely integer operations converting RGB with byte components to HSB with byte components or are you ok using floats internally to do the conversion and as a final step convert the FP results to bytes?
As already mention you can very easily "quantize" the floats when they are normalized (i.e. 0 to 1 range) by simply multiplying with 255 which should be obvious IMO.
Note: They used 240 as upper bound in ColorRGBToHLS API which is beyond comprehension but probably has some reasoning behind this choice.
cheers,
</wqw>
-
Feb 5th, 2025, 09:44 AM
#7
Re: RGB to HSB with *Byte* values??
I don't mind using float/double internally so long as rounding/precision issues don't mess with the final result. I'll probably rig up something to test the code I ported if no one has a proven solution. Just thought of maybe looking around PhotoDemon's source for something too ... Good chance it has related code .
-
Feb 5th, 2025, 09:48 AM
#8
Re: RGB to HSB with *Byte* values??
I'm personally using this
Code:
Private Declare Function OleTranslateColor Lib "oleaut32" (ByVal lOleColor As Long, ByVal lHPalette As Long, ByVal lColorRef As Long) As Long
Private Type UcsRgbQuad
R As Byte
G As Byte
B As Byte
A As Byte
End Type
Public Function RGBToHSB(ByVal clrValue As OLE_COLOR) As Variant
Const IDX_HUE As Long = 0
Const IDX_SAT As Long = 1
Const IDX_BRI As Long = 2
Dim nTemp As Double
Dim lMin As Long
Dim lMax As Long
Dim lDelta As Long
Dim rgbValue As UcsRgbQuad
Dim vRetVal As Variant
ReDim vRetVal(0 To 2) As Double
Call OleTranslateColor(clrValue, 0, VarPtr(rgbValue))
lMax = IIf(rgbValue.R > rgbValue.G, IIf(rgbValue.R > rgbValue.B, rgbValue.R, rgbValue.B), IIf(rgbValue.G > rgbValue.B, rgbValue.G, rgbValue.B))
lMin = IIf(rgbValue.R < rgbValue.G, IIf(rgbValue.R < rgbValue.B, rgbValue.R, rgbValue.B), IIf(rgbValue.G < rgbValue.B, rgbValue.G, rgbValue.B))
lDelta = lMax - lMin
vRetVal(IDX_BRI) = (lMax * 100) / 255
If lMax > 0 Then
vRetVal(IDX_SAT) = (lDelta / lMax) * 100
If lDelta > 0 Then
If lMax = rgbValue.R Then
nTemp = (CLng(rgbValue.G) - rgbValue.B) / lDelta
ElseIf lMax = rgbValue.G Then
nTemp = 2 + (CLng(rgbValue.B) - rgbValue.R) / lDelta
Else
nTemp = 4 + (CLng(rgbValue.R) - rgbValue.G) / lDelta
End If
vRetVal(IDX_HUE) = nTemp * 60
If vRetVal(IDX_HUE) < 0 Then
vRetVal(IDX_HUE) = vRetVal(IDX_HUE) + 360
End If
End If
End If
RGBToHSB = vRetVal
End Function
. . . and store the result as FP tripple.
cheers,
</wqW>
-
Feb 5th, 2025, 11:37 AM
#9
Re: RGB to HSB with *Byte* values??
 Originally Posted by wqweto
Note: They used 240 as upper bound in ColorRGBToHLS API which is beyond comprehension but probably has some reasoning behind this choice.
That's an excellent point. In some contexts, 240 is the upper bound (and multiple for 0 to 1 to integer) for "brightness" for HSB, and for "lightness" for HSL. In other contexts, when represented as an integer, it might be 0 to 100 (so 100 would be the multiple). So, you have to look at the specifications where HSB or HSL is needed to know for sure.
Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.
-
Feb 7th, 2025, 10:42 PM
#10
Re: RGB to HSB with *Byte* values??
 Originally Posted by wqweto
I'm personally using this
Code:
Private Declare Function OleTranslateColor Lib "oleaut32" (ByVal lOleColor As Long, ByVal lHPalette As Long, ByVal lColorRef As Long) As Long
Private Type UcsRgbQuad
R As Byte
G As Byte
B As Byte
A As Byte
End Type
Public Function RGBToHSB(ByVal clrValue As OLE_COLOR) As Variant
Const IDX_HUE As Long = 0
Const IDX_SAT As Long = 1
Const IDX_BRI As Long = 2
Dim nTemp As Double
Dim lMin As Long
Dim lMax As Long
Dim lDelta As Long
Dim rgbValue As UcsRgbQuad
Dim vRetVal As Variant
ReDim vRetVal(0 To 2) As Double
Call OleTranslateColor(clrValue, 0, VarPtr(rgbValue))
lMax = IIf(rgbValue.R > rgbValue.G, IIf(rgbValue.R > rgbValue.B, rgbValue.R, rgbValue.B), IIf(rgbValue.G > rgbValue.B, rgbValue.G, rgbValue.B))
lMin = IIf(rgbValue.R < rgbValue.G, IIf(rgbValue.R < rgbValue.B, rgbValue.R, rgbValue.B), IIf(rgbValue.G < rgbValue.B, rgbValue.G, rgbValue.B))
lDelta = lMax - lMin
vRetVal(IDX_BRI) = (lMax * 100) / 255
If lMax > 0 Then
vRetVal(IDX_SAT) = (lDelta / lMax) * 100
If lDelta > 0 Then
If lMax = rgbValue.R Then
nTemp = (CLng(rgbValue.G) - rgbValue.B) / lDelta
ElseIf lMax = rgbValue.G Then
nTemp = 2 + (CLng(rgbValue.B) - rgbValue.R) / lDelta
Else
nTemp = 4 + (CLng(rgbValue.R) - rgbValue.G) / lDelta
End If
vRetVal(IDX_HUE) = nTemp * 60
If vRetVal(IDX_HUE) < 0 Then
vRetVal(IDX_HUE) = vRetVal(IDX_HUE) + 360
End If
End If
End If
RGBToHSB = vRetVal
End Function
. . . and store the result as FP tripple.
cheers,
</wqW>
Yeah there's no correlation at all for most colors using this...
Code:
Dim hr As Long = SetRibbonColors(pFramework, pbClrTheme.BackColor, pbClrStd.BackColor, pbClrHighlight.BackColor)
Public Function SetRibbonColors(ByVal pFramework As IUIFramework, ByVal clrBackground As OLE_COLOR, ByVal clrText As OLE_COLOR, ByVal clrHighlight As OLE_COLOR) As Long
If pFramework IsNot Nothing Then
Dim pStore As IPropertyStore
Set pStore = pFramework
Dim v As Variant
Dim hsbBackground As Long
v = RGBToHSB(clrBackground)
hsbBackground = UI_HSB(v(0), v(1), v(2))
Dim hsbHighlight As Long
v = RGBToHSB(clrHighlight)
hsbHighlight = UI_HSB(v(0), v(1), v(2))
Dim hsbText As Long
v = RGBToHSB(clrText)
hsbText = UI_HSB(v(0), v(1), v(2))
Dim propvarBackground As Variant
InitPropVariantFromUInt32 hsbBackground, propvarBackground
Dim propvarHighlight As Variant
InitPropVariantFromUInt32 hsbHighlight, propvarHighlight
Dim propvarText As Variant
InitPropVariantFromUInt32 hsbText, propvarText
pStore.SetValue(UI_PKEY_GlobalBackgroundColor, propvarBackground)
pStore.SetValue(UI_PKEY_GlobalTextColor, propvarText)
pStore.SetValue(UI_PKEY_GlobalHighlightColor, propvarHighlight)
pStore.Commit()
Return Err.LastHresult
End If
End Function
Private Function RGBToHSB(ByVal clrValue As OLE_COLOR) As Variant
Const IDX_HUE As Long = 0
Const IDX_SAT As Long = 1
Const IDX_BRI As Long = 2
Dim nTemp As Double
Dim lMin As Long
Dim lMax As Long
Dim lDelta As Long
Dim rgbValue As RGBQUAD
Dim vRetVal As Variant
ReDim vRetVal(0 To 2) As Double
Call OleTranslateColor(clrValue, 0, ByVal VarPtr(rgbValue))
lMax = IIf(rgbValue.rgbRed > rgbValue.rgbGreen, IIf(rgbValue.rgbRed > rgbValue.rgbBlue, rgbValue.rgbRed, rgbValue.rgbBlue), IIf(rgbValue.rgbGreen > rgbValue.rgbBlue, rgbValue.rgbGreen, rgbValue.rgbBlue))
lMin = IIf(rgbValue.rgbRed < rgbValue.rgbGreen, IIf(rgbValue.rgbRed < rgbValue.rgbBlue, rgbValue.rgbRed, rgbValue.rgbBlue), IIf(rgbValue.rgbGreen < rgbValue.rgbBlue, rgbValue.rgbGreen, rgbValue.rgbBlue))
lDelta = lMax - lMin
vRetVal(IDX_BRI) = (lMax * 100) / 255
If lMax > 0 Then
vRetVal(IDX_SAT) = (lDelta / lMax) * 100
If lDelta > 0 Then
If lMax = rgbValue.rgbRed Then
nTemp = (CLng(rgbValue.rgbGreen) - rgbValue.rgbBlue) / lDelta
ElseIf lMax = rgbValue.rgbGreen Then
nTemp = 2 + (CLng(rgbValue.rgbBlue) - rgbValue.rgbRed) / lDelta
Else
nTemp = 4 + (CLng(rgbValue.rgbRed) - rgbValue.rgbGreen) / lDelta
End If
vRetVal(IDX_HUE) = nTemp * 60
If vRetVal(IDX_HUE) < 0 Then
vRetVal(IDX_HUE) = vRetVal(IDX_HUE) + 360
End If
End If
End If
RGBToHSB = vRetVal
End Function
Not sure how to check whether it's the ribbon or the values though.
-
Feb 8th, 2025, 05:17 AM
#11
Re: RGB to HSB with *Byte* values??
RGBToHSB returns B and S in 0..100.0 range and H in 0..360.0 range so you have to normalize in UI_HSB (or other) helper all three to 0..255 (esp. hue) to not produce psychedelic colors.
cheers,
</wqw>
-
Feb 14th, 2025, 03:25 AM
#12
Member
Re: RGB to HSB with *Byte* values??
Thanks for the code I have a module where I collect color conversion stuff, all I come across. However HSB is still missing. With your permission I hope this is OK for you, so I will integrate that too
MColor
-
Feb 17th, 2025, 12:42 PM
#13
Re: RGB to HSB with *Byte* values??
 Originally Posted by fafalone
The problem is every conversion method I can find is based on float (Single) between 0 and 1.0, while obviously a Byte is 0-255.
Yea, I encountered this when working on this program. I had to shed some naivete about how colours worked. By the end of that project I had learned that this 0-255 scheme I was comfortable with was actually quite clumsy. It turns out that it is far more useful to think of colours in terms of percentages. This is why you keep encountering the use of Singles in colour algorithms. HSB and HSL are percentage based colour schemes. For example a saturation value of 0.7 means the colour is 70% saturated. The same goes for brightness in HSB. Only hue isn't a percentage value, it's a point of a colour wheel. Even RGB can be interpreted as a percentage based colour scheme. A red value of 0.2 means 20% red.
My advice would be to go with the flow. Work with the singles and when it comes time to show something on the screen or any other situation where you require the tradition 0-255 scheme, you simple multiply your percentages by 255. Note though that this only works with RGB. HSL and HSB must stay as percentages as it doesn't make sense interpreting them any other way.
-
Feb 17th, 2025, 12:55 PM
#14
Re: RGB to HSB with *Byte* values??
 Originally Posted by Elroy
Also, I'm not sure I've ever seen either HSL or HSB represented as hex. With respect to colors, that seems to be almost exclusively an RGB thing.
Like I said above, it wouldn't make sense. HSL and HSB specifically tell you how much a colour is saturated or how bright it is based on percentages. Even RGB is percentage based. I think the only reason RGB uses the 0-255 range is because far easier to work with integers when it comes time to perform bitwise operations on images. Floating point numbers have a more complicated representation in memory than integers so it would complicate XOR or AND operations on images. Outside of bitwise operations, you will find it a lot more straightforward to use percentages to perform certain calculations on colours.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|