# Hue math formula (it matches Microsoft's, but not others') what is it?

Go to solution Solved by Rick Brewster,

## Recommended Posts

Microsoft Window's has a ColorRGBToHLS function that matches Paint.net's Hue readout. This function is in the range 0-240 and doesn't do lossless conversion of the same color in and out (round trip).
Other sources give vastly different results for hue:
https://www.chilliant.com/rgb2hsv.html
https://en.wikipedia.org/wiki/Hue

I think it might be a sRGB/linear color space thing, but linearizing my inputs to these functions doesn't appreciably change the results. Paint.net's looks better, but I just started by using its data via its color picker, and now I don't have a color picker that matches these other functions. I may try GIMP later. I'd like to know what math/formula Paint.net is using please.

Thank you!

##### Share on other sites

This is the code for it. Hue is between 0-360, Saturation is 0-100, and Value is 0-100.

Paint.NET always uses sRGB, unless you are a plugin developer implementing a GpuEffect in which case the default is linear (converted from sRGB) (and you can specify you don't want linearization).

```public readonly Int32RgbColor ToRgb()
{
// Int32HsvColor contains values scaled as in the color wheel:

// Scale Hue to be between 0 and 360. Saturation
// and value scale to be between 0 and 1.
double h = (double)(this.Hue % 360);
double s = (double)this.Saturation / 100;
double v = (double)this.Value / 100;

double r;
double g;
double b;
if (s == 0)
{
// If s is 0, all colors are the same.
// This is some flavor of gray.
r = v;
g = v;
b = v;
}
else
{
// The color wheel consists of 6 sectors.
// Figure out which sector you're in.
double sectorPos = h / 60.0;
int sectorNumber = (int)(Math.Floor(sectorPos));

// get the fractional part of the sector.
// That is, how many degrees into the sector
// are you?
double fractionalSector = sectorPos - sectorNumber;

// Calculate values for the three axes
// of the color.
double p = v * (1 - s);
double q = v * (1 - (s * fractionalSector));
double t = v * (1 - (s * (1 - fractionalSector)));

// Assign the fractional colors to r, g, and b
// based on the sector the angle is in.
switch (sectorNumber)
{
default:
case 0:
r = v;
g = t;
b = p;
break;

case 1:
r = q;
g = v;
b = p;
break;

case 2:
r = p;
g = v;
b = t;
break;

case 3:
r = p;
g = q;
b = v;
break;

case 4:
r = t;
g = p;
b = v;
break;

case 5:
r = v;
g = p;
b = q;
break;
}
}

// return an RgbColor structure, with values scaled
// to be between 0 and 255.
return new Int32RgbColor(
DoubleUtil.ClampToByte(r * 255),
DoubleUtil.ClampToByte(g * 255),
DoubleUtil.ClampToByte(b * 255));
}```

• 1

The Paint.NET Blog: https://blog.getpaint.net/

Donations are always appreciated! https://www.getpaint.net/donate.html

##### Share on other sites

I'm sorry. Can you please share your corresponding RGB to HSV function? Your function here is smoother here than others. But I'm getting a green shift when using Microsoft's ColorRGBToHLS function combined with HSL->HSV to pump into your function. (The printout of its hue table looks promising. I can't figure out what I'm doing wrong, but so far only Microsoft's code is succeeding for me, and I'm a seasoned developer. I think if I have both of yours then I can see how it stands up. I still feel like I'm missing something though, since I can't seem to get approximate success with any of my own functions I've written.)

##### Share on other sites

• Solution
```public readonly Int32HsvColor ToHsv()
{
// In this function, R, G, and B values must be scaled
// to be between 0 and 1.
// Int32HsvColor.Hue will be a value between 0 and 360, and
// Int32HsvColor.Saturation and value are between 0 and 1.

double min;
double max;
double delta;

double r = (double)this.Red / 255;
double g = (double)this.Green / 255;
double b = (double)this.Blue / 255;

double h;
double s;
double v;

min = Math.Min(Math.Min(r, g), b);
max = Math.Max(Math.Max(r, g), b);
v = max;
delta = max - min;

if (max == 0 || delta == 0)
{
// R, G, and B must be 0, or all the same.
// In this case, S is 0, and H is undefined.
// Using H = 0 is as good as any...
s = 0;
h = 0;
}
else
{
s = delta / max;
if (r == max)
{
// Between Yellow and Magenta
h = (g - b) / delta;
}
else if (g == max)
{
// Between Cyan and Yellow
h = 2 + (b - r) / delta;
}
else
{
// Between Magenta and Cyan
h = 4 + (r - g) / delta;
}

}
// Scale h to be between 0 and 360.
// This may require adding 360, if the value
// is negative.
h *= 60;

if (h < 0)
{
h += 360;
}

return new Int32HsvColor((int)h, (int)(s * 100), (int)(v * 100));
}```

• 1

The Paint.NET Blog: https://blog.getpaint.net/

Donations are always appreciated! https://www.getpaint.net/donate.html

##### Share on other sites

I found my main problem finally, it was I'd swapped the G and B members in my makeshift float4 structure. But luckily it led me to find your group's source code that matches Microsoft's. Basically it seems to provide a higher quality mapping of values than most of the code floating around the net. I don't know if it's more color correct, but it works with Paint.net! Thank you • 1

## Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account. ×   Pasted as rich text.   Paste as plain text instead

Only 75 emoji are allowed.

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×