2

I'm making a system which includes picking a color using "colorDialog" and display it on a textbox. The problem is other colors display a Hex Value(like ffff8000). How can I change it into a readable texts?

I have this one solution:

private string changeColortoReadable(string changedColor){
     if(colorDialog.Color.Name == "ffff8000"){
         changedColor = "Orange";
     }
     return changedColor;
}

It's a little bit tiring and time consuming for me to put all the hex colors and convert it to a readable Colors.

halfer
  • 19,824
  • 17
  • 99
  • 186
Mark
  • 21
  • 5
  • Hello there! Welcome to stack overflow. Please spare some time to take [the tour](https://stackoverflow.com/tour) to figure out the kind of questions entertained in this community. To me, this question looks too broad to answer.. – Romeo Sierra Jul 09 '18 at 03:45
  • 1
    Hi, take a look at the Color.ToKnownColor method. Sounds like this is what you are looking for: https://msdn.microsoft.com/de-de/library/system.drawing.color.toknowncolor(v=vs.110).aspx – Sascha Jul 09 '18 at 03:51
  • The other comments and answer show what you might need to learn. And there are even more over the internet, like https://stackoverflow.com/questions/4556559/is-there-an-online-example-of-all-the-colours-in-system-drawing-color But not all colors (in HEX) can be named, so I don't think your question is valid. – Lex Li Jul 09 '18 at 04:20
  • The duplicate also shows a method to find "nearest match". ps please research before asking new questions. – Jeremy Thompson Jul 09 '18 at 04:59

3 Answers3

5

Get the name of the color only with a perfect match:

You can use the KnownColor enumeration to create the lookup you need. See below:

public static class HexColorTranslator
{
    private static Dictionary<string, string> _hex2Name;

    private static Dictionary<string, string> Hex2Name
    {
        get
        {
            if (_hex2Name == null)
            {
                _hex2Name = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
                foreach (KnownColor ce in typeof(KnownColor).GetEnumValues())
                {
                    var name = ce.ToString();
                    var color = Color.FromKnownColor(ce);
                    var hex = HexConverter(color);
                    _hex2Name[hex] = name;
                }
            }

            return _hex2Name;
        }
    }

    //https://stackoverflow.com/a/2395708/1155329
    private static String HexConverter(System.Drawing.Color c)
    {
        return c.R.ToString("X2") + c.G.ToString("X2") + c.B.ToString("X2");
    }

    public static string GetKnownColorFromHex(string hex)
    {
        hex = hex.TrimStart('#');
        if (Hex2Name.TryGetValue(hex, out string result)) return result;
        return "???";
    }
}

Get a color by calling the GetKnownColorFromHex function:

 Console.WriteLine(HexColorTranslator.GetKnownColorFromHex("#ff0000")); // Red

Note that unfortunately you cannot use ToKnownColor, unless the Color was created with a known Color. See:

var aquaKnown = Color.FromKnownColor(KnownColor.Aqua);
var aquaUnknown = Color.FromArgb(aquaKnown.A, aquaKnown.R, aquaKnown.G, aquaKnown.B);
Console.WriteLine(aquaKnown.ToKnownColor()); //Aqua
Console.WriteLine(aquaUnknown.ToKnownColor()); //0

Get the name of the nearest color, in RGB space:

If you want to get the closest color, you can try this:

 public static string GetNearestKnownColor(string hex)
 {
     var color = System.Drawing.ColorTranslator.FromHtml(hex);

     double bestSquared = double.MaxValue;
     KnownColor bestMatch = default(KnownColor);
     foreach (KnownColor ce in typeof(KnownColor).GetEnumValues())
     {
         Color tryColor = Color.FromKnownColor(ce);
         double deltaR = tryColor.R - color.R;
         double deltaG = tryColor.G - color.G;
         double deltaB = tryColor.B - color.B;
         double squared = deltaR * deltaR + deltaG * deltaG + deltaB * deltaB;
         if(squared == 0) return ce.ToString();
         if (squared < bestSquared)
         {
             bestMatch = ce;
             bestSquared = squared;
         }
     }

     return bestMatch.ToString();
 }

Note that this is not entirely accurate, as it's operating in RGB space, which may produce results different than a human might categorize colors.

MineR
  • 2,144
  • 12
  • 18
  • Or just `colorDialog.Color.ToKnownColor();` or directly `colorDialog.Color.Name;`? The problem is, if the color is not included in the `KnownColor` enumeration, what name would you give it, since it "looks like a tint of Orange". If it's included, it already has a name (since ColorDialog gives back a Color structure which contains the KnownColor readable Name). – Jimi Jul 09 '18 at 04:13
  • 1
    If you pick a Color from the `ColorDialog` which is in the `KnownColor` enumeration, it already has a Name (the KnownColor name); try with White and Black, for example. If it's not included, as in the OP example, you are not giving it a Name this way. – Jimi Jul 09 '18 at 04:24
  • It would be lovely to have the `NearestColorWithName` implemented. – PepitoSh Jul 09 '18 at 04:24
  • Yeah I realized what you were saying. – MineR Jul 09 '18 at 04:24
  • @PepitoSh Yeah OK fine. :) – MineR Jul 09 '18 at 04:35
  • Oh, I didn't mean that you should have done that. Just that it would be a fine piece of code. – PepitoSh Jul 09 '18 at 04:44
  • Well, it's already done :) I would change `if (hex.Length != 6)` because you are probably/possibly also receiving the Alpha byte (for a total max of 8 in string length). – Jimi Jul 09 '18 at 04:48
  • 1
    @Jimi yeah, let ColorTranslator.FromHTML deal with it. – MineR Jul 09 '18 at 04:50
  • @PepitoSh finding the nearest is here: https://stackoverflow.com/a/7792111/495455 – Jeremy Thompson Jul 09 '18 at 04:57
  • Last thing (to make you happy :). If you can combine +- the code you already have (with some tweaks and optimization) with what is suggested in @Todd answer, you'll have the best answer in SO in this matter. – Jimi Jul 09 '18 at 05:05
