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