If you have a System.Drawing.Bitmap instance that contains a greyscale image, is there a built in way to "colourize" it with the influence of another colour?
For example, if you had a black and white (greyscale) picture of a coffee mug and you wanted to create separate images of red, green and purple versions programmatically.
I don't have a code example to give but here's a way to do this. Convert each pixel from RGB to HSV and change the Hue and Saturation component on each pixel. The Hue controls the Color. The Value should stay the same. The result will be a Bitmap with the same lightness and darkness but with a different color.
Edit: here's an example. Notice the Hue and Saturation update.
public static Color ColorFromAhsb(int a, float h, float s, float b)
{
if (0 > a || 255 < a)
{
throw new Exception("a");
}
if (0f > h || 360f < h)
{
throw new Exception("h");
}
if (0f > s || 1f < s)
{
throw new Exception("s");
}
if (0f > b || 1f < b)
{
throw new Exception("b");
}
if (0 == s)
{
return Color.FromArgb(a, Convert.ToInt32(b * 255),
Convert.ToInt32(b * 255), Convert.ToInt32(b * 255));
}
float fMax, fMid, fMin;
int iSextant, iMax, iMid, iMin;
if (0.5 < b)
{
fMax = b - (b * s) + s;
fMin = b + (b * s) - s;
}
else
{
fMax = b + (b * s);
fMin = b - (b * s);
}
iSextant = (int)Math.Floor(h / 60f);
if (300f <= h)
{
h -= 360f;
}
h /= 60f;
h -= 2f * (float)Math.Floor(((iSextant + 1f) % 6f) / 2f);
if (0 == iSextant % 2)
{
fMid = h * (fMax - fMin) + fMin;
}
else
{
fMid = fMin - h * (fMax - fMin);
}
iMax = Convert.ToInt32(fMax * 255);
iMid = Convert.ToInt32(fMid * 255);
iMin = Convert.ToInt32(fMin * 255);
switch (iSextant)
{
case 1:
return Color.FromArgb(a, iMid, iMax, iMin);
case 2:
return Color.FromArgb(a, iMin, iMax, iMid);
case 3:
return Color.FromArgb(a, iMin, iMid, iMax);
case 4:
return Color.FromArgb(a, iMid, iMin, iMax);
case 5:
return Color.FromArgb(a, iMax, iMin, iMid);
default:
return Color.FromArgb(a, iMax, iMid, iMin);
}
}
private void Form1_Load(object sender, EventArgs e)
{
var bmp = new Bitmap("c:\\bw.bmp");
foreach (int y in Enumerable.Range(0, bmp.Height))
{
foreach (int x in Enumerable.Range(0,bmp.Width))
{
var p = bmp.GetPixel(x, y);
var h = p.GetHue();
var c = ColorFromAhsb(p.A, p.GetHue() + 200, p.GetSaturation() + 0.5f, p.GetBrightness());
bmp.SetPixel(x, y, c);
}
}
pictureBox1.Image = bmp;
//bmp.Dispose();
}
If it's an 8 bit image, you can just use a different the palette (Image.Palette). That's essentially a lookup table that assigns a Color value to each possible pixel byte value. Much faster than changing all pixels in a loop.
See here
I have used this in the past. You are wanting to look specifically at ToSepia.
You may need to deconstruct this a bit but it has worked for me.
I'd create a copy of the original image and them put a separate semi transparent image of the desired color of the top.
Update: see example at http://www.codeproject.com/KB/cs/Merge_Images_in_C_.aspx
I am unsure of a built in way but, if you represent each colour as a float rather than a byte (255 becomes 1 - full intensity), multiplying the each channel with your desired colour should give the effect you are talking about.
(1,1,1) "white" * (1,0,0) "red" = (1,0,0) "red"
(0.5,0.5, 0.5) "grey" * (0,1,0) "green" = (0,0.5,0) "dark green"
You do need to apply this per pixel though.
Related
C# has a very convenient getHue method, but I can't find a setHue method. Is there one?
If not, I think the best way to define a color after changing the hue would be to convert the HSL value to RGB, and then set the RGB value. I know there are formulas on the internet for doing this, but how would I best go about performing this conversion from HSL to RGB using C#?
Thank You
To set the Hue you create a new Color, maybe from a given one by using GetHue and GetSaturation. See below for the getBrightness function!
I'm using this:
Color SetHue(Color oldColor)
{
var temp = new HSV();
temp.h = oldColor.GetHue();
temp.s = oldColor.GetSaturation();
temp.v = getBrightness(oldColor);
return ColorFromHSL(temp);
}
// A common triple float struct for both HSL & HSV
// Actually this should be immutable and have a nice constructor!!
public struct HSV { public float h; public float s; public float v;}
// the Color Converter
static public Color ColorFromHSL(HSV hsl)
{
if (hsl.s == 0)
{ int L = (int)hsl.v; return Color.FromArgb(255, L, L, L); }
double min, max, h;
h = hsl.h / 360d;
max = hsl.v < 0.5d ? hsl.v * (1 + hsl.s) : (hsl.v + hsl.s) - (hsl.v * hsl.s);
min = (hsl.v * 2d) - max;
Color c = Color.FromArgb(255, (int)(255 * RGBChannelFromHue(min, max,h + 1 / 3d)),
(int)(255 * RGBChannelFromHue(min, max,h)),
(int)(255 * RGBChannelFromHue(min, max,h - 1 / 3d)));
return c;
}
static double RGBChannelFromHue(double m1, double m2, double h)
{
h = (h + 1d) % 1d;
if (h < 0) h += 1;
if (h * 6 < 1) return m1 + (m2 - m1) * 6 * h;
else if (h * 2 < 1) return m2;
else if (h * 3 < 2) return m1 + (m2 - m1) * 6 * (2d / 3d - h);
else return m1;
}
Do not use the built-in GetBrightness method! It returns the same value (0.5f) for red, magenta, cyan, blue and yellow (!). This is better:
// color brightness as perceived:
float getBrightness(Color c)
{ return (c.R * 0.299f + c.G * 0.587f + c.B *0.114f) / 256f; }
System.Drawing.Color is a value type, which are almost always made immutable, especially in frameworks. That's why you can't setHue on it, you can only construct a new value type with fields you need.
So, if you have a function that will give you RGB values for your HSB values, you can do it like this
Color oldColor = ...;
int red, green, blue;
FromHSB(oldColor.GetHue(), oldColor.GetSaturation(), oldColor.GetBrightness(), out red, out green out blue);
Color newColor = Color.FromArgb(oldColor.A, red, green, blue);
where FromHSB looks like this
void FromHSB(float hue, float saturation, float brightness, out int red, out int green, out int blue)
{
// ...
}
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
Is there any way or workaround to combine/append two System.Drawing.Brush classes together?
e.g. Brush b1 = GetFromSomewhere();
Brush b2 = GetFromSomewhereElse();
(something like that...)
Brush b3 = b1 + b2;
Eventually my purpose is to do something like:
Graphics graphics = new Graphics;
graphics.FillRectangle(b3, rectangle);
Update:
I have a third party library (have no control over it) which gives me a predefined Brush instance (represents a fill pattern, e.g. ++++ or #####). I want to "overlay" that instance with my "own" brush pattern.
Update:
Since you have finally clarified what you want here is a solution to mix two TextureBrushes:
I assume you have the pattern for your TextureBrush in the Image img2. Use the simple method below to mix two images of the same size and create the new brush by using the combined patterns:
TextureBrush brush3 = new TextureBrush(
mixBitmaps( (Bitmap)(brush1.Image), (Bitmap) img2) );
Now you can paint or fill stuff with it..
Bitmap mixBitmaps(Bitmap bmp1, Bitmap bmp2)
{
using (Graphics G = Graphics.FromImage(bmp1) )
{
G.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceOver;
G.DrawImage(bmp2, Point.Empty);
}
return bmp1;
}
Here is an example:
I leave the old answer, since some folks were interested in it, too:
If you want to mix the Colors you can do it easily, maybe like this:
SolidBrush MixColor(SolidBrush b1, SolidBrush b2)
{
return new SolidBrush(Color.FromArgb(Math.Max(b1.Color.A, b2.Color.A),
(b1.Color.R + b2.Color.R) / 2, (b1.Color.G + b2.Color.G) / 2,
(b1.Color.B + b2.Color.B) / 2));
}
You may want to set the alpha channel to a fixed value of 255 instead.
However this is a simplistic average caculation, which will not work well if the colors are not close.
For a better mix you would mix the hues separatly from the saturation and the brightness values, that is you would have to convert to HSL or HSV, mix there and convert back to RGB..
Here is a version that should do just that:
SolidBrush MixBrushes(SolidBrush br1, SolidBrush br2)
{
return new SolidBrush ( MixColorHSV( br1.Color, br2.Color) );
}
Color MixColorHSV(Color c1 , Color c2 )
{
double h1 = c1.GetHue();
double h2 = c2.GetHue();
double d = (h2 - h1) / 2d;
double h = h1 + d;
if (d > 90) h -= 180; else if (d < -90) h += 180; // correction 1!
if (h < 0) h += 360; else if (h > 360) h -= 360; // correction 2!
int max1 = Math.Max(c1.R, Math.Max(c1.G, c1.B));
int min1 = Math.Min(c1.R, Math.Min(c1.G, c1.B));
double s1 = (max1 == 0) ? 0 : 1d - (1d * min1 / max1);
double v1 = max1 / 255d;
int max2 = Math.Max(c2.R, Math.Max(c2.G, c2.B));
int min2 = Math.Min(c2.R, Math.Min(c2.G, c2.B));
double s2 = (max2 == 0) ? 0 : 1d - (1d * min2 / max2);
double v2 = max2 / 255d;
double s = (s1 + s2) / 2d;
double v = (v1 + v2) / 2d;
return ColorFromHSV(h,s,v);
}
public static Color ColorFromHSV(double hue, double saturation, double value)
{
int hi = Convert.ToInt32(Math.Floor(hue / 60)) % 6;
double f = hue / 60 - Math.Floor(hue / 60);
value = value * 255;
int v = Convert.ToInt32(value);
int p = Convert.ToInt32(value * (1 - saturation));
int q = Convert.ToInt32(value * (1 - f * saturation));
int t = Convert.ToInt32(value * (1 - (1 - f) * saturation));
if (hi == 0) return Color.FromArgb(255, v, t, p);
else if (hi == 1) return Color.FromArgb(255, q, v, p);
else if (hi == 2) return Color.FromArgb(255, p, v, t);
else if (hi == 3) return Color.FromArgb(255, p, q, v);
else if (hi == 4) return Color.FromArgb(255, t, p, v);
else return Color.FromArgb(255, v, p, q);
}
See this post for parts of the conversion!
Here is a color chart that compares the two mixes adding Red with colors each 30° farther away. Note how many of the simple mixes are murkier with less saturation:
I have a color of class Microsoft.Xna.Framework.Color. How can I change its hue (or get a new color with slightly different hue). Should I convert it to System.Drawing.Color, then somehow change it and convert back? I can't find any useful information on this anywhere.
EDIT
Example:
I have red color R:255, G:0, B:0. Now I want to get slightly more orange color. Then if I get this color and transform it again I'll get even more orange color, then after some transformations I'll go to yellow, green etc. I don't know exact values of ARGB of each color and I don't need them. I just need to change hue of a color by some factor (for example 10 degrees).
You should use the A R G B properties and change the values to get different nyansers.
For example:
Color color = new Color(0,0,0);
//Then you can change the argb properties:
color.A = 10;
color.R = 15;
color.G = 9;
color.B = 25;
If I understand you need something like this:
public static class Utilities
{
public static void Increase(this Color color, int value)
{
if(color.R >= color.G && color.R >= color.B)
color.R += value;
else if(color.G >= color.R && color.G >= color.B)
color.G += value;
else
color.B += value;
}
public static void Decrease(this Color color, int value)
{
if(color.R <= color.G && color.R <= color.B)
color.R -= value;
else if(color.G <= color.R && color.G <= color.B)
color.G -= value;
else
color.B -= value;
}
}
Then:
Color myColor = new Color(10,0,0);
myColor.Increase(10);
//or
myColor.Decrease(10);
according to this documentation, you can pass whatever RGB(A) values you want into the XNA color class constructor. You can also use the R, B, and G properties to change them afterwards
example:
Color myColor = new Color(150, 100, 100);
myColor.R = 200
that example will change a red to a slightly deeper red.
An example of making a color go from Red to orange to yellow to green would be
Color myColor = new Color(255, 0, 0);
for(int i=0; i<255; i++)
{
myColor.R--;
myColor.G++
}
Red and Green make yellow, so higher numbers of red will make it redder, higher numbers of green will make it greener. same of both numbers make it redder.
You can change color incrementally in other ways too, so long as you know how the primary colors of light work.
You're never ever going to find a function called Color.MakeRedder() or Color.MakeGreener() It will always focus on some sort of mathmatical representation of the color, (RBG is most common but there are other representations)
If you want to convert Hue to RBG Here is a guide on how to do it
What would probably be easiest is to keep track of a System.Drawing.Color class as your base color class, and modify your XNA Color Class based on your System.Drawing.Color class accordingly.
If you want to get really adventurous, you can see if it is possible to make a class that extends(inherits from) Microsoft.Xna.Framework.Color, override the R, G, and B properties, so that they are based off of an underlying System.Drawing.Color object
I did some research and found this post which has C++ code:
http://www.cs.rit.edu/~ncs/color/t_convert.html
I've modified the code to be C#, to have an IncreaseHueBy method, and to fix a few bugs:
public static void IncreaseHueBy(ref Color color, float value, out float hue)
{
float h, s, v;
RgbToHsv(color.R, color.G, color.B, out h, out s, out v);
h += value;
float r, g, b;
HsvToRgb(h, s, v, out r, out g, out b);
color.R = (byte)(r);
color.G = (byte)(g);
color.B = (byte)(b);
hue = h;
}
static void RgbToHsv(float r, float g, float b, out float h, out float s, out float v)
{
float min, max, delta;
min = System.Math.Min(System.Math.Min(r, g), b);
max = System.Math.Max(System.Math.Max(r, g), b);
v = max; // v
delta = max - min;
if (max != 0)
{
s = delta / max; // s
if (r == max)
h = (g - b) / delta; // between yellow & magenta
else if (g == max)
h = 2 + (b - r) / delta; // between cyan & yellow
else
h = 4 + (r - g) / delta; // between magenta & cyan
h *= 60; // degrees
if (h < 0)
h += 360;
}
else
{
// r = g = b = 0 // s = 0, v is undefined
s = 0;
h = -1;
}
}
static void HsvToRgb(float h, float s, float v, out float r, out float g, out float b)
{
// Keeps h from going over 360
h = h - ((int)(h / 360) * 360);
int i;
float f, p, q, t;
if (s == 0)
{
// achromatic (grey)
r = g = b = v;
return;
}
h /= 60; // sector 0 to 5
i = (int)h;
f = h - i; // factorial part of h
p = v * (1 - s);
q = v * (1 - s * f);
t = v * (1 - s * (1 - f));
switch (i)
{
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;
default: // case 5:
r = v;
g = p;
b = q;
break;
}
}
I tested it by using a value of 1 to increase the hue by 1 every frame and it worked fairly well. Notice there may be some rounding errors.
I would like some advice on how to accomplish the following within C#. I would like to plot a "color", the exact color will be determined by a property value, for the sake of this example let's assume it's a percentage.
Ideally I'd like the user to specify five colors.
Negative MAX
Negative MIN
Even
Positive MIN
Positive MAX
The user is only specifying colors for each level, not the value which determines Min and Max.
Using this data, I would like to be able to calculate a color based on a percentage. i.e. 57% would result in a color hue in between Positive MIN and Positive MAX. Any help or advice for this is appreciated.
To interpolate between two colors you just interpolate each color channel
Color color1 = Color.Red;
Color color2 = Color.Green;
double fraction = 0.3;
Color color3 = Color.FromArgb(
(int)(color1.R * fraction + color2.R * (1 - fraction)),
(int)(color1.G * fraction + color2.G * (1 - fraction)),
(int)(color1.B * fraction + color2.B * (1 - fraction)));
To interpolate along your scale you need to decide what exact percentage values your "steps" have and project your target value that a fraction between two of those color steps.
Using the function copied from here, you can convert the hues back into RGB colors. This function assumes has all inputs and outputs in on a 0..1 scale, so you'll need to divide by color.GetHue() by 255. Below the function is some sample code using a set of percentages; implement DisplayColor in the UI of your choice to see the results.
public static void HSVToRGB(double H, double S, double V, out double R, out double G, out double B)
{
if (H == 1.0)
{
H = 0.0;
}
double step = 1.0/6.0;
double vh = H/step;
int i = (int) System.Math.Floor(vh);
double f = vh - i;
double p = V*(1.0 - S);
double q = V*(1.0 - (S*f));
double t = V*(1.0 - (S*(1.0 - f)));
switch (i)
{
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;
}
default:
{
// not possible - if we get here it is an internal error
throw new ArgumentException();
}
}
}
Color min = Color.Blue;
Color max = Color.Green;
float minHue = min.GetHue() / 255;
float maxHue = max.GetHue() / 255;
float scale = maxHue - minHue;
float[] percents = new float[] { .05F, .15F, .40F, .70F, .85F, .95F };
foreach (var pct in percents) {
float curHue = minHue + (scale * pct);
double r, g, b;
HSVToRGB(curHue, 1.0, 1.0, out r, out g, out b);
Color curColor = Color.FromArgb((int)(r * 255), (int)(g * 255), (int)(b * 255));
DisplayColor(curColor);
}
I am trying to convert a HSB Color to RGB. The way I am doing that is
System.Windows.Media.Color winColor = value;
System.Drawing.Color drawColor = System.Drawing.Color.FromArgb(winColor.R, winColor.G, winColor.B);
Hue = (byte)(drawColor.GetHue()*255);
Saturation = (byte)(drawColor.GetSaturation()*255);
Luminosity = (byte)(drawColor.GetBrightness()*255);
I find that when I have FF0000, it will be converted to H = 0, S = 255, L = 127 which converts to RGB FF0E0E. I think Luminosity should be 120? Or am I getting the whole HSB thing wrong? When I look at the color picker in Photoshop, Hue is 0-360 degrees, Saturation, Luminosity is 0-100%. I am having HSB values ranging from 0 - 255, am I doing it wrong?
Maybe you already look into this wikipedia article, but to make it clear.
There is a difference between HSL and HSB (aka HSV).
So you can't take the (B)rightness from the color class and use it like a (L)uminosity.
To get back from the Color class provided values GetHue(), GetSaturation() and GetBrightness() to a normal color you should give this extension method a chance.
/// <summary>
/// Creates a Color from alpha, hue, saturation and brightness.
/// </summary>
/// <param name="alpha">The alpha channel value.</param>
/// <param name="hue">The hue value.</param>
/// <param name="saturation">The saturation value.</param>
/// <param name="brightness">The brightness value.</param>
/// <returns>A Color with the given values.</returns>
public static Color FromAhsb(int alpha, float hue, float saturation, float brightness)
{
if (0 > alpha
|| 255 < alpha)
{
throw new ArgumentOutOfRangeException(
"alpha",
alpha,
"Value must be within a range of 0 - 255.");
}
if (0f > hue
|| 360f < hue)
{
throw new ArgumentOutOfRangeException(
"hue",
hue,
"Value must be within a range of 0 - 360.");
}
if (0f > saturation
|| 1f < saturation)
{
throw new ArgumentOutOfRangeException(
"saturation",
saturation,
"Value must be within a range of 0 - 1.");
}
if (0f > brightness
|| 1f < brightness)
{
throw new ArgumentOutOfRangeException(
"brightness",
brightness,
"Value must be within a range of 0 - 1.");
}
if (0 == saturation)
{
return Color.FromArgb(
alpha,
Convert.ToInt32(brightness * 255),
Convert.ToInt32(brightness * 255),
Convert.ToInt32(brightness * 255));
}
float fMax, fMid, fMin;
int iSextant, iMax, iMid, iMin;
if (0.5 < brightness)
{
fMax = brightness - (brightness * saturation) + saturation;
fMin = brightness + (brightness * saturation) - saturation;
}
else
{
fMax = brightness + (brightness * saturation);
fMin = brightness - (brightness * saturation);
}
iSextant = (int)Math.Floor(hue / 60f);
if (300f <= hue)
{
hue -= 360f;
}
hue /= 60f;
hue -= 2f * (float)Math.Floor(((iSextant + 1f) % 6f) / 2f);
if (0 == iSextant % 2)
{
fMid = (hue * (fMax - fMin)) + fMin;
}
else
{
fMid = fMin - (hue * (fMax - fMin));
}
iMax = Convert.ToInt32(fMax * 255);
iMid = Convert.ToInt32(fMid * 255);
iMin = Convert.ToInt32(fMin * 255);
switch (iSextant)
{
case 1:
return Color.FromArgb(alpha, iMid, iMax, iMin);
case 2:
return Color.FromArgb(alpha, iMin, iMax, iMid);
case 3:
return Color.FromArgb(alpha, iMin, iMid, iMax);
case 4:
return Color.FromArgb(alpha, iMid, iMin, iMax);
case 5:
return Color.FromArgb(alpha, iMax, iMin, iMid);
default:
return Color.FromArgb(alpha, iMax, iMid, iMin);
}
}
Update
So just to make things clear. My code above and the three methods within the Color class mentioned above are using the HSB (aka HSV) color model, but Photoshop uses the HSL color model.
In your comment you wrote that the parameters Hue = 0, Saturation = 1 and Brightness = 1 give you with the code above a red color and white in Photoshop. When you take a closer look at the differences of these modes this makes absolutely sense:
The HSL cylinder
(source: wikimedia.org)
In both models the hue acts as the same by using color Red as start and end point (zero and 360 degree).
By just looking at the hue you've got a red color.
The saturation defines how opaque the color is or how much the portion of a whitescale is.
So by setting it to one you say you want a full shiny red color.
The lighting now defines how much is the black and white part within your color. By setting it to zero you got black, one means white and 0.5 means perfect weighting.
So by setting it to one you say you want it as bright as possible which result in a white color.
The HSB cylinder
(source: wikimedia.org)
In both models the hue acts as the same by using color Red as start and end point (zero and 360 degree).
By just looking at the hue you've got a red color.
The saturation defines how opaque the color is or how much the portion of a whitescale is.
So by setting it to one you say you want a full shiny red color.
The brightness (or value) now defines how much is the black part within the color (not the white part).
So by setting it to one you say you want it full colored leading to a full shiny red color.
As you can see, Photoshop and the .Net framework (including my extension function) are using different coloring models. So you should check if you find somewhere an implementation of the other coloring model, a transformation or something else that gives you the results you need.
This works...modified from Java source code. The other answer is still HSL, This really is HSB to RGB (actually it's HSB/HSV to System.Windows.Media.Color as my return type)
public static Color HSBtoRGB(float hue, float saturation, float brightness)
{
int r = 0, g = 0, b = 0;
if (saturation == 0)
{
r = g = b = (int)(brightness * 255.0f + 0.5f);
}
else
{
float h = (hue - (float)Math.Floor(hue)) * 6.0f;
float f = h - (float)Math.Floor(h);
float p = brightness * (1.0f - saturation);
float q = brightness * (1.0f - saturation * f);
float t = brightness * (1.0f - (saturation * (1.0f - f)));
switch ((int)h)
{
case 0:
r = (int)(brightness * 255.0f + 0.5f);
g = (int)(t * 255.0f + 0.5f);
b = (int)(p * 255.0f + 0.5f);
break;
case 1:
r = (int)(q * 255.0f + 0.5f);
g = (int)(brightness * 255.0f + 0.5f);
b = (int)(p * 255.0f + 0.5f);
break;
case 2:
r = (int)(p * 255.0f + 0.5f);
g = (int)(brightness * 255.0f + 0.5f);
b = (int)(t * 255.0f + 0.5f);
break;
case 3:
r = (int)(p * 255.0f + 0.5f);
g = (int)(q * 255.0f + 0.5f);
b = (int)(brightness * 255.0f + 0.5f);
break;
case 4:
r = (int)(t * 255.0f + 0.5f);
g = (int)(p * 255.0f + 0.5f);
b = (int)(brightness * 255.0f + 0.5f);
break;
case 5:
r = (int)(brightness * 255.0f + 0.5f);
g = (int)(p * 255.0f + 0.5f);
b = (int)(q * 255.0f + 0.5f);
break;
}
}
return Color.FromArgb(Convert.ToByte(255), Convert.ToByte(r), Convert.ToByte(g), Convert.ToByte(b));
}
Since the other answers don't seem to work for me (and I didn't have the patience to see what's going on), I'm sharing my code for HSV->RGB conversion. It's based on the section "Alternate HSV conversion" on Wikipedia and is quite compact.
public static Color FromAhsv(byte alpha, float hue, float saturation, float value)
{
if (hue < 0f || hue > 360f)
throw new ArgumentOutOfRangeException(nameof(hue), hue, "Hue must be in the range [0,360]");
if (saturation < 0f || saturation > 1f)
throw new ArgumentOutOfRangeException(nameof(saturation), saturation, "Saturation must be in the range [0,1]");
if (value < 0f || value > 1f)
throw new ArgumentOutOfRangeException(nameof(value), value, "Value must be in the range [0,1]");
int Component(int n)
{
var k = (n + hue / 60f) % 6;
var c = value - value * saturation * Math.Max(Math.Min(Math.Min(k, 4 - k), 1), 0);
var b = (int)Math.Round(c * 255);
return b < 0 ? 0 : b > 255 ? 255 : b;
}
return Color.FromArgb(alpha, Component(5), Component(3), Component(1));
}
You can use ColorHelper library for this:
using ColorHelper;
RGB rgb = new RGB(20, 20, 20);
HSV hsv = ColorConverter.RgbToHsv(rgb);
Links:
Github
Nuget