Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hashing strings to Color in C#

Tags:

I don't know if hashing is the right word for this, but I want to convert a string into a hex or argb color semi randomly.

I've used the string.GetHasCode function, but the results skew towards greenness:

string[] list = { "Test String", "something else", "Test Hooray" };

foreach (string k in list)
{
    string x = k.ToUpper().GetHashCode().ToString("X8");
    Console.WriteLine("#" + x.Substring(0,6));
}

I'd ideally like strings that begin with similar prefixes to have widely different colors. For example, "Test String" and "Test Hooray" should be completely different because they both begin with "Test."

I'm not really worried about an absolute solution, I just want something that is good enough. The list[] will at most have like 10 elements in it at a single time, and most of the time only 2, 3 or 4. This means that a color only has to be distinct from 2 or 3 other colors.

I'm basically generating a visual list, where the color references the name, but the name should ALWAYS map to the same color.

Edit: Sample Output:

#66BD44
#7EC83E
#95E4FE

Colors: http://www.colorcombos.com/combotester.html?color0=66BD44&color1=7EC83E&color2=95E4FE&color3=000316

like image 933
Shawn Avatar asked Oct 08 '10 01:10

Shawn


1 Answers

Create an MD5 hash of the string and take the first three bytes as the red, green and blue components respectively.

The following demo produces a reasonable distribution of colors.

var words = ("She sells sea shells on the sea shore but the sea " +
             "shells she sells are sea shells no more.").Split(' ');
var md5 = MD5.Create();
var box = new ListBox
    {
        Dock = DockStyle.Fill,
        DrawMode = DrawMode.OwnerDrawFixed
    };
box.Items.AddRange(words);
box.DrawItem += (sender, e) =>
    {
        var value = (string) box.Items[e.Index];
        var hash = md5.ComputeHash(Encoding.UTF8.GetBytes(value));
        var color = Color.FromArgb(hash[0], hash[1], hash[2]);
        using (var backBrush = new SolidBrush(color))
        using (var foreBrush = new SolidBrush(e.ForeColor))
        {
            e.Graphics.FillRectangle(backBrush, e.Bounds);
            e.Graphics.DrawString(value, e.Font, foreBrush, e.Bounds);
        }
        e.DrawFocusRectangle();
    };
new Form {Controls = {box}}.ShowDialog();

Screenshot

like image 98
Nathan Baulch Avatar answered Sep 24 '22 00:09

Nathan Baulch