Drawing a Color Hue Wheel with C#
Thursday, December 1, 2011 at 1:10PM You’ve see the interface before. It’s a thick ring with a smooth rainbow of colors.
Here’s an an example from the MyPaint digital painting application.

And another one from Corel Painter 12

Notice how they differ in terms of where there colors are on the wheel and the direction of the colors.
Yesterday I was planning a few blog posts about RGB colors and realized I needed to create one of these. And rather than re-using one from an existing application, I thought I’d would be a good learning exercise to build my own. So, below is the one I created using a little program I wrote.

GET SOURCE CODE
- You can get a snapshot of the source code in the zip file here.
- Or you can download it from the viziblr codeplex project – look for a project called DemoDrawColorWheelBitmap in the Demos folder.
HOW IT WORKS
The code below is not efficient. It certainly is not optimized. And I admit there are better ways of doing it. I intended the code as an educational sample that illustrates basic concepts. Now that I think about it, this is a good coding question I should ask the next time I interview someone for a position at Microsoft.
It works like this: a bitmap is created to hold a circular of some width – defined by an inner radius and and outer radius. A loop goes through each coordinate in the bitmap; if the coordinate is within the ring then color is computed based on the coordinate and drawn. If the coordinate is outside the ring, a simple white pixel is drawn.
Computing the color from the coordinate requires first finding the angle produced between the center of the ring and the current coordinate. This angle can range from –pi to pi. The hue is computed from the angle by normalizing the angle to a range of 0.0 to 1.0.
Then the RGB value is constructed from a Hue, Saturation, and Value - where Saturation is 1.0 and Value is 1.0.
-----
string output_filename = "D:\\colorwheel.png";
int padding = 10;
int inner_radius = 200;
int outer_radius = inner_radius + 50;
int bmp_width = (2 * outer_radius) + (2 * padding);
int bmp_height = bmp_width;
var center = new System.Drawing.Point(bmp_width / 2, bmp_height / 2);
var c = System.Drawing.Color.Red;
using (var bmp = new System.Drawing.Bitmap(bmp_width, bmp_height))
{
using (var g = System.Drawing.Graphics.FromImage(bmp))
{
g.FillRectangle(System.Drawing.Brushes.White, 0, 0, bmp.Width, bmp.Height);
}
for (int y = 0; y < bmp_width; y++)
{
int dy = (center.Y - y);
for (int x = 0; x < bmp_width; x++)
{
int dx = (center.X - x);
double dist = System.Math.Sqrt(dx * dx + dy * dy);
if (dist >= inner_radius && dist <= outer_radius)
{
double theta = System.Math.Atan2(dy, dx);
// theta can go from -pi to pi
double hue = (theta + System.Math.PI) / (2 * System.Math.PI);
double dr, dg, db;
const double sat = 1.0;
const double val = 1.0;
HSVToRGB(hue, sat, val, out dr, out dg, out db);
c = System.Drawing.Color.FromArgb((int)(dr * 255), (int)(dg * 255), (int)(db * 255));
bmp.SetPixel(x, y, c);
}
}
}
bmp.Save(output_filename);
----
The code to convert HSV to RGB is below. Note that all the values for input and output should be in the range of 0 to 1.0.
-----
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();
}
}
}
----
saveenr |
4 Comments |
Reader Comments (4)
Hi Saveen
I went looking for the code that you pointed to but couldnt..could you post the full code here or see if it still is on the link?
Thanks
@Samarth
Here is a link to the zip file: https://skydrive.live.com/redir.aspx?cid=1ff099edb1c7ebfa&resid=1FF099EDB1C7EBFA!1559&parid=1FF099EDB1C7EBFA!1551
Thank you!
Thanks very much, this HSVToRGB function is exactly what I needed :)