diff --git a/src/Spectre.Console/Color.cs b/src/Spectre.Console/Color.cs
index 38825a991..d3fc25396 100644
--- a/src/Spectre.Console/Color.cs
+++ b/src/Spectre.Console/Color.cs
@@ -213,6 +213,50 @@ public static Color FromInt32(int number)
return ColorTable.GetColor(number);
}
+ ///
+ /// Creates a color from a hexadecimal string representation.
+ ///
+ /// The hexadecimal string representation of the color.
+ /// The color created from the hexadecimal string.
+ public static Color FromHex(string hex)
+ {
+ if (hex is null)
+ {
+ throw new ArgumentNullException(nameof(hex));
+ }
+
+ if (hex.StartsWith("#"))
+ {
+ hex = hex.Substring(1);
+ }
+
+ var r = byte.Parse(hex.Substring(0, 2), NumberStyles.HexNumber);
+ var g = byte.Parse(hex.Substring(2, 2), NumberStyles.HexNumber);
+ var b = byte.Parse(hex.Substring(4, 2), NumberStyles.HexNumber);
+
+ return new Color(r, g, b);
+ }
+
+ ///
+ /// Tries to convert a hexadecimal color code to a object.
+ ///
+ /// The hexadecimal color code.
+ /// When this method returns, contains the equivalent of the hexadecimal color code, if the conversion succeeded, or if the conversion failed.
+ /// true if the conversion succeeded; otherwise, false.
+ public static bool TryFromHex(string hex, out Color color)
+ {
+ try
+ {
+ color = FromHex(hex);
+ return true;
+ }
+ catch
+ {
+ color = Color.Default;
+ return false;
+ }
+ }
+
///
/// Converts a to a .
///
diff --git a/test/Spectre.Console.Tests/Unit/ColorTests.cs b/test/Spectre.Console.Tests/Unit/ColorTests.cs
index 5c07195be..e2ea9dde1 100644
--- a/test/Spectre.Console.Tests/Unit/ColorTests.cs
+++ b/test/Spectre.Console.Tests/Unit/ColorTests.cs
@@ -1,9 +1,73 @@
+using System.Drawing;
+
namespace Spectre.Console.Tests.Unit;
public sealed class ColorTests
{
public sealed class TheEqualsMethod
{
+ [Theory]
+ [InlineData("800080")]
+ [InlineData("#800080")]
+ public void Should_Consider_Color_And_Color_From_Hex_Equal(string color)
+ {
+ // Given
+ var color1 = new Color(128, 0, 128);
+
+ // When
+ var color2 = Color.FromHex(color);
+
+ // Then
+ color2.ShouldBe(color1);
+ }
+
+ [Theory]
+ [InlineData("800080")]
+ [InlineData("#800080")]
+ public void Should_Consider_Color_And_Color_Try_From_Hex_Equal(string color)
+ {
+ // Given
+ var color1 = new Color(128, 0, 128);
+
+ // When
+ var result = Color.TryFromHex(color, out var color2);
+
+ // Then
+ result.ShouldBeTrue();
+ color2.ShouldBe(color1);
+ }
+
+ [Theory]
+ [InlineData(null)]
+ [InlineData("")]
+ [InlineData("#")]
+ [InlineData("#80")]
+ [InlineData("FOO")]
+ public void Should_Not_Parse_Non_Color_From_Hex(string noncolor)
+ {
+ // Given, When
+ var result = Record.Exception(() => Color.FromHex(noncolor));
+
+ // Then
+ result.ShouldBeAssignableTo();
+ }
+
+ [Theory]
+ [InlineData(null)]
+ [InlineData("")]
+ [InlineData("#")]
+ [InlineData("#80")]
+ [InlineData("FOO")]
+ public void Should_Not_Parse_Non_Color_Try_From_Hex(string noncolor)
+ {
+ // Given, When
+ var result = Color.TryFromHex(noncolor, out var color);
+
+ // Then
+ result.ShouldBeFalse();
+ color.ShouldBe(Color.Default);
+ }
+
[Fact]
public void Should_Consider_Color_And_Non_Color_Equal()
{