Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Image Color Picker

0.00/5 (No votes)
9 Sep 2011 1  
Turn an image to a ColorPicker.

Introduction

This article demonstrates how to turn an image to a simple color picker.

Background

Actually, there is a lot of custom color pickers in the internet, in MSDN, and also here at The Code Project. You will find a lot of similar articles talking about custom color pickers but I never saw an article discuss how to turn an image/bitmap to a color picker, so I decided to give it a try, and here it is. I really hope it will be helpful for fellow CodeProject members.

How to Get Color from a Bitmap

To get a pixel color from an image/bitmap, simply use the Bitmap.GetPixel method which is a part of the Bitmap class, and to do that, you need to define an Image object, then pass the x and y coordinates of the pixel color to the GetPixel method, and you will get the color of the pixel. The code looks something like:

' Create a Bitmap object 
Dim bmp As New Bitmap("Grapes.jpg")

' Define the x-coordinate of the pixel to retrieve. 
Dim x As Integer = 20

' Define the x-coordinate of the pixel to retrieve. 
Dim y As Integer = 20

' Define the color and pass x, y coordinates to GetPixel Method
Dim pixelColor As Color = bmp.GetPixel(x, y)

Image Color Picker Control

The idea behind the image color picker is to pass a byRef point to the MouseDown and MouseMove events and get the mouse location, then pass the same point to a private method to get the color at that point.

ImageColorPicker Files

  • ImageColorPicker.vb: Extends the Windows.Forms.Control class.

Control Properties

  • Image: used to set the user picked image/bitmap.
  • Public Property Image As Bitmap
        Get
            Return Me.originalBitmap
        End Get
        Set(ByVal value As Bitmap)
            Me.originalBitmap = value
            Me.DrawImage()
            Me.Invalidate()
        End Set
    End Property
  • Color: gets the color selected.
  • Public Property Color As Color
        Get
            Return Me.selectedColor
        End Get
        Set(ByVal value As Color)
            Me.selectedColor = value
            Me.PixelColorToPoint()
            Me.DrawImage()
            MyBase.Invalidate()
        End Set
    End Property

Control Events

  • ColorChanged: occurs when the image pixel color changes, it also represents the control's DefaultEvent.
  • ''' <summary>
    ''' occurs when pixel color changed
    ''' </summary>
    ''' <remarks></remarks>
    Public Custom Event ColorChanged As EventHandler
        AddHandler(ByVal value As EventHandler)
            Me.Events.AddHandler("ColorChangedEvent", value)
        End AddHandler
    
        RemoveHandler(ByVal value As EventHandler)
            Me.Events.RemoveHandler("ColorChangedEvent", value)
        End RemoveHandler
    
        RaiseEvent(ByVal sender As Object, ByVal e As System.EventArgs)
            CType(Me.Events("ColorChangedEvent"), EventHandler).Invoke(sender, e)
        End RaiseEvent
    End Event

Control Methods

#Region " Methods"

Private Sub DrawImage()
    If MyBase.Width > 0 AndAlso Me.originalBitmap IsNot Nothing Then
        Me.pickerBitmap = New Bitmap(MyBase.ClientRectangle.Width - _
            (Me.controlBorder * 2), MyBase.ClientRectangle.Height - _
            (Me.controlBorder * 2))
        Dim g As Graphics = Graphics.FromImage(Me.pickerBitmap)
        Dim mode As SmoothingMode = g.SmoothingMode
        Dim rect As New Rectangle(0, 0, Me.pickerBitmap.Width, _
                    Me.pickerBitmap.Height)
        g.DrawImage(Me.originalBitmap, rect)
        g.SmoothingMode = mode
        g.Dispose()
    End If
End Sub

''' <summary>
''' Get pixel color point
''' </summary>
''' <param name="pt">pixel point</param>
''' <param name="pixelColor">pixel color</param>
''' <param name="w">width</param>
''' <param name="h">height</param>
''' <remarks></remarks>
Private Sub PixelColorToPoint(ByRef pt As Point, ByVal pixelColor _
            As Color, ByVal w As Integer, ByVal h As Integer)
    pt.X = ((255 - pixelColor.GetBrightness()) * w) / 255
    pt.Y = ((255 - pixelColor.GetSaturation()) * h) / 255
End Sub

Private Sub PixelColorToPoint()
    PixelColorToPoint(New Point(Me.selectedPoint.X, Me.selectedPoint.Y), _
      Me.selectedColor, MyBase.Width - (2 * Me.controlBorder), _
      MyBase.Height - (Me.controlBorder))
End Sub

