Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Using the methods built into .NET's Color object is a non-starter because, as several of the answers point out, they don't support the reverse (converting an HSB color to RGB). Additionally, <code>Color.GetBrightness</code> actually returns <em>lightness</em>, rather than brightness/value. There is a lot of confusion over the differences between the HSB/HSV and HSL color spaces because of their similarities (<a href="http://en.wikipedia.org/wiki/HSL_and_HSV" rel="noreferrer">Wikipedia</a>). I see lots of color pickers that end up using the wrong algorithm and/or model.</p> <p>The original code looks to me like it misses a few possible scenarios when it calculates the value for hue, given an RGB color. It's a little difficult for me to follow the additions that you're contemplating to the code, but the first thing that jumps out at me (and that you don't appear to suggest correcting) is that when the saturation = 0, you set hue to -1. When you later multiply the hue by 60, you end up with -60, then you add that to 360 (<code>If h &lt; 0 Then h = h + 360</code>), producing a result of 300, which is not correct.</p> <p>I use the following code (in VB.NET) to convert between RGB and HSB (which I call HSV). The results have been tested very extensively, and the results are virtually identical to those given by Photoshop's color picker (aside from the compensation it does for color profiles). The major difference between the posted code and mine (aside from the important portion that calculates the hue) is that I prefer normalizing the RGB values to be between 0 and 1 to do the calculations, rather than working with the original values between 0 and 255. This eliminates some of the inefficiencies and multiple conversions in the original code that you posted, as well.</p> <pre><code>Public Function RGBtoHSV(ByVal R As Integer, ByVal G As Integer, ByVal B As Integer) As HSV ''# Normalize the RGB values by scaling them to be between 0 and 1 Dim red As Decimal = R / 255D Dim green As Decimal = G / 255D Dim blue As Decimal = B / 255D Dim minValue As Decimal = Math.Min(red, Math.Min(green, blue)) Dim maxValue As Decimal = Math.Max(red, Math.Max(green, blue)) Dim delta As Decimal = maxValue - minValue Dim h As Decimal Dim s As Decimal Dim v As Decimal = maxValue ''# Calculate the hue (in degrees of a circle, between 0 and 360) Select Case maxValue Case red If green &gt;= blue Then If delta = 0 Then h = 0 Else h = 60 * (green - blue) / delta End If ElseIf green &lt; blue Then h = 60 * (green - blue) / delta + 360 End If Case green h = 60 * (blue - red) / delta + 120 Case blue h = 60 * (red - green) / delta + 240 End Select ''# Calculate the saturation (between 0 and 1) If maxValue = 0 Then s = 0 Else s = 1D - (minValue / maxValue) End If ''# Scale the saturation and value to a percentage between 0 and 100 s *= 100 v *= 100 ''# Return a color in the new color space Return New HSV(CInt(Math.Round(h, MidpointRounding.AwayFromZero)), _ CInt(Math.Round(s, MidpointRounding.AwayFromZero)), _ CInt(Math.Round(v, MidpointRounding.AwayFromZero))) End Function </code></pre> <p>You didn't post the code you use to convert from an HSB (which I call HSV) color to RGB, but here's what I use, again working with interim values that are between 0 and 1:</p> <pre><code>Public Function HSVtoRGB(ByVal H As Integer, ByVal S As Integer, ByVal V As Integer) As RGB ''# Scale the Saturation and Value components to be between 0 and 1 Dim hue As Decimal = H Dim sat As Decimal = S / 100D Dim val As Decimal = V / 100D Dim r As Decimal Dim g As Decimal Dim b As Decimal If sat = 0 Then ''# If the saturation is 0, then all colors are the same. ''# (This is some flavor of gray.) r = val g = val b = val Else ''# Calculate the appropriate sector of a 6-part color wheel Dim sectorPos As Decimal = hue / 60D Dim sectorNumber As Integer = CInt(Math.Floor(sectorPos)) ''# Get the fractional part of the sector ''# (that is, how many degrees into the sector you are) Dim fractionalSector As Decimal = sectorPos - sectorNumber ''# Calculate values for the three axes of the color Dim p As Decimal = val * (1 - sat) Dim q As Decimal = val * (1 - (sat * fractionalSector)) Dim t As Decimal = val * (1 - (sat * (1 - fractionalSector))) ''# Assign the fractional colors to red, green, and blue ''# components based on the sector the angle is in Select Case sectorNumber Case 0, 6 r = val g = t b = p Case 1 r = q g = val b = p Case 2 r = p g = val b = t Case 3 r = p g = q b = val Case 4 r = t g = p b = val Case 5 r = val g = p b = q End Select End If ''# Scale the red, green, and blue values to be between 0 and 255 r *= 255 g *= 255 b *= 255 ''# Return a color in the new color space Return New RGB(CInt(Math.Round(r, MidpointRounding.AwayFromZero)), _ CInt(Math.Round(g, MidpointRounding.AwayFromZero)), _ CInt(Math.Round(b, MidpointRounding.AwayFromZero))) End Function </code></pre> <p><strong>EDIT:</strong> This code looks very similar to that provided in C by Richard J. Ross III. I hunted down as many different algorithms as I could find online, rewrote a lot of code borrowing the best from each of them, and did extensive testing to verify the accuracy of the results. I neglected to note who I borrowed code from, as this was just for a private library. Maybe the VB version will help someone who doesn't want to do a conversion from C. :-)</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload