午後わてんのブログ

ベランダ菜園とWindows用アプリ作成(WPFとC#)

WPFとVB.NETでカラーピッカーその1

イメージ 10
指定した色を透明にするときに色を直接選びたい時があるけど
 

WPFにはカラーダイアログが無い

イメージ 1
参照を追加すればいつものWindowsForm用の↑が使えるみたいなんだけど
別のを作ってみたい!ってことで作り始めた
 
イメージ 2
今回のは最低限のもの
デザイン画面、XAML

f:id:gogowaten:20191025115849p:plain

 
VBコード
Class MainWindow
    Private Const MaxSV As Integer = 100 'SとVの最大値、100%表示なら100、詳細なら255指定

    Public Structure HSV
        Public H As Double
        Public S As Double
        Public V As Double
    End Structure
    Private Function RGBtoHSV(c As Color) As HSV
        Dim h, s, v As Double

        Dim r As Integer = c.R
        Dim g As Integer = c.G
        Dim b As Integer = c.B
        Dim min As Integer = Math.Min(b, Math.Min(r, g))
        Dim max As Integer = Math.Max(b, Math.Max(r, g))

        If max = min Then
            h = 0
        ElseIf max = r Then
            h = 60 * ((g - b) / (max - min))
        ElseIf max = g Then
            h = 60 * ((b - r) / (max - min)) + 120
        ElseIf max = b Then
            h = 60 * ((r - g) / (max - min)) + 240
        End If

        'hがマイナスなら360足す、RとBが同じ値だとマイナスになることがある
        If h < 0 Then h += 360

        ''100%表示の時のSV
        's = ((max - min) / max) * 100
        'v = (max / 255) * 100

        ''最大値が255表示の時のSV
        's = (max - min) / max * 255
        'v = max

        'Const設定のSV
        s = (max - min) / max * MaxSV
        v = (max / 255) * MaxSV

    If min = 0 And max = 0 Then s = 0

        Dim hsv As New HSV
        With hsv
            .H = h
            .S = s
            .V = v
        End With
        Return hsv
    End Function

    '    HSV色空間 - Wikipedia
    'https://ja.wikipedia.org/wiki/HSV%E8%89%B2%E7%A9%BA%E9%96%93
    ''' <summary>
    ''' HSVをRGB(Color)に変換する、RGBは小数点付きの0-255で返す
    ''' </summary>
    ''' <param name="hsv"></param>
    ''' <returns></returns>
    Private Function HSV2RGB(hsv As HSV) As Color
        Dim h As Double = hsv.H / 360
        Dim s As Double = hsv.S / MaxSV ' 255 ' 100
        Dim v As Double = hsv.V / MaxSV ' 255 ' 100
        Dim r As Double = v
        Dim g As Double = v
        Dim b As Double = v
        Dim neko As Double
        If s > 0 Then
            h *= 6
            Dim i As Integer = Math.Floor(h)
            Dim f As Double = h - i
            Select Case i
                Case 0
                    g *= 1 - s * (1 - f)
                    b *= 1 - s
                Case 1
                    r *= 1 - s * f
                    b *= 1 - s
                Case 2
                    r *= 1 - s
                    b *= 1 - s * (1 - f)
                Case 3
                    r *= 1 - s
                    g *= 1 - s * f
                Case 4
                    neko = r * (1 - s * (1 - f))
                    r *= 1 - s * (1 - f)
                    g *= 1 - s
                Case 5
                    g *= 1 - s
                    b *= 1 - s * f
            End Select

        End If

        r *= 255
        g *= 255
        b *= 255
        Dim col As Color = Color.FromRgb(r, g, b)
        Return col

    End Function
    Private Sub AddHueBar()
        '色相のバー作成
        Dim w As Integer = imgHue.Width
        Dim h As Integer = 360
        Dim wb As New WriteableBitmap(w, h, 96, 96, PixelFormats.Bgra32, Nothing)
        Dim stride As Integer = wb.BackBufferStride
        Dim pixels(h * stride * w - 1) As Byte
        Dim p As Integer
        wb.CopyPixels(pixels, stride, 0)

        Dim col As Color
        Dim hsv As New HSV
        With hsv
            .H = 0
            .S = MaxSV ' 255
            .V = MaxSV ' 255
        End With

        For y As Integer = 0 To h - 1
            hsv.H = y
            col = HSV2RGB(hsv)
            For x As Integer = 0 To w - 1
                p = y * stride + (x * 4)
                pixels(p + 0) = col.B
                pixels(p + 1) = col.G
                pixels(p + 2) = col.R
                pixels(p + 3) = 255
            Next
        Next

        Dim sourceRect As Int32Rect = New Int32Rect(0, 0, w, h)
        wb.WritePixels(sourceRect, pixels, stride, 0)
        imgHue.Source = wb
    End Sub
    'sv画像
    Private Sub ChangeImageSV(hue As Double)
        Dim w As Integer = MaxSV + 1 '100%表示なら0から100なので101ピクセル必要、255表示なら256ピクセル必要なので+1
        Dim h As Integer = MaxSV + 1 ' 255 'imgHue.Height
        Dim wb As New WriteableBitmap(w, h, 96, 96, PixelFormats.Bgra32, Nothing)
        Dim stride As Integer = wb.BackBufferStride
        Dim pixels(h * stride * w - 1) As Byte
        Dim p As Integer
        wb.CopyPixels(pixels, stride, 0)
        Dim hsv As New HSV
        With hsv
            .H = hue
            .S = MaxSV ' 255
            .V = MaxSV ' 255
        End With
        Dim col As Color
        For y As Integer = 0 To h - 1
            hsv.V = MaxSV - y ' 255 - y
            For x As Integer = 0 To w - 1
                hsv.S = x
                col = HSV2RGB(hsv)
                p = y * stride + (x * 4)
                pixels(p + 0) = col.B
                pixels(p + 1) = col.G
                pixels(p + 2) = col.R
                pixels(p + 3) = 255
            Next
        Next

        Dim sourceRect As Int32Rect = New Int32Rect(0, 0, w, h)
        wb.WritePixels(sourceRect, pixels, stride, 0)
        imgSV.Source = wb
    End Sub
    ''' <summary>
    ''' 画像(BitmapSource)の指定座標の色を取得
    ''' </summary>
    ''' <param name="p">座標</param>
    ''' <param name="bmp">画像</param>
    ''' <returns></returns>
    Private Function GetPixelColor(p As Point, bmp As BitmapSource) As Color
        Dim w As Integer = bmp.PixelWidth
        Dim h As Integer = bmp.PixelHeight
        Dim x As Integer = Math.Floor(p.X)
        Dim y As Integer = Math.Floor(p.Y)

        If x >= w Then x = w - 1
        If y >= h Then y = h - 1

        Dim cb As New CroppedBitmap(bmp, New Int32Rect(x, y, 1, 1))
        Dim fcb As New FormatConvertedBitmap(cb, PixelFormats.Bgra32, Nothing, 0)
        Dim pixels(3) As Byte 'コピー先の場所作成
        fcb.CopyPixels(pixels, 4, 0)
        Return Color.FromArgb(pixels(3), pixels(2), pixels(1), pixels(0))
    End Function



    Private Sub MainWindow_Initialized(sender As Object, e As EventArgs) Handles Me.Initialized
        '色相バー
        Call AddHueBar()

        '初期SV画像作成、色相は0(赤)で作成
        Call ChangeImageSV(0)
        imgSV.Width = MaxSV + 1 '100%表示なら0から100なので101ピクセル必要、255表示なら256ピクセル必要なので+1
        imgSV.Height = MaxSV + 1

    End Sub
    Private Sub MainWindow_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded
        AddHandler sldHue.ValueChanged, AddressOf sldHue_ValueChanged
    End Sub

    '色相スライダー変化でSV画像更新
    Private Sub sldHue_ValueChanged(sender As Object, e As RoutedPropertyChangedEventArgs(Of Double))
        Call ChangeImageSV(e.NewValue)
    End Sub
    'SV画像クリック
    Private Sub imgSV_MouseLeftButtonDown(sender As Object, e As MouseButtonEventArgs) Handles imgSV.MouseLeftButtonDown
        Dim clickPoint As Point = e.GetPosition(imgSV)
        Dim col As Color = GetPixelColor(clickPoint, imgSV.Source)
        rectMihon.Fill = New SolidColorBrush(col)
        tbkRGB.Text = $"ARGB = {col.ToString}"

        tbkRGB2.Text = $"ARGB = {col.A:000},{col.R:000},{col.G:000},{col.B:000}"
    End Sub

End Class
 
 
 

f:id:gogowaten:20191025115909p:plain

↑をどこで何をしているかを書き加えたのが↓

f:id:gogowaten:20191025115925p:plain

RGBとHSVの変換式は

ja.wikipedia.org

ここのコピペ
 
イメージ 6
3行目のMaxSVがSとVの最大値指定でここを100なら0%から100%表示
255にすると0から255で色を表現する
255にして起動すると↓
イメージ 7
クリックする画像も大きくなる256x256
100よりこっちのほうが詳細だけど必要はないのかな
右の色相スライダーを動かした時にこの画像を書き換えるから
大きな画像だと処理が大変ってのもある
 
ピクセルごとに色を指定して画像を作成するのは1ヶ月前の↓この記事とほぼ同じ

gogowaten.hatenablog.com

 
WPFVB.NETで画像の中の特定の色を透明にする ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログ
http://blogs.yahoo.co.jp/gogowaten/13957183.html
 
WriteableBitmap作成
CopyPixelsで色のByte配列を取得
Byte配列の中を書き換える(色の指定)
WritePixelsでByte配列を上書き
っていう流れ
これ書いてて思ったけどCopyPixelsを使ってByte配列を取得しなくても
直接Byte配列を作成してもできそうな気がする
 
 
画像をクリックした場所の色取得は1ヶ月前の

gogowaten.hatenablog.com

 
WPFVB.NETで表示した画像をクリックした場所の色を取得はややこしい ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログ
http://blogs.yahoo.co.jp/gogowaten/13952774.html
この記事の時とほとんど同じ
 
イメージ 9
クリックした座標取得は
クリックイベントでGetPositionで取得して
座標と画像を↓に渡す
イメージ 8
 
 
 
 
この記事の続き

gogowaten.hatenablog.com

 
WPFVB.NETでカラーピッカーその2、HSVとRGBで色指定 ( ガーデニング ) - 午後わてんのブログ - Yahoo!ブログ
http://blogs.yahoo.co.jp/gogowaten/14025927.html