1. Implement a Spectrum
2. Picking a color by mouse click
In this post, We are going to make a 'Color Picker' with UserControl in WPF.
As you know, In Wpf, there is something very useful control that's LinearGradientBrush and it means that we just only to make a spectrum for picking color.
Let's move on next, to implement a spectrum in code.
<Grid x:Name="SpectrumGrid" Height="40" MouseMove="SpectrumGrid_MouseMove">
<Rectangle x:Name="SpectrumGridBar" Width="10" HorizontalAlignment="Left" Stroke="Black"></Rectangle>
</Grid>
Code above works like a spectrum slider. SpectrumGrid's background will be filled up by spectrum and SpectrumGridBar will follow our mouse move.
public ColorPicker()
{
InitializeComponent();
var g6 = HSV.GradientSpectrum();
LinearGradientBrush gradientBrush = new LinearGradientBrush();
gradientBrush.StartPoint = new Point(0, 0);
gradientBrush.EndPoint = new Point(1, 0);
for (int i = 0; i < g6.Length; i++) {
GradientStop stop = new GradientStop(g6[i].Color(), (i) * 0.16);
gradientBrush.GradientStops.Add(stop);
}
SpectrumGrid.Opacity = 1;
SpectrumGrid.Background = gradientBrush;
MiddleStop.Color = HSV.RGBFromHSV(0, 1f, 1f).Color();
}
This is contructor of UserControl. In this code, It initalize GradientBrush and set default GradientStop of color panel.
private void SpectrumGrid_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
{
if (e.LeftButton == System.Windows.Input.MouseButtonState.Pressed)
{
var x = e.GetPosition(SpectrumGrid).X;
pectrumGridBar.Margin = new Thickness(x, 0, 0, 0);
currH = 360 * (x / this.Width);
MiddleStop.Color = HSV.RGBFromHSV(currH, 1f, 1f).Color();
}
}
We will create HSV extension class later. but, We need to know about formula that converts HSV to RGB.
You can reference this post.
public class RGB
{
public byte R { get; set; }
public byte G { get; set; }
public byte B { get; set; }
public RGB()
{
R = 0xff;
G = 0xff;
B = 0xff;
}
public RGB(double r, double g, double b)
{
if (r > 255 || g > 255 || b > 255) throw new Exception("RGB must be under 255 (1byte)");
R = (byte)r;
G = (byte)g;
B = (byte)b;
}
public string Hex()
{
return BitConverter.ToString(new byte[] { R, G, B }).Replace("-", string.Empty);
}
public Color Color()
{
var color = new Color();
color.R = R;
color.G = G;
color.B = B;
color.A = 255;
return color;
}
}
It's class for simplifiy when using in HSV.
public static class HSV
{
public static RGB[] GetSpectrum()
{
RGB[] rgbs = new RGB[360];
for (int h = 0; h < 360; h++)
{
rgbs[h] = RGBFromHSV(h, 1f, 1f);
}
return rgbs;
}
public static RGB[] GradientSpectrum()
{
RGB[] rgbs = new RGB[7];
for (int h = 0; h < 7; h++)
{
rgbs[h] = RGBFromHSV(h*60, 1f, 1f);
}
return rgbs;
}
public static RGB RGBFromHSV(double h, double s, double v)
{
if (h > 360 || h < 0 || s > 1 || s < 0 || v > 1 || v < 0)
return null;
double c = v * s;
double x = c *(1 - Math.Abs((h / 60 % 2) - 1));
double m = v - c;
double r = 0, g = 0, b = 0;
if (h < 60)
{
r = c;
g = x;
}
else if(h < 120)
{
r = x;
g = c;
}
else if(h < 180)
{
g = c;
b = x;
}
else if(h < 240)
{
g = x;
b = c;
}
else if(h < 300)
{
r = x;
b = c;
}
else if(h <= 360)
{
r = c;
b = x;
}
return new RGB((r+m)*255, (g + m) * 255, (b + m) * 255);
}
}
HSV static class is the main of this post. It's simple that it just implement HSV to RGB.
Anyway we need 7 GradientStop colors and we can get RGB arrays per 60% of 360%.
Okay That's all. We just made a spectrum.
<Canvas HorizontalAlignment="Stretch" Height="210" MouseMove="RgbGradient_MouseMove">
<Canvas.Background>
<LinearGradientBrush EndPoint="0,0" StartPoint="1,0">
<GradientStop Color="Black" Offset="1"/>
<GradientStop Color="White"/>
<GradientStop x:Name="MiddleStop" Color="Red" Offset="0.5"/>
</LinearGradientBrush>
</Canvas.Background>
</Canvas>
We should one more xaml code. It is used for picking up and let's implement RgbGradient_MousMove.
private void RgbGradient_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
{
if(e.LeftButton == System.Windows.Input.MouseButtonState.Pressed)
{
var pos = e.GetPosition(sender as Canvas);
var x = pos.X;
var y = pos.Y;
RGB c;
if (x < Width / 2)
{
c = HSV.RGBFromHSV(currH, 1f, x / (Width / 2));
}
else
{
c = HSV.RGBFromHSV(currH, (Width / 2 - (x - Width / 2)) / Width, 1f);
}
//hexcode = c.Hex(); ....
}
}
That's all. As you can find, the gradient looks [black - spectrum selected - white], so the S of HSV must be 0 to 100%. It means range of S value is [spectrum color - white] and V is[black - spectrum color].
Finally we made it.
Thank you
ToList에 대한 오해 (0) | 2022.06.16 |
---|---|
C# SQLite 사용 - 테이블 생성 (0) | 2021.02.22 |
[WPF] Designer 뷰에서와, 디버깅에서의 Height, Width 차이 해결하기 (0) | 2020.11.22 |
[C#] 1. Visual Studio 2019 설치하고 Hello World 찍기 (0) | 2019.09.15 |