Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I generate a "random constant colour" for a given string?

Tags:

c#

wpf

how can I generate a "random constant colour" for a given string at runtime?

So a given string value will always have the same colour but different strings will have different colours.

Like how gmail assigns colours to the sender names.

Thanks

Responses to comments:

  1. Thinking to generate the colour from a hashcode.
  2. The colours won't be stored but generated from a hashcode.
like image 458
CodingHero Avatar asked Oct 07 '15 14:10

CodingHero


People also ask

How do you generate a random color in python?

Using random() function to generate random colors To begin, import the random function in Python to obtain a random color. The variable r stands for red, g stands for green, and b stands for blue. We already know that the RGB format contains an integer value ranging from 0 to 255.

How do I randomly change color in JavaScript?

In JavaScript, use the Math random() function to select colors randomly. We will use event listeners to change image color. The event listener is used to change random color for the background color of the given image.


2 Answers

I don't know any dedicated method for this, but here is a simple method generating Hexadecimal values with MD5 based on a given string:

using System.Security.Cryptography;
using System.Text;


static string GetColor(string raw)
{
    using (MD5 md5Hash = MD5.Create())
    {
        byte[] data = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(raw));
        return BitConverter.ToString(data).Replace("-", string.Empty).Substring(0, 6);
    }
}

Examples:

  1. [email protected]

    -> 23463B

  2. [email protected]

    -> 3C9015

  3. [email protected]

    -> 7CA5E8

Edit:

I didn't tested it enough, so you may want to tweak it a little bit to get more different and unique values.

Edit2:

If you want transparency, check out this question/answer. By setting the Substring to Substring(0,8) , you should return a string with the alpha channel.

like image 114
Alex H Avatar answered Oct 12 '22 23:10

Alex H


Similar to what the other answers are suggesting (hash the string in some form then use that hash to pick the color), but instead of using the hash to directly calculate the color use it as the index to an array of "Acceptable" colors.

class ColorPicker
{
    public ColorPicker(int colorCount)
    {
        //The ".Skip(2)" makes it skip pure white and pure black.
        // If you want those two, take out the +2 and the skip.
        _colors = ColorGenerator.Generate(colorCount + 2).Skip(2).ToArray();
    }
    private readonly Color[] _colors;

    public Color StringToColor(string message)
    {
        int someHash = CalculateHashOfStringSomehow(message);
        return _colors[someHash % _colors.Length];
    }

    private int CalculateHashOfStringSomehow(string message)
    {
        //TODO: I would not use "message.GetHashCode()" as you are not
        // guaranteed the same value between runs of the program.
        // Make up your own algorithom or use a existing one that has a fixed 
        // output for a given input, like MD5.
    }
}

This prevents issues like getting a white color when you plan on showing the text with a white background and other similar problems.

To populate your Color[] see this answer for the ColorGenerator class or just make your own pre-defined list of colors that look good on whatever background they will be used on.


Appendix:
In case the link goes down, here is a copy of the ColorGenerator class

public static class ColorGenerator
{

    // RYB color space
    private static class RYB
    {
        private static readonly double[] White = { 1, 1, 1 };
        private static readonly double[] Red = { 1, 0, 0 };
        private static readonly double[] Yellow = { 1, 1, 0 };
        private static readonly double[] Blue = { 0.163, 0.373, 0.6 };
        private static readonly double[] Violet = { 0.5, 0, 0.5 };
        private static readonly double[] Green = { 0, 0.66, 0.2 };
        private static readonly double[] Orange = { 1, 0.5, 0 };
        private static readonly double[] Black = { 0.2, 0.094, 0.0 };

        public static double[] ToRgb(double r, double y, double b)
        {
            var rgb = new double[3];
            for (int i = 0; i < 3; i++)
            {
                rgb[i] = White[i]  * (1.0 - r) * (1.0 - b) * (1.0 - y) +
                         Red[i]    * r         * (1.0 - b) * (1.0 - y) +
                         Blue[i]   * (1.0 - r) * b         * (1.0 - y) +
                         Violet[i] * r         * b         * (1.0 - y) +
                         Yellow[i] * (1.0 - r) * (1.0 - b) *        y +
                         Orange[i] * r         * (1.0 - b) *        y +
                         Green[i]  * (1.0 - r) * b         *        y +
                         Black[i]  * r         * b         *        y;
            }

            return rgb;
        }
    }

    private class Points : IEnumerable<double[]>
    {
        private readonly int pointsCount;
        private double[] picked;
        private int pickedCount;

        private readonly List<double[]> points = new List<double[]>();

        public Points(int count)
        {
            pointsCount = count;
        }

        private void Generate()
        {
            points.Clear();
            var numBase = (int)Math.Ceiling(Math.Pow(pointsCount, 1.0 / 3.0));
            var ceil = (int)Math.Pow(numBase, 3.0);
            for (int i = 0; i < ceil; i++)
            {
                points.Add(new[]
                {
                    Math.Floor(i/(double)(numBase*numBase))/ (numBase - 1.0),
                    Math.Floor((i/(double)numBase) % numBase)/ (numBase - 1.0),
                    Math.Floor((double)(i % numBase))/ (numBase - 1.0),
                });
            }
        }

        private double Distance(double[] p1)
        {
            double distance = 0;
            for (int i = 0; i < 3; i++)
            {
                distance += Math.Pow(p1[i] - picked[i], 2.0);
            }

            return distance;
        }

        private double[] Pick()
        {
            if (picked == null)
            {
                picked = points[0];
                points.RemoveAt(0);
                pickedCount = 1;
                return picked;
            }

            var d1 = Distance(points[0]);
            int i1 = 0, i2 = 0;
            foreach (var point in points)
            {
                var d2 = Distance(point);
                if (d1 < d2)
                {
                    i1 = i2;
                    d1 = d2;
                }

                i2 += 1;
            }

            var pick = points[i1];
            points.RemoveAt(i1);

            for (int i = 0; i < 3; i++)
            {
                picked[i] = (pickedCount * picked[i] + pick[i]) / (pickedCount + 1.0);
            }

            pickedCount += 1;
            return pick;
        }

        public IEnumerator<double[]> GetEnumerator()
        {
            Generate();
            for (int i = 0; i < pointsCount; i++)
            {
                yield return Pick();
            }
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    }

    public static IEnumerable<Color> Generate(int numOfColors)
    {
        var points = new Points(numOfColors);

        foreach (var point in points)
        {
            var rgb = RYB.ToRgb(point[0], point[1], point[2]);
            yield return Color.FromArgb(
                (int)Math.Floor(255 * rgb[0]),
                (int)Math.Floor(255 * rgb[1]),
                (int)Math.Floor(255 * rgb[2]));
        }
    }
}
like image 33
Scott Chamberlain Avatar answered Oct 12 '22 22:10

Scott Chamberlain