''' <summary>
''' check if pixel color point is within the boundary
''' of specified width and height and if not reset its value
''' </summary>
''' <param name="pt">point</param>
''' <param name="w">width</param>
''' <param name="h">height</param>
''' <param name="border">control border</param>
''' <remarks></remarks>
Private Sub CheckPixelColorPoint(ByRef pt As Point, ByVal w As _
            Integer, ByVal h As Integer, ByVal border As Integer)
    If (pt.X - border) < 0 Then
        pt.X = border
    End If
    If pt.X > ((w - border) - 1) Then
        pt.X = (w - border) - 1
    End If

    If (pt.Y - border) < 0 Then
        pt.Y = border
    End If
    If pt.Y > ((h - border) - 1) Then
        pt.Y = (h - border) - 1
    End If
End Sub

''' <summary>
''' check if pixel color point is within the boundary
''' of the control width and height, if not reset its value
''' </summary>
''' <param name="pt"></param>
''' <remarks></remarks>
Private Sub CheckPixelColorPoint(ByRef pt As Point)
    Me.CheckPixelColorPoint(pt, MyBase.ClientRectangle.Width, _
            MyBase.ClientRectangle.Height, controlBorder)
End Sub

''' <summary>
''' 
''' </summary>
''' <param name="pt"></param>
''' <returns></returns>
''' <remarks></remarks>
Private Function HitTestPixelPoint(ByVal pt As Point) As Boolean
    Me.CheckPixelColorPoint(pt)
    If Me.originalBitmap IsNot Nothing Then
        If (((pt.X - Me.controlBorder) >= 0) AndAlso _
             ((pt.X - Me.controlBorder) < Me.pickerBitmap.Width)) _
               AndAlso (((pt.Y - Me.controlBorder) >= 0) _
               AndAlso ((pt.Y - Me.controlBorder) < Me.pickerBitmap.Height)) Then
            Dim pixelcolor As Color = _
                Me.pickerBitmap.GetPixel((pt.X - Me.controlBorder), _
                (pt.Y - Me.controlBorder))
            If pixelcolor.A > 0 Then
                Me.selectedColor = pixelcolor
                Me.selectedPoint.X = pt.X - Me.controlBorder
                Me.selectedPoint.Y = pt.Y - Me.controlBorder
                Return True
            End If
        End If
    End If
    Return False
End Function

Protected Sub OnColorChanged(ByVal e As EventArgs)
    Dim colorChangedHandler As EventHandler = _
         CType(Me.Events("ColorChangedEvent"), EventHandler)
    If (colorChangedHandler IsNot Nothing) Then
        colorChangedHandler.Invoke(Me, e)
    End If
End Sub

Protected Overrides Sub OnMouseDown(ByVal e As System.Windows.Forms.MouseEventArgs)
    MyBase.OnMouseDown(e)
    If Me.HitTestPixelPoint(e.Location) Then
        If Not Me.Focused Then
            MyBase.Focus()
        End If
        MyBase.Invalidate()
        Me.OnColorChanged(New EventArgs())
    End If
End Sub

Protected Overrides Sub OnMouseMove(ByVal e As System.Windows.Forms.MouseEventArgs)
    MyBase.OnMouseMove(e)
    If (e.Button = Windows.Forms.MouseButtons.Left) _
            AndAlso Me.HitTestPixelPoint(e.Location) Then
        MyBase.Invalidate()
        Me.OnColorChanged(New EventArgs())
    End If

End Sub

Protected Overrides Sub OnEnter(ByVal e As System.EventArgs)
    MyBase.OnEnter(e)
    MyBase.Invalidate()
End Sub

Protected Overrides Sub OnLeave(ByVal e As System.EventArgs)
    MyBase.OnLeave(e)
    MyBase.Invalidate()
End Sub

Protected Overrides Sub OnSizeChanged(ByVal e As System.EventArgs)
    Me.DrawImage()
    MyBase.OnSizeChanged(e)
End Sub

Protected Overrides Sub OnResize(ByVal e As System.EventArgs)
    Me.DrawImage()
    MyBase.OnResize(e)
End Sub

Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
    MyBase.OnPaint(e)

    Dim mode As SmoothingMode = e.Graphics.SmoothingMode
    e.Graphics.SmoothingMode = SmoothingMode.AntiAlias

    If Me.pickerBitmap IsNot Nothing Then
        Using lgb As New LinearGradientBrush(Me.ClientRectangle, _
                  Color.Black, Color.FromArgb(200, Color.Black), 90, True)
            e.Graphics.FillRectangle(lgb, Me.ClientRectangle)
        End Using
        e.Graphics.DrawImage(Me.pickerBitmap, Me.controlBorder, Me.controlBorder)
    End If

    If Not Me.DesignMode Then
        Dim r As New Rectangle((Me.controlBorder + Me.selectedPoint.X) - 5, _
             (Me.controlBorder + Me.selectedPoint.Y) - 5, 10, 10)
        Using sb As New SolidBrush(Me.selectedColor)
            e.Graphics.FillRectangle(sb, r)
            e.Graphics.DrawRectangle(Pens.White, r)
            r.Inflate(1, 1)
            e.Graphics.DrawRectangle(Pens.Black, r)
        End Using
    End If

End Sub

#End Region

Using the Control

Build the ImageColorPicker class, drag it to your form, then use it as follows:

Public Class Form1

    Private selectedColor As Color

    Private Sub ImagColorPicker1_ColorChanged(ByVal sender As System.Object, _
            ByVal e As System.EventArgs) Handles ImagColorPicker1.ColorChanged
        selectedColor = Me.ImagColorPicker1.Color
        Me.Invalidate()
    End Sub

    Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
        MyBase.OnPaint(e)

        e.Graphics.FillRectangle(New SolidBrush(Me.selectedColor), _
                   New Rectangle(0, 0, 30, 30))
    End Sub

End Class

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here