Jamie Poole
Jamie Poole

Reputation: 516

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.

Upvotes: 2

Views: 2631

Answers (3)

Jamie Poole
Jamie Poole

Reputation: 516

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

Upvotes: 0

Parviz Bazgosha
Parviz Bazgosha

Reputation: 167

You can do like this :

string ColorValue="your Color String";
          Color col;
          try
          {
              col = ColorTranslator.FromHtml(ColorValue);


          }
          catch
          {
              ColorValue = ColorValue.ToLower();
              Array Colors=Enum.GetValues(typeof(KnownColor));
              string[] names=Enum.GetNames(typeof(KnownColor));
              for (int k = 0; k < Colors.Length; k++)
              {
                  if (names.Equals(ColorValue))
                  {

                      col = Color.FromKnownColor((KnownColor)Colors.GetValue(k));
                  }


              }
          }
        }

Upvotes: 3

sparrow
sparrow

Reputation: 980

Put a try/catch block around the code that's throwing the error and if the exception type matches whatever the exception type you are getting then handle it and adjust the color name instead of throwing the exception.

Upvotes: 1

Related Questions