指定した色を透明にするときに
色を直接選びたい時があるけど
WPFにはカラーダイアログが無い
参照を追加すればいつものWindowsForm用の↑が使えるみたいなんだけど
別のを作ってみたい!ってことで作り始めた
Class MainWindow
Private Const MaxSV As Integer = 100
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
If h < 0 Then h += 360
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
Private Function HSV2RGB(hsv As HSV) As Color
Dim h As Double = hsv.H / 360
Dim s As Double = hsv.S / MaxSV
Dim v As Double = hsv.V / MaxSV
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
.V = MaxSV
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
Private Sub ChangeImageSV(hue As Double)
Dim w As Integer = MaxSV + 1
Dim h As Integer = MaxSV + 1
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
.V = MaxSV
End With
Dim col As Color
For y As Integer = 0 To h - 1
hsv.V = MaxSV - 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 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()
Call ChangeImageSV(0)
imgSV.Width = MaxSV + 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
Private Sub sldHue_ValueChanged(sender As Object, e As RoutedPropertyChangedEventArgs(Of Double))
Call ChangeImageSV(e.NewValue)
End Sub
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
↑をどこで何をしているかを書き加えたのが↓
ここのコピペ
3行目のMaxSVがSとVの最大値指定でここを100なら0%から100%表示
255にすると0から255で色を表現する
255にして起動すると↓
100よりこっちのほうが詳細だけど必要はないのかな
右の色相スライダーを動かした時にこの画像を書き換えるから
大きな画像だと処理が大変ってのもある
WriteableBitmap作成
CopyPixelsで色のByte配列を取得
Byte配列の中を書き換える(色の指定)
WritePixelsでByte配列を上書き
っていう流れ
これ書いてて思ったけどCopyPixelsを使ってByte配列を取得しなくても
直接Byte配列を作成してもできそうな気がする
クリックイベントでGetPositionで取得して
座標と画像を↓に渡す