2

It would be easier to convert and work on an HSV (Hue, Saturation, Value) structure.

System.Drawing.Color color = System.Drawing.ColorTranslator.FromHtml("#FFCC66");
float hue = color.GetHue();
float saturation = color.GetSaturation();
float lightness = color.GetBrightness();

With those colour components, you could conceivably create a mapping between the Hue value and an English name of the colour (perhaps this component already exists). You would accomplish the mapping with a range of Hues mapping to a simple colour name. In addition, you would also be able to describe how saturated the colour is "Bold", "Faded", "Grey". And how bright it is with the Value/Brightness component.

You should be able to therefore achieve an output like: "Light Blue Grey" deterministically, instead of having to map all possible values to a name. You would also be able to control how specific you want to be about the hue name. Is it "Red" or is it "Maroon"?

It would also be possible to have some overlap in Hue mapping, to achieve hue descriptions like "Blue-Green", "Green-Blue", depending on which one is more dominant.

Sounds like it would be an interesting mini-project to build this.

Update:

    //Usage:
    //var result = ColourHexToEnglish("#ffff80");
    //result == "yellow"

    public static string ColourHexToEnglish(string Hex)
    {
        System.Drawing.Color color = System.Drawing.ColorTranslator.FromHtml(Hex);
        float hue = color.GetHue(); //0-360
        float saturation = color.GetSaturation();
        float lightness = color.GetBrightness();

        var hueNameComponent = HueName(hue);

        return hueNameComponent; //TODO: addition of more adjectives from saturation and lightness
    }

    public static string HueName(float hue)
    {
        if (hue >= 0 && hue < 30)
            return "red";
        else if (hue >= 30 && hue < 60)
            return "orange";
        else if (hue >= 60 && hue < 90)
            return "yellow";
        else if (hue >= 90 && hue < 180)
            return "green";
        else if (hue >= 180 && hue < 270)
            return "blue";
        else if (hue >= 270 && hue < 300)
            return "purple";
        else if (hue >= 300 && hue < 360)
            return "pink";
        else
            return "unknown";
    }
Kind Contributor
  • 17,547
  • 6
  • 53
  • 70
0

You could use an external database or service to do the colour naming for you.

Here's one: http://chir.ag/projects/name-that-color/#6195ED. They have a Javascript library you could use in your client-side code (I presume): http://chir.ag/projects/ntc/. You could also run that on the server-side using edge.js if the database is within the script, or translating it to C#; or accessing their webservice directly using C# Web Request.

Kind Contributor
  • 17,547
  • 6
  • 53
  • 70