65.9K
CodeProject 正在变化。 阅读更多。
Home

图像颜色选择器

starIconstarIconstarIconstarIconstarIcon

5.00/5 (2投票s)

2011年9月9日

CPOL

1分钟阅读

viewsIcon

31335

downloadIcon

924

将图像转换为颜色选择器。

引言

本文演示了如何将图像转换为一个简单的颜色选择器。

背景

实际上,互联网上、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 点传递给 MouseDownMouseMove 事件,并获取鼠标位置,然后将相同的点传递给一个私有方法,以获取该点的颜色。

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
© . All rights reserved.