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:
Dim bmp As New Bitmap("Grapes.jpg")
Dim x As Integer = 20
Dim y As Integer = 20
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.
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
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
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
Private Sub CheckPixelColorPoint(ByRef pt As Point)
Me.CheckPixelColorPoint(pt, MyBase.ClientRectangle.Width, _
MyBase.ClientRectangle.Height, controlBorder)
End Sub
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