午後わてんのブログ

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

WPFとVB.NETでカラーピッカーその2、HSVとRGBで色指定のコード前半部分

このコードの記事は

gogowaten.hatenablog.com

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

gogowaten.hatenablog.com

 
WPFVB.NETでカラーピッカーその2、HSVとRGBで色指定のコード後半部分 ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログ
http://blogs.yahoo.co.jp/gogowaten/14025951.html
全体は
 
 
 
 
Imports System.Windows.Controls.Primitives

Class MainWindow
    Private Const MaxSV As Integer = 100 'SとVの最大値、100%表示なら100、詳細なら255指定
    Private IsDrag As Boolean 'マーカーを移動中フラグ
    Private IsChangeHSV As Boolean 'HSVのスライダーで値変更中フラグ
    Private IsChangeRGB As Boolean 'RGBのスライダーで値変更中フラグ

    Public Structure HSV
        Public H As Double
        Public S As Double
        Public V As Double
        Public Sub New(h As Double, s As Double, v As Double)
            Me.H = h
            Me.S = s
            Me.V = v
        End Sub
    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
            If max = 0 Then
                s = 0
                v = 0
                Return New HSV(0, 0, 0)
            End If
        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

        Dim hsv As New HSV(h, s, v)
        '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)に変換する、Hは0-360、SとVは0-100で受け取って、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 = 20 ' imgHue.Width
        Dim h As Integer = 360 ' 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 col As Color
        Dim hsv As New HSV(0, MaxSV, MaxSV)

        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

        '横の色相バーはこっちで270度回転させる
        Dim rotate As New RotateTransform(270)
        Dim rb As New TransformedBitmap(wb, rotate)
        imgHue.Source = rb

    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(hue, MaxSV, MaxSV)

        Dim col As Color
        For y As Integer = 0 To h - 1
            hsv.V = 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

    '市松模様作成
    Private Sub CreateTransparentImage()
        Dim grid As Integer = imgTransparent.Height / 10 '5 'マスの大きさ指定、なぜか4とかだと市松模様にならない
        Dim gray As Integer = 200 '灰色の指定
        Dim iro As Integer = 255 '白色の指定、255固定

        Dim w As Integer = imgTransparent.Width
        Dim h As Integer = imgTransparent.Height
        Dim wb As New WriteableBitmap(100, 100, 96, 96, PixelFormats.Bgra32, Nothing)
        Dim stride As Integer = wb.BackBufferStride
        Dim pixels(h * stride * w - 1) As Byte
        wb.CopyPixels(pixels, stride, 0)
        Dim p As Integer = 0

        For y As Integer = 0 To h - 1
            'マスの大きさによって色を変える、白と灰色
            If y Mod grid = 0 Then
                If iro = 255 Then
                    iro = gray
                Else
                    iro = 255
                End If
            End If
            'マスの大きさによって色を変える、白と灰色
            For x As Integer = 0 To w - 1
                If x Mod grid = 0 Then
                    If iro = 255 Then
                        iro = gray
                    Else
                        iro = 255
                    End If
                End If

                p = y * stride + (x * 4)

                pixels(p + 0) = iro
                pixels(p + 1) = iro
                pixels(p + 2) = iro
                pixels(p + 3) = 255

            Next

        Next

        Dim sourceRect As New Int32Rect(0, 0, w, h)
        wb.WritePixels(sourceRect, pixels, stride, 0)
        imgTransparent.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

    'Thumbの位置修正、中心になる座標を渡すとSetするべき座標を返す
    Private Function ConvertThumbPoint(p As Point) As Point
        Dim w As Integer = Math.Floor(thumb1.ActualWidth / 2)
        Dim h As Integer = Math.Floor(thumb1.ActualHeight / 2)
        Return New Point(p.X - w, p.Y - h)
    End Function


    'マーカーを移動して選択色表示
    Private Sub MoveThumb(p As Point)
        If IsDrag Then Return

        Dim t As Thumb = thumb1
        Dim np As Point = ConvertThumbPoint(p)
        Canvas.SetLeft(t, np.X)
        Canvas.SetTop(t, np.Y)

    End Sub

    Private Sub ChangeMihon(col As Color)
        '見本色の更新
        rectMihon.Fill = New SolidColorBrush(col)

        'textblockの更新
        tbkRGB.Text = $"ARGB = {col.ToString}"

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

    'HSVの変更のときRGBを更新
    Private Sub ValueChangedHSV()
        Dim col As Color = HSV2RGB(New HSV(sldHue.Value, sldS.Value, sldV.Value))
        'RGBの指定
        sldR.Value = col.R
        sldG.Value = col.G
        sldB.Value = col.B

        '見本色とTextblockの更新
        Dim argb As Color = Color.FromArgb(sldA.Value, col.R, col.G, col.B)
        Call ChangeMihon(argb)

    End Sub

    'RGBの変更の時HSVを更新
    Private Function ChangeHSV() As HSV
        Dim hsv = RGBtoHSV(Color.FromArgb(255, sldR.Value, sldG.Value, sldB.Value))
        'HSVの指定
        sldHue.Value = hsv.H
        sldS.Value = hsv.S
        sldV.Value = hsv.V
        Return hsv
    End Function