【WPF】自定义颜色拾取器

1.界面布局

cpp 复制代码
 <GroupBox
     Padding="0"
     BorderThickness="0.1"
     Foreground="White"
     Header="Color Pick">
     <DockPanel>
         <GroupBox
             Margin="5,0,5,2"
             BorderThickness="0.1"
             DockPanel.Dock="Right"
             Foreground="White"
             Header="Color">
             <WrapPanel
                 Width="200"
                 DockPanel.Dock="Right"
                 Orientation="Vertical">
                 <WrapPanel Margin="5,5,0,0">
                     <Label
                         VerticalContentAlignment="Center"
                         Content="R:"
                         Foreground="White" />
                     <Label
                         Name="Label_R"
                         Margin="5,0,0,0"
                         VerticalContentAlignment="Center"
                         Content="0"
                         Foreground="White" />
                 </WrapPanel>
                 <WrapPanel Margin="5,5,0,0">
                     <Label
                         VerticalContentAlignment="Center"
                         Content="G:"
                         Foreground="White" />
                     <Label
                         Name="Label_G"
                         Margin="5,0,0,0"
                         VerticalContentAlignment="Center"
                         Content="0"
                         Foreground="White" />
                 </WrapPanel>
                 <WrapPanel Margin="5,5,0,0">
                     <Label
                         VerticalContentAlignment="Center"
                         Content="B:"
                         Foreground="White" />
                     <Label
                         Name="Label_B"
                         Margin="5,0,0,0"
                         VerticalContentAlignment="Center"
                         Content="0"
                         Foreground="White" />
                 </WrapPanel>
                 <WrapPanel Background="Black">
                     <Image
                         x:Name="Image_Clolor"
                         Width="200"
                         Height="150"
                         Margin="0" />
                 </WrapPanel>
             </WrapPanel>
         </GroupBox>
         <GroupBox
             Name="WrapPanel_Image"
             Padding="0,0,0,0"
             HorizontalContentAlignment="Stretch"
             VerticalContentAlignment="Stretch"
             Background="Black"
             BorderThickness="0"
             ClipToBounds="True"
             Cursor="Cross"
             DockPanel.Dock="Left">
             <Image
                 x:Name="Image_Img"
                 Width="{Binding ElementName=WrapPanel_Image, Path=ActualWidth}"
                 Height="{Binding ElementName=WrapPanel_Image, Path=ActualHeight}"
                 Margin="-5,0,0,0"
                 HorizontalAlignment="Left"
                 VerticalAlignment="Top"
                 ClipToBounds="True"
                 MouseWheel="Image_Img_MouseWheel"
                 PreviewMouseLeftButtonDown="Image_Img_PreviewMouseLeftButtonDown"
                 PreviewMouseLeftButtonUp="Image_Img_PreviewMouseLeftButtonUp"
                 PreviewMouseMove="Image_Img_PreviewMouseMove"
                 PreviewMouseRightButtonDown="Image_Img_PreviewMouseRightButtonDown"
                 RenderOptions.BitmapScalingMode="Fant"
                 Stretch="Uniform">
                 <Image.RenderTransform>
                     <TransformGroup>
                         <ScaleTransform x:Name="Image_Img_ScaleTransform" CenterX="0" CenterY="0" ScaleX="1" ScaleY="1" />
                         <TranslateTransform x:Name="Image_Img_TranslateTransform" X="0" Y="0" />
                     </TransformGroup>
                 </Image.RenderTransform>
             </Image>
         </GroupBox>
     </DockPanel>
 </GroupBox>

2.后台实现

