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
Dim hsv As New HSV
With hsv
.H = h
.S = s
.V = v
End With
Return hsv
End Function
' HSV色空間 - Wikipedia
''' <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