'GetNearest... Modified from
' http://social.msdn.microsoft.com/Forums/en-US/vbgeneral/thread/b2d491ac-4031-46d6-bccb-8bf9a46c2289
' http://www.eggheadcafe.com/conversation.aspx?messageid=31472401&threadid=31472286
#Region "Imports"
Imports System.Reflection
Imports System.Runtime.CompilerServices
#End Region
'Color Extensions and Functions
Public Module ColorExtensions
#Region "GetColor..."
''' <summary>
''' Gets the <see cref="System.Drawing.Color.Name">System.Drawing.Color.Name</see> of the closest matching KnownColor Name.
''' </summary>
''' <example>
''' <code>
''' Private Sub Example()
''' Dim oColor As Color = Color.FromName(Color.FromArgb(255, 255, 255, 0).GetColorNearestName)
''' Debug.Assert(oColor.Name = "Yellow")
''' End Sub
''' </code>
''' </example>
<Extension()>
Public Function GetColorNearestName(ByVal unknownColor As Color, Optional ByVal SkipSystemColors As Boolean = True) As String
'short-circut
If unknownColor.IsNamedColor Then
Return unknownColor.Name
End If
Dim oBestMatch As sColor = GetColorNearestNameInternal(unknownColor, SkipSystemColors)
Return oBestMatch.Name
End Function
''' <summary>
''' Gets the <see cref="System.Drawing.KnownColor">System.Drawing.KnownColor</see> of the closest matching KnownColor.
''' </summary>
''' <example>
''' <code>
''' Private Sub Example()
''' Dim oColor As Color = Color.FromKnownColor(Color.FromArgb(255, 255, 255, 0).GetColorNearestKnown)
''' Debug.Assert(oColor.Name = "Yellow")
''' End Sub
''' </code>
''' </example>
<Extension()>
Public Function GetColorNearestKnown(ByVal unknownColor As Color, Optional ByVal SkipSystemColors As Boolean = True) As KnownColor
'short-circut
If unknownColor.IsKnownColor Then
Return unknownColor.ToKnownColor
End If
Dim oBestMatch As sColor = GetColorNearestKnownInternal(unknownColor, SkipSystemColors)
Return oBestMatch.Color.ToKnownColor
End Function
''' <summary>
''' Gets the <see cref="System.Drawing.Color.Name">System.Drawing.Color.Name</see> of the color and returns Named Color Name if RGB match is found.
''' </summary>
''' <example>
''' <code>
''' Private Sub Example()
''' Dim oColor As Color = Color.FromName(Color.FromArgb(255, 255, 255, 0).GetColorBestName)
''' Debug.Assert(oColor.Name = "Yellow")
''' End Sub
''' </code>
''' </example>
<Extension()>
Public Function GetColorBestName(ByVal unknownColor As Color, Optional ByVal withAlpha As Boolean = False, Optional ByVal SkipSystemColors As Boolean = True) As String
'short-circut
If unknownColor.R = 255 AndAlso unknownColor.G = 255 AndAlso unknownColor.B = 255 Then
If unknownColor.A = 0 Then
Return "Transparent"
Else
Return "White"
End If
ElseIf unknownColor.IsNamedColor Then
Return unknownColor.Name
End If
Dim CurrColor As Color = Color.FromArgb(unknownColor.R, unknownColor.G, unknownColor.B)
Dim CheckColor As KnownColor = CurrColor.GetColorNearestKnown(SkipSystemColors)
If Color.Equals(CurrColor.ToArgb, Color.FromKnownColor(CheckColor).ToArgb) Then
If Not withAlpha OrElse (withAlpha And unknownColor.A = 255) Then
Return Color.FromKnownColor(CheckColor).Name
Else
Return unknownColor.Name
End If
Else
If withAlpha Then
Return unknownColor.Name
Else
Return CurrColor.Name
End If
End If
End Function
''' <summary>
''' Gets the <see cref="System.Drawing.Color">System.Drawing.Color</see> and returns Named Color if RGB match is found.
''' </summary>
''' <example>
''' <code>
''' Private Sub Example()
''' Dim oColor As Color = Color.FromArgb(255, 255, 0).GetColorBest)
''' Debug.Assert(oColor.Name = "Yellow")
''' End Sub
''' </code>
''' </example>
<Extension()>
Public Function GetColorBest(ByVal unknownColor As Color, Optional ByVal withAlpha As Boolean = False, Optional ByVal SkipSystemColors As Boolean = True) As Color
'short-circut
If unknownColor.R = 255 AndAlso unknownColor.G = 255 AndAlso unknownColor.B = 255 Then
If unknownColor.A = 0 Then
Return Color.Transparent
Else
Return Color.White
End If
ElseIf unknownColor.IsNamedColor Then
Return unknownColor
End If
Dim CurrColor As Color = Color.FromArgb(unknownColor.R, unknownColor.G, unknownColor.B)
Dim CheckColor As KnownColor = CurrColor.GetColorNearestKnown(SkipSystemColors)
If Color.Equals(CurrColor.ToArgb, Color.FromKnownColor(CheckColor).ToArgb) Then
If Not withAlpha OrElse (withAlpha And unknownColor.A = 255) Then
Return Color.FromKnownColor(CheckColor)
Else
Return unknownColor
End If
Else
If withAlpha Then
Return unknownColor
Else
Return CurrColor
End If
End If
End Function
#Region "sColor"
Friend Structure sColor
Public Name As String
Public Color As Color
Public Distance As Double
''' <summary>
''' Returns RGB=(212,208,200)
''' </summary>
Public Function ToRGBString() As String
Return String.Format("RGB=({0},{1},{2})", Color.R, Color.G, Color.B)
End Function
End Structure
#End Region
#Region "Private methods"
Private Function GetColorNearestNameInternal(ByVal unknownColor As Color, Optional ByVal SkipSystemColors As Boolean = True) As sColor
Dim oBestMatch As sColor = Nothing
If unknownColor.R = 255 AndAlso unknownColor.G = 255 AndAlso unknownColor.B = 255 Then
If unknownColor.A = 0 Then
oBestMatch.Name = "Transparent"
oBestMatch.Distance = 0
oBestMatch.Color = Color.Transparent
Else
oBestMatch.Name = "White"
oBestMatch.Distance = 0
oBestMatch.Color = Color.White
End If
Else
Dim nClosestDistance As Double = Double.MaxValue
Dim oBindingFlags As BindingFlags = _
BindingFlags.DeclaredOnly Or _
BindingFlags.Public Or _
BindingFlags.Static
For Each oProperty As PropertyInfo In GetType(Color).GetProperties(oBindingFlags)
Dim oNamedColor As Color = DirectCast(oProperty.GetValue(Nothing, Nothing), Color)
If SkipSystemColors AndAlso oNamedColor.IsSystemColor Then Continue For
Dim nDistance As Double
nDistance = Math.Sqrt( _
(CInt(unknownColor.R) - oNamedColor.R) ^ 2 + _
(CInt(unknownColor.G) - oNamedColor.G) ^ 2 + _
(CInt(unknownColor.B) - oNamedColor.B) ^ 2)
nDistance = Math.Sqrt(nDistance / 3)
If nDistance < nClosestDistance Then
nClosestDistance = nDistance
oBestMatch.Name = oProperty.Name
oBestMatch.Distance = nDistance
oBestMatch.Color = oNamedColor
End If
Next
End If
Return oBestMatch
End Function
Private Function GetColorNearestKnownInternal(ByVal unknownColor As Color, Optional ByVal SkipSystemColors As Boolean = True) As sColor
Dim oBestMatch As sColor = Nothing
If unknownColor.R = 255 AndAlso unknownColor.G = 255 AndAlso unknownColor.B = 255 Then
If unknownColor.A = 0 Then
oBestMatch.Name = "Transparent"
oBestMatch.Distance = 0
oBestMatch.Color = Color.Transparent
Else
oBestMatch.Name = "White"
oBestMatch.Distance = 0
oBestMatch.Color = Color.White
End If
Else
Dim nClosestDistance As Double = Double.MaxValue
For Each sColorName As String In [Enum].GetNames(GetType(KnownColor))
Dim oNamedColor As Color = Color.FromName(sColorName)
If SkipSystemColors AndAlso oNamedColor.IsSystemColor Then Continue For
Dim nDistance As Double
nDistance = Math.Sqrt( _
(CInt(unknownColor.R) - oNamedColor.R) ^ 2 + _
(CInt(unknownColor.G) - oNamedColor.G) ^ 2 + _
(CInt(unknownColor.B) - oNamedColor.B) ^ 2)
nDistance = Math.Sqrt(nDistance / 3)
If nDistance < nClosestDistance Then
nClosestDistance = nDistance
oBestMatch.Name = oNamedColor.Name
oBestMatch.Distance = nDistance
oBestMatch.Color = oNamedColor
End If
Next
End If
Return oBestMatch
End Function
#End Region
#End Region
#Region "Sort List(of Color) by Color Shade"
''' <summary>
''' Sorts a List(of Color) by Color Shade
''' </summary>
''' <example>
''' <code>
''' With ColorBox
''' .Items.Clear()
''' Dim cList As New List(Of Color)
''' For Each s As String In [Enum].GetNames(GetType(KnownColor))
''' If Not Color.FromName(s).IsSystemColor Then
''' cList.Add(Color.FromName(s))
''' End If
''' Next
''' cList.Sort(AddressOf SortColors)
''' For Each c As Color In cList
''' .Items.Add(c.Name)
''' Next
''' End With
''' </code>
''' </example>
Friend Function SortColors(ByVal x As Color, ByVal y As Color) As Integer
'To use it first add all non-system colors to a List(Of Color),
'sort it by calling colors.Sort(AddressOf SortColors),
'then add all the list colors to the combo Items.
Dim huecompare As Integer = x.GetHue.CompareTo(y.GetHue)
Dim satcompare As Integer = x.GetSaturation.CompareTo(y.GetSaturation)
Dim brightcompare As Integer = x.GetBrightness.CompareTo(y.GetBrightness)
If huecompare <> 0 Then
Return huecompare
ElseIf satcompare <> 0 Then
Return satcompare
ElseIf brightcompare <> 0 Then
Return brightcompare
Else
Return 0
End If
End Function
#End Region
#Region "Dim or gray a Color"
''' <summary>
''' This function takes the given color and Lightens or Darkens it by the given value
''' </summary>
''' <param name="DimColor">Base Color object to be changed</param>
''' <param name="DimDegree">Positive value to darken and negative value to lighten DimColor</param>
<Extension()>
Public Function DimTheColor(ByVal DimColor As Color, ByVal DimDegree As Integer) As Color
If DimColor = Color.Transparent Or DimDegree = 0 Then Return DimColor
Dim ColorR As Integer = DimColor.R + DimDegree
Dim ColorG As Integer = DimColor.G + DimDegree
Dim ColorB As Integer = DimColor.B + DimDegree
If ColorR > 255 Then ColorR = 255
If ColorG > 255 Then ColorG = 255
If ColorB > 255 Then ColorB = 255
If ColorR < 0 Then ColorR = 0
If ColorG < 0 Then ColorG = 0
If ColorB < 0 Then ColorB = 0
Return Color.FromArgb(ColorR, ColorG, ColorB)
End Function
''' <summary>
''' This function takes the given color and returns its gray equivilant
''' </summary>
''' <param name="GrayColor">Color object to be grayed</param>
<Extension()>
Public Function GrayTheColor(ByVal GrayColor As Color) As Color
Dim gray As Integer = CInt(GrayColor.R * 0.3 + GrayColor.G * 0.59 + GrayColor.B * 0.11)
Return Color.FromArgb(GrayColor.A, gray, gray, gray)
End Function
#End Region
End Module