Search code examples
c#winformsexceptioncolorsvision

C# ColorTranslator.FromHtml() throws Exception for "Grey" (is not a valid value for int32)


I am using the Microsoft Cognitive Services / Vision API in my application.

Vision API returns colours as string - either HEX (without the "#" prefix), or as a Name.

In order to convert this to a System.Drawing.Color that I can use as a panel background color, I am using the below code:

// Hex Color Format
Regex hex = new Regex("^#(?:[0-9a-fA-F]{3}){1,2}$");

// Colours
System.Drawing.Color accent = new System.Drawing.Color();
System.Drawing.Color fore = new System.Drawing.Color();
System.Drawing.Color back = new System.Drawing.Color();

try
{
  if (hex.IsMatch("#" + result.Color.AccentColor.ToString())) accent = ColorTranslator.FromHtml("#" + result.Color.AccentColor.ToString());
  else accent = ColorTranslator.FromHtml(result.Color.AccentColor.ToString());

  fore = ColorTranslator.FromHtml(result.Color.DominantColorForeground.ToString());
  back = ColorTranslator.FromHtml(result.Color.DominantColorBackground.ToString());

  displayData.Colors = new System.Drawing.Color[] { accent, fore, back };

}
catch (Exception e)
{
  throw new Exception(e.Message.ToString());
}

This has worked fine in 99% of cases, however, when one of the Colors returns from Micrsoft Vision API with "Grey", I get an Exception:

Grey is not a valid value for Int32

(This is the only color name I've encountered but I don't know if there would be others)

From my understanding, this would be because "Grey" is not a HTML Color Name, as it should be "Gray" ("Grey" being the CSS name) http://www.rapidtables.com/web/color/gray-color.htm

What would be the best way to handle this Exception? I was thinking creating a Dictionary of "bad" color names and manually assign those colors their true HTML Color Name (or a System.Drawing.Color directly), but this seems prone to human error and a constant game of update the Color.

Thoughts? Thanks.


Solution

  • I probably did this is in a convoluted manner, but I merged all of your responses into one and I think it was a neat solution:

    I create a new class called ColorFix, which checks for "bad" names in a Dictionary<string, string> (manually defined), then checks if it is a KnownName, before otherwise just returning a new blank Color object.

    Then, from the calling class, I created a Method ColorFromString which accepts the raw string color from the Microsoft API.

    This is the old code that tries to ColorTranslate.FromHtml -- and catches Exceptions -- except now Exceptions are processed through ColorFix.

    So round-about way of just parsing through a Dictionary and Checking if it's a KnownName.

    I'm relatively new to C#, so here is my code if this helps anyone:

    Controller.cs

            // Colours
            System.Drawing.Color accent = new System.Drawing.Color();
            System.Drawing.Color fore = new System.Drawing.Color();
            System.Drawing.Color back = new System.Drawing.Color();
    
            try
            {
                accent = ColorFromString(result.Color.AccentColor.ToString());
                fore = ColorFromString(result.Color.DominantColorForeground.ToString());
                back = ColorFromString(result.Color.DominantColorBackground.ToString());
    
                displayData.Colors = new System.Drawing.Color[] { accent, fore, back };
            }
            catch (Exception e)
            {
                throw new Exception(e.Message.ToString());
            }
    

    ...

        private System.Drawing.Color ColorFromString(string color)
        {
            System.Drawing.Color value = new System.Drawing.Color();
    
            // Hex Color Format
            Regex hex = new Regex("^#(?:[0-9a-fA-F]{3}){1,2}$");
    
            try
            {
                if (hex.IsMatch("#" + color)) value = ColorTranslator.FromHtml("#" + color);
                else value = ColorTranslator.FromHtml(color);
            }
            catch (Exception)
            {
                ColorFix colorFix = new ColorFix(color);
    
                value = colorFix.Fix();
            }
    
            return value;
        }
    

    ColorFix.cs

    using System;
    using System.Collections.Generic;
    using System.Drawing;
    
    namespace Project.Services
    {
        class ColorFix
        {
            private string color;
            public Dictionary<string, string> badColors = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase);
    
            //
            // Constructor, takes Color String
            //
            // @param string(color)
            // @return void
            //
            public ColorFix(string color)
            {
                this.color = color;
    
                badColors.Add("Grey", "Gray");
            }
    
            //
            // Fix the Color Exception
            //
            // @return Color
            //
            public Color Fix()
            {
                if (Bad() != null) return (Color)Bad();
                if (Known() != null) return (Color)Known();
    
                return new Color();
            }
    
            //
            // Check if Color is a system KnownColor
            //
            // @return Nullable<Color>
            //
            private Color? Known()
            {
                string colorLower = color.ToLower();
    
                Array colorValues = Enum.GetValues(typeof(KnownColor));
                string[] colorNames = Enum.GetNames(typeof(KnownColor));
    
                for (int c = 0; c < colorValues.Length; c++)
                {
                    if (colorNames.Equals(colorLower)) return Color.FromKnownColor((KnownColor)colorValues.GetValue(c));
                }
    
                return null;
            }
    
            //
            // Check if Color is within the Bad Colors Dictionary
            //
            // @return Nullable<Color>
            //
            private Color? Bad()
            {
                if (badColors.ContainsKey(color))
                {
                    try
                    {
                        return ColorTranslator.FromHtml(badColors[color]);
                    }
                    catch (Exception)
                    {
                        return null;
                    }
                }
    
                return null;
            }
        }
    }