csharp 复制代码
 /// <summary>
 /// ColorPickerUserControl.xaml 的交互逻辑
 /// </summary>
 public partial class ColorPickerUserControl : UserControl
 {
     //图像原图
     private Bitmap originalBitmap;
     //缩放比率
     private double ScaleRatio = 0.2;
     //鼠标按下坐标
     private System.Windows.Point currentClickPoint = new System.Windows.Point(0, 0);
     //鼠标按下标识
     bool isImageLeftButtonDown = false;
     /// <summary>
     /// 当前选中颜色
     /// </summary>
     public System.Drawing.Color CurrentColor;

     public ColorPickerUserControl()
     {
         InitializeComponent();
     }
     /// <summary>
     /// 资源释放
     /// </summary>
     public void Dispose()
     {
         try
         {
             Image_Img.Source?.Freeze();
             Image_Img.Source = null;
             originalBitmap?.Dispose();
             originalBitmap = null;
             Image_Clolor.Source?.Freeze();
             Image_Clolor.Source = null;
         }
         catch (Exception ex)
         {
             throw new Exception(ex.Message);
         }
     }
     /// <summary>
     /// 加载图像
     /// </summary>
     /// <param name="fileName">图像文件路径</param>
     public void InitImage(string fileName)
     {
         try
         {
             Image_Img.Stretch = Stretch.Uniform;
             if (File.Exists(fileName))
             {
                 Task<BitmapImage> task = Task.Run(() =>
                 {
                     //后台读取图像,防止图像太大卡住主线程
                     using (var stream = File.OpenRead(fileName))
                     {
                         var bmp = new BitmapImage();
                         bmp.BeginInit();
                         bmp.StreamSource = stream;
                         bmp.CacheOption = BitmapCacheOption.OnLoad;
                         bmp.EndInit();
                         bmp.Freeze(); // 冻结对象以便跨线程访问
                         originalBitmap = new Bitmap(stream);
                         return bmp;
                     }
                 });
                 task.Wait();
                 Image_Img.Source = task.Result;
             }
         }
         catch (Exception ex)
         {
             throw new Exception(ex.Message);
         }
     }
     /// <summary>
     /// 加载图像
     /// </summary>
     /// <param name="bitmap">图像</param>
     public void InitImage(Bitmap bitmap)
     {
         try
         {
             originalBitmap?.Dispose();
             originalBitmap = null;
             originalBitmap = new Bitmap(bitmap);
             // 将Bitmap转换为WPF的BitmapImage
             BitmapImage bitmapImage;
             using (MemoryStream memory = new MemoryStream())
             {
                 bitmap.Save(memory, System.Drawing.Imaging.ImageFormat.Png);
                 memory.Position = 0;
                 bitmapImage = new BitmapImage();
                 bitmapImage.BeginInit();
                 bitmapImage.StreamSource = memory;
                 bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
                 bitmapImage.EndInit();
             }
             Image_Img.Source = bitmapImage;
             bitmapImage?.Freeze();
             bitmapImage = null;
         }
         catch (Exception ex)
         {
             throw new Exception(ex.Message);
         }
     }

     /// <summary>
     /// 鼠标左键按下
     /// </summary>
     /// <param name="sender"></param>
     /// <param name="e"></param>
     private void Image_Img_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
     {
         try
         {
             if (e.ChangedButton != MouseButton.Left) return;
             var pos = e.GetPosition((System.Windows.Controls.Image)e.Source);
             currentClickPoint = pos;
             isImageLeftButtonDown = true;
             var img = ((System.Windows.Controls.Image)e.Source).Source as BitmapSource;
             ColorPicker(img, pos);
         }
         catch (Exception ex)
         {
             throw new Exception(ex.Message);
         }
     }
     /// <summary>
     /// 图像点转真实点
     /// </summary>
     /// <param name="thumbnailX"></param>
     /// <returns></returns>
     private double ToCamRealX(double thumbnailX)
     {
         return (thumbnailX / Image_Img.ActualWidth) * (double)(originalBitmap?.Width ?? 0);
     }
     /// <summary>
     /// 图像点转真实点
     /// </summary>
     /// <param name="thumbnailY"></param>
     /// <returns></returns>
     private double ToCamRealY(double thumbnailY)
     {
         return (thumbnailY / Image_Img.ActualHeight) * (double)(originalBitmap?.Height ?? 0);
     }
     /// <summary>
     /// 颜色拾取
     /// </summary>
     /// <param name="img"></param>
     /// <param name="pos"></param>
     /// <exception cref="Exception"></exception>
     protected void ColorPicker(BitmapSource img, System.Windows.Point pos)
     {
         try
         {
             int stride = img.PixelWidth * 4;
             int size = img.PixelHeight * stride;
             byte[] pixels = new byte[(int)size];

             img.CopyPixels(pixels, stride, 0);

             // Get pixel
             //屏幕坐标转图像坐标
             var x = (int)ToCamRealX(pos.X);
             var y = (int)ToCamRealY(pos.Y);

             int index = y * stride + 4 * x;

             byte red = pixels[index];
             byte green = pixels[index + 1];
             byte blue = pixels[index + 2];
             byte alpha = pixels[index + 3];

             System.Drawing.Color color = System.Drawing.Color.FromArgb(alpha, blue, green, red);
             Label_R.Content = color.R.ToString();
             Label_G.Content = color.G.ToString();
             Label_B.Content = color.B.ToString();
             //string ColorText = "#" + color.A.ToString("X2") + color.R.ToString("X2") + color.G.ToString("X2") + color.B.ToString("X2");
             ColorShow(color);
         }
         catch (Exception ex)
         {
             throw new Exception(ex.Message);
         }
     }
     /// <summary>
     /// 颜色显示
     /// </summary>
     /// <param name="color"></param>
     /// <exception cref="Exception"></exception>
     private void ColorShow(System.Drawing.Color color)
     {
         try
         {
             CurrentColor = color;
             int w = (int)Image_Clolor.Width;
             int h = (int)Image_Clolor.Height;
             Bitmap bitmap = new Bitmap(w, h, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
             for (int x = 0; x < w; x++)
             {
                 for (int y = 0; y < h; y++)
                 {
                     bitmap.SetPixel(x, y, color);
                 }
             }
             BitmapImage bitmapImage;
             using (MemoryStream memory = new MemoryStream())
             {
                 bitmap.Save(memory, System.Drawing.Imaging.ImageFormat.Png);
                 memory.Position = 0;
                 bitmapImage = new BitmapImage();
                 bitmapImage.BeginInit();
                 bitmapImage.StreamSource = memory;
                 bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
                 bitmapImage.EndInit();
             }
             Image_Clolor.Source = bitmapImage;
             bitmapImage?.Freeze();
             bitmapImage = null;
             bitmap.Dispose();
         }
         catch (Exception ex)
         {
             throw new Exception(ex.Message);
         }
     }
     /// <summary>
     /// 鼠标滚动缩放
     /// </summary>
     /// <param name="sender"></param>
     /// <param name="e"></param>
     private void Image_Img_MouseWheel(object sender, MouseWheelEventArgs e)
     {
         try
         {
             System.Windows.Point center = e.GetPosition(Image_Img);
             double scale = 0;
             if (e.Delta > 0)
             {
                 scale = Image_Img_ScaleTransform.ScaleX + ScaleRatio;
                 if (scale > 30)
                 {
                     return;
                 }
             }
             else
             {
                 scale = Image_Img_ScaleTransform.ScaleX - ScaleRatio;
                 if (scale < 0.5)
                 {
                     return;
                 }
             }
             //图像
             Image_Img_ScaleTransform.ScaleX = scale;
             Image_Img_ScaleTransform.ScaleY = scale;
         }
         catch
         {
         }
     }
     /// <summary>
     /// 鼠标移动
     /// </summary>
     /// <param name="sender"></param>
     /// <param name="e"></param>
     private void Image_Img_PreviewMouseMove(object sender, MouseEventArgs e)
     {
         try
         {
             if (isImageLeftButtonDown == true)
             {
                 if (e.LeftButton == MouseButtonState.Pressed)
                 {
                     //移动
                     System.Windows.Point newPoint = e.GetPosition(Image_Img);
                     double deltaX = newPoint.X - currentClickPoint.X;
                     double deltaY = newPoint.Y - currentClickPoint.Y;
                     //图像
                     Image_Img_TranslateTransform.X += deltaX;
                     Image_Img_TranslateTransform.Y += deltaY;
                 }
             }
         }
         catch
         {

         }
     }
     /// <summary>
     /// 鼠标放开
     /// </summary>
     /// <param name="sender"></param>
     /// <param name="e"></param>
     private void Image_Img_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
     {
         isImageLeftButtonDown = false;
     }
     /// <summary>
     /// 鼠标右键
     /// </summary>
     /// <param name="sender"></param>
     /// <param name="e"></param>
     private void Image_Img_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
     {
         Recombination();
     }

     /// <summary>
     /// 重置图像大小
     /// </summary>
     private void Recombination()
     {
         try
         {
             //图像
             Image_Img_ScaleTransform.ScaleX = 1;
             Image_Img_ScaleTransform.ScaleY = 1;
             Image_Img_TranslateTransform.X = 0;
             Image_Img_TranslateTransform.Y = 0;
         }
         catch
         {
         }
     }

 }

3.效果

相关推荐
小二·8 小时前
微服务架构设计与实践
微服务·架构·wpf
暖馒9 小时前
WPF-Prism学习入门步骤记录
学习·wpf
baivfhpwxf202310 小时前
雷赛(Leadshine)EtherCAT 数字 I/O 模块(如 EMC-E5064-8)的状态指示灯(I/O 状态)说明
c#·wpf
故渊at1 天前
第二板块:Android 四大组件标准化学理 | 第十二篇:四大组件全景总结与系统服务(System Server)架构
android·架构·wpf·四大组件·system service
伶俜661 天前
# [特殊字符] 零基础学 ArkUI 数据持久化(专题三):5 种存储方案深度对比
学习·华为·wpf·harmonyos
IT策士1 天前
Redis 从入门到精通:数据结构String 与键管理
数据结构·redis·wpf
AC赳赳老秦1 天前
技术文章素材收集自动化:用 OpenClaw 自动爬取行业资讯、技术热点、优质文章
运维·开发语言·python·自动化·wpf·deepseek·openclaw
加号31 天前
【WPF】 Storyboard 故事板动画设计深度解析
wpf
xiaoshuaishuai81 天前
C# Avalonia 依赖属性与WPF的区别
开发语言·c#·wpf
大G的笔记本2 天前
生产级 Spring Boot 网关简单实现方案
wpf