WPF 简单实现颜色选择器
- 框架使用
.NET4
; Visual Studio 2022
;
实现代码
1)新增 xaml
代码如下:
- 定义一个
WriteableBitmap
用于记录颜色缓冲值。 - 在
XAML
中定义Canvas
设置背景为一张图像。 - 在
Canvas
中添加Thumb
是一个可拖动的控件,用于实现交互中的拖动后获取颜色。
<Canvas x:Name="canvas" MouseLeftButtonDown="canvas_MouseLeftButtonDown"> <Canvas.Background> <ImageBrush ImageSource="{Binding Bitmap}" /> </Canvas.Background> <Thumb x:Name="thumb" Canvas.Left="0" Canvas.Top="0" Width="20" Height="20" Background="Transparent" BorderBrush="Black" BorderThickness="2" DragDelta="Thumb_DragDelta"> <Thumb.Template> <ControlTemplate TargetType="Thumb"> <Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="10" SnapsToDevicePixels="True" /> </ControlTemplate> </Thumb.Template> </Thumb> </Canvas>
2)新增 Loaded逻辑
处理代码如下:
- 首先嵌套循环,用于在图像的每个像素位置上进行操作色值。
height
和width
是图像的高度和宽度。- 在外层循环中,变量
y
从 0 开始递增,直到小于height
。 - 在内层循环中,变量
x
从 0 开始递增,直到小于width
。 - 在每个像素位置上,通过计算
normalizedX
和normalizedY
,将x
和y
的值归一化到 [0, 1] 范围内。 - 使用
HSVToRGB
函数将归一化后的normalizedX
、normalizedY
和 1(表示最大亮度)转换为 RGB 值,并将结果存储在r
、g
和b
变量中。 - 计算像素在图像数据缓冲区中的偏移量
pixelOffset
,其中stride
是每行像素占用的字节数。 - 使用
Marshal.WriteByte
方法将 RGB 值写入图像数据缓冲区中的相应位置,同时设置 Alpha 通道为 0xFF(完全不透明)。
IntPtr backBuffer = Bitmap.BackBuffer; int stride = Bitmap.BackBufferStride; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { byte r, g, b; double normalizedX = (double)x / (width - 1); double normalizedY = (double)y / (height - 1); HSVToRGB(normalizedX, normalizedY, 1, out r, out g, out b); int pixelOffset = y * stride + x * 4; Marshal.WriteByte(backBuffer, pixelOffset + 0, b); Marshal.WriteByte(backBuffer, pixelOffset + 1, g); Marshal.WriteByte(backBuffer, pixelOffset + 2, r); Marshal.WriteByte(backBuffer, pixelOffset + 3, 0xFF); } }
3)新增 HSVToRGB
方法代码如下:
- HSVToRGB 方法返回 r 、g、b
h
是色相值,取值范围为 [0, 1]。s
是饱和度值,取值范围为 [0, 1]。v
是亮度值,取值范围为 [0, 1]。r
、g
和b
是输出参数,用于存储转换后的 RGB 值。- 在函数内部,根据 HSV 转换公式进行计算。如果饱和度
s
为 0,则表示灰度色调,此时将 RGB 的三个分量都设置为亮度v
的值,并乘以 255 转换为字节表示。 - 如果饱和度
s
不为 0,则根据色相h
的值确定所处的色相区间,并根据公式计算出对应的 RGB 值。具体步骤如下: - 将色相
h
乘以 6,得到一个扩展的色相值hue
。 - 取
hue
的整数部分作为索引i
,表示所处的色相区间。 - 计算
hue
的小数部分f
。 - 根据公式计算出对应的 RGB 值,其中
p
是亮度v
与饱和度s
的乘积,q
是亮度v
与饱和度s
以及f
的乘积,t
是亮度v
与饱和度s
以及(1.0 - f)
的乘积。 - 根据索引
i
的值,将计算得到的 RGB 值赋给输出参数r
、g
和b
。
private static void HSVToRGB(double h, double s, double v, out byte r, out byte g, out byte b) { if (s == 0) { r = g = b = (byte)(v * 255); } else { double hue = h * 6.0; int i = (int)Math.Floor(hue); double f = hue - i; double p = v * (1.0 - s); double q = v * (1.0 - (s * f)); double t = v * (1.0 - (s * (1.0 - f))); switch (i) { case 0: r = (byte)(v * 255); g = (byte)(t * 255); b = (byte)(p * 255); break; case 1: r = (byte)(q * 255); g = (byte)(v * 255); b = (byte)(p * 255); break; case 2: r = (byte)(p * 255); g = (byte)(v * 255); b = (byte)(t * 255); break; case 3: r = (byte)(p * 255); g = (byte)(q * 255); b = (byte)(v * 255); break; case 4: r = (byte)(t * 255); g = (byte)(p * 255); b = (byte)(v * 255); break; default: r = (byte)(v * 255); g = (byte)(p * 255); b = (byte)(q * 255); break; } } }
4)新增 Thumb_DragDelta
代码如下:
- 在事件处理程序中,首先获取拖动的
Thumb
控件,并计算出新的左侧和顶部位置。通过Canvas.GetLeft(thumb)
和Canvas.GetTop(thumb)
方法获取当前Thumb
控件在Canvas
中的左侧和顶部位置,然后将其与拖动的变化量e.HorizontalChange
和e.VerticalChange
相加,得到新的位置。 - 计算
Canvas
的右侧和底部边界。通过canvas.ActualWidth - thumb.ActualWidth
和canvas.ActualHeight - thumb.ActualHeight
计算出Canvas
的右侧和底部边界位置。 - 对新的左侧和顶部位置进行边界检查。如果新的左侧位置小于 0,则将其设置为 0,以保证
Thumb
控件不会超出Canvas
的左侧边界。如果新的左侧位置大于Canvas
的右侧边界位置canvasRight
,则将其设置为canvasRight
,以确保Thumb
控件不会超出Canvas
的右侧边界。类似地,对新的顶部位置进行边界检查。 - 通过
Canvas.SetLeft(thumb, newLeft)
和Canvas.SetTop(thumb, newTop)
将Thumb
控件的位置更新为新的左侧和顶部位置。 - 调用
GetAreaColor()
方法来获取更新后的区域颜色。
private void Thumb_DragDelta(object sender, DragDeltaEventArgs e) { var thumb = (Thumb)sender; double newLeft = Canvas.GetLeft(thumb) + e.HorizontalChange; double newTop = Canvas.GetTop(thumb) + e.VerticalChange; double canvasRight = canvas.ActualWidth - thumb.ActualWidth; double canvasBottom = canvas.ActualHeight - thumb.ActualHeight; if (newLeft < 0) newLeft = 0; else if (newLeft > canvasRight) newLeft = canvasRight; if (newTop < 0) newTop = 0; else if (newTop > canvasBottom) newTop = canvasBottom; Canvas.SetLeft(thumb, newLeft); Canvas.SetTop(thumb, newTop); GetAreaColor(); }
5)新增 canvas_MouseLeftButtonDown
代码如下:
实现鼠标左键按下时,将 Thumb 控件移动到鼠标点击位置,并进行边界限制。同时,还获取了鼠标点击位置的颜色信息
private void canvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { var canvasPosition = e.GetPosition(canvas); double newLeft = canvasPosition.X - thumb.ActualWidth / 2; double newTop = canvasPosition.Y - thumb.ActualHeight / 2; double canvasRight = canvas.ActualWidth - thumb.ActualWidth; double canvasBottom = canvas.ActualHeight - thumb.ActualHeight; if (newLeft < 0) newLeft = 0; else if (newLeft > canvasRight) newLeft = canvasRight; if (newTop < 0) newTop = 0; else if (newTop > canvasBottom) newTop = canvasBottom; Canvas.SetLeft(thumb, newLeft); Canvas.SetTop(thumb, newTop); var thumbPosition = e.GetPosition(canvas); GetAreaColor(thumbPosition); }
6)新增 GetAreaColor
代码如下:
Thumb
控件的中心点坐标转换为相对于 Canvas
的坐标。
计算每行像素数据所占的字节数。
创建一个字节数组,用于存储位图的像素数据。
将位图的像素数据复制到字节数组中。
计算要访问的像素在字节数组中的索引位置。
Color.FromArgb
取其 Alpha
、红色、绿色和蓝色通道的值。在这段代码中,它被用于构造一个 Color
对象,表示位图中特定像素的颜色。
pixels[pixelIndex + 3]
表示字节数组中的第pixelIndex + 3
个元素,即 Alpha 通道的值。pixels[pixelIndex + 2]
表示字节数组中的第pixelIndex + 2
个元素,即红色通道的值。pixels[pixelIndex + 1]
表示字节数组中的第pixelIndex + 1
个元素,即绿色通道的值。pixels[pixelIndex]
表示字节数组中的第pixelIndex
个元素,即蓝色通道的值。
void GetAreaColor(Point? thumbPosition = null) { thumbPosition = thumbPosition == null ? thumbPosition = thumb.TranslatePoint(new Point(thumb.ActualWidth / 2, thumb.ActualHeight / 2), canvas) : thumbPosition; int xCoordinate = (int)thumbPosition?.X; int yCoordinate = (int)thumbPosition?.Y; if (xCoordinate >= 0 && xCoordinate < Bitmap.PixelWidth && yCoordinate >= 0 && yCoordinate < Bitmap.PixelHeight) { int stride = Bitmap.PixelWidth * (Bitmap.Format.BitsPerPixel / 8); byte[] pixels = new byte[Bitmap.PixelHeight * stride]; Bitmap.CopyPixels(new Int32Rect(0, 0, Bitmap.PixelWidth, Bitmap.PixelHeight), pixels, stride, 0); int pixelIndex = (yCoordinate * stride) + (xCoordinate * (Bitmap.Format.BitsPerPixel / 8)); Color color = Color.FromArgb(pixels[pixelIndex + 3], pixels[pixelIndex + 2], pixels[pixelIndex + 1], pixels[pixelIndex]); MyBtn.Background = new SolidColorBrush(color); } }
效果图
到此这篇关于基于WPF开发简单的颜色选择器的文章就介绍到这了,更多相关WPF颜色选择器内容请搜索本网站以前的文章或继续浏览下面的相关文章希望大家以后多多支持本网站!
您可能感兴趣的文章:
- C#及WPF获取本机所有字体和颜色的方法
- C# wpf简单颜色板的实现
- C#中WPF颜色对话框控件的实现
- 基于WPF实现用户头像选择器的示例代码