图像颜色选择器
将图像转换为颜色选择器。
引言
本文演示了如何将图像转换为一个简单的颜色选择器。
背景
实际上,互联网上、MSDN 中以及 Code Project 上有很多自定义颜色选择器。你会找到很多类似的关于自定义颜色选择器的文章,但我从未见过一篇文章讨论如何将图像/位图转换为颜色选择器,所以我决定尝试一下,这就是它。我真的希望它对 CodeProject 的成员们有所帮助。
如何从位图中获取颜色
要从图像/位图中获取像素颜色,只需使用 Bitmap.GetPixel 方法,它是 Bitmap 类的一部分。为此,你需要定义一个 Image 对象,然后将像素颜色的 x 和 y 坐标传递给 GetPixel 方法,你将获得该像素的颜色。代码如下所示:
' 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)
图像颜色选择器控件
图像颜色选择器的想法是将一个 byRef 点传递给 MouseDown 和 MouseMove 事件,并获取鼠标位置,然后将相同的点传递给一个私有方法,以获取该点的颜色。
ImageColorPicker 文件
- ImageColorPicker.vb:扩展了 Windows.Forms.Control类。
控件属性
- Image:用于设置用户选择的图像/位图。
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:获取所选颜色。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
控制事件
- ColorChanged:当图像像素颜色更改时发生,它也代表控件的- 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
控制方法
#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
使用控件
构建 ImageColorPicker 类,将其拖到你的窗体上,然后像下面这样使用它
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



