Click here to Skip to main content
15,896,500 members
Articles / Multimedia / GDI+

ColorBlender - Dynamic Gradient Color Blend Creation Control (VB.NET)

Rate me:
Please Sign up or sign in to vote.
4.90/5 (29 votes)
1 Aug 2012CPOL6 min read 89.5K   4.4K   61  
How to create a ColorBlend and two color blending UserControls to make it easier.
'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

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
United States United States
I first got hooked on programing with the TI994A. After it finally lost all support I reluctantly moved to the Apple IIe. Thank You BeagleBros for getting me through. I wrote programs for my Scuba buisness during this time. Currently I am a Database manager and software developer. I started with VBA and VB6 and now having fun with VB.NET/WPF/C#...

Comments and Discussions