Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.4k views
in Technique[技术] by (71.8m points)

c# - Color Table Algorithm

I've been searching for just over a week now on how to create something like this.

enter image description here

I have the code and for loops to create each Panel by X, and Y coords and everything. Each Panel is part of an array and starts at 0 at top left and ends at 90 at top right, but I don't care how its done as long as its done and its panels and works. The colors don't need to be the same but something similar so that I can have a fullscreen color picker. If someone knows some code to take one specific color and make it brighter ten times to set the panels backColor, using Color.FromARGB or just the Color class, to then please help me out. Thank you.

(This is a app I'm making for windows tablet and is touchscreen. The purpose of the app is to be fullscreen and not reviele that its a windows tablet, There for I have to make the color picker myself and cannot use the built in color dialog.)

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

For best control I suggest using a color calculation function.

enter image description here

There are many out there; here is one I use:

Color HsvToRgb(double h, double S, double V)
{
    /// Convert HSV to RGB
    /// h is from 0d - 360d
    /// s,v values are 0d - 1d
    /// r,g,b values are 0 - 255

    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);
}

Do note the input ranges!!

Now it is easy to setup a Color array at class level:

int width = 10;
int height = 9;
Color[,] colors;

And fill it:

void loadColors()
{
    colors = new Color[width, height];

    // load greys
    for (int i = 0; i < width; i++ ) colors[i, 0] = HsvToRgb(0f, 0f, 1f * i / width);
    // load bright stripe:
    for (int i = 0; i < width; i++) colors[i, 1] = HsvToRgb(i* 360f / width, 0.33f, 1f);
    // load matrix:
    for (int j = 2; j < height; j++)
        for (int i = 0; i < width; i++) 
             colors[i, j] = HsvToRgb(i * 360f / width, 1f, 1f * (height - j + 2) / height);
}

From this is is a snap to set the BackColors of your Panels.

Here is a Form.Paint function, I used to create the above screenshot:

private void Form1_Paint(object sender, PaintEventArgs e)
{
    int w = ClientSize.Width / width;
    int h = ClientSize.Height / height;

    for (int j = 0; j < height; j++) 
        for (int i = 0; i < width; i++)
        {
            using (SolidBrush brush = new SolidBrush(colors[i,j]))
            e.Graphics.FillRectangle(brush, i * w, j * h, w, h);
        }
}

Of course it is as simple as changing two numbers to make a finer grid, here 20x20:

enter image description here

Also note how the even spacing of hues doesn't really work well, as neither the human eye nor our common display systems are equally sensitive to changes in hues across the spectrum..

The eye is actually rather sensitive to greenish hues

the just-noticeable difference in wavelength varies from about 1 nm in the blue-green and yellow wavelengths, to 10 nm and more in the longer red and shorter blue wavelengths

but our monitors do a pretty bad job at creating different green hues..

Using an adapted list of perceptionally evenly spaced hues might help, depending on what you want..

enter image description here

Using this one-liner:

private void pictureBox1_MouseClick(object sender, MouseEventArgs e)
{
    int hue = (int) ((Bitmap)pictureBox1.Image).GetPixel(e.X, e.Y).GetHue();
}

on the image above gives us one such list of hues:

20 32 41 50 58 72 133 163 170 177 183 190 197 206 269 288 307 324 334 346 

I have modified it a little, maybe to make it work better with my monitor:

List<int> hues = new List<int> 
{ 20, 32, 41, 50, 58, 72, 133, 162,  180, 188, 195,  205, 215, 223, 246, 267, 288, 300, 320, 346 };

And changing the above code (keeping width = 20) to

HsvToRgb(hues[i],..

results in this:

enter image description here

Update: I have replaced the HsvToRgb function by a greatly simplified one.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...