Win10手记-取色器ColorPicker的实现

最近个人项目需要用到ColorPicker,但是适用于WinRT和Win10的基本没用,所以只能自己造轮子了。

平台环境

  1. Windows 10
  2. Visual Studio 2015

思路

确定需求后,我查找了各方信息,发现PhotoShop的ColorPicker最符合我的需求,这里我们实现的仿PhotoShop HSB取色器,样式如下图。

确定目标后,则需要研究具体的调色原理了。我们都知道,程序使用的一般都是RGB颜色,而这里使用的则是HSB颜色。顾名思义,HSB分别是指色相(Hue)纯度(Saturation)明度(Brightness),这三个参数构成了HSB颜色,这比RGB颜色更易于选取,能够同时提供的颜色种类最多,对应HSV。色相可以通过色环来表示,HSB三个参数均和RGB保持着数学上的关系。详细信息可见于维基百科:https://en.wikipedia.org/wiki/HSL_and_HSV

这里计算流程为先计算色相,然后固定亮度,最后计算饱和度。首先对于色相,计算相对简单,分析色环,即可发现处于不同度数区间对应的RGB值也是有规律的。

具体来说假定HSB值为(H,100%,100%)条件下,RGB值对应关系如下:


H         Color     Value


-----------------------------


0-60         G       0->255


60-120      R       255->0


120-180    B       0->255


180-240    G       255->0


240-360    R       0->255


300-360    B       255->0

接下来根据饱和度S来进一步计算出RGB,此时假定条件为(H,S,100%),计算公式如下:

r"= r‘+ (255 - r‘) * s

g"= g‘+ (255 - g‘) * s
b"= b‘+ (255 - b‘) * s

其中r‘,g‘,b‘分别为第一步计算出的RGB结果。

最后一步,亮度L值与RGB关系最简单,RGB只需要分别乘以亮度即可。

实现代码

核心计算类CWColorService

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.UI;

namespace CWColorPicker.Core
{
    public class CWColorService
    {
        /// <summary>
        /// Convert HSB value to RGB value
        /// </summary>
        /// <param name="hsb">HSB value</param>
        /// <returns>RGB value</returns>
        public static int[] HSBToRGB(float[] hsb)
        {
            var rgb = new float[3];
            var hValue = hsb[0];
            /*
            Firstly, we need to calculate RGB value, when the HSB value is (h,100%,100%).
                H         Color     Value
              ----------------------------
               0-60         G       0->255
               60-120       R       255->0
               120-180      B       0->255
               180-240      G       255->0
               240-360      R       0->255
               300-360      B       255->0
            */
            if (hValue <= 60)
            {
                rgb[0] = 255;
                rgb[1] = hValue / 60.0f * 255;
            }
            else if (hValue <= 120)
            {
                hValue -= 60;
                rgb[1] = 255;
                rgb[0] = (1 - hValue / 60.0f) * 255;
            }
            else if (hValue <= 180)
            {
                hValue -= 120;
                rgb[1] = 255;
                rgb[2] = hValue / 60.0f * 255;
            }
            else if (hValue <= 240)
            {
                rgb[2] = 255;
                hValue -= 180;
                rgb[1] = (1 - hValue / 60.0f) * 255;
            }
            else if (hValue <= 300)
            {
                rgb[2] = 255;
                hValue -= 240;
                rgb[0] = hValue / 60.0f * 255;
            }
            else
            {
                hValue -= 300;
                rgb[0] = 255;
                rgb[2] = (1 - hValue / 60.0f) * 255;
            }
            /*
            Secondly, acorrding to the value of staturation, we can calculate the rgb value, when the value of hsb is (h,s,100%)
            -------------------------
            r"= r‘+ (255 - r‘) * s
            g"= g‘+ (255 - g‘) * s
            b"= b‘+ (255 - b‘) * s
            */
            for (int i = 0; i < 3; i++)
            {
                rgb[i] += (255 - rgb[i]) * hsb[1];
            }
            var result = new int[3];
            /*
            Finally, we need to calculate the real value of rgb, according to the value of brightness
            r = r" * br
            g = g" * br
            b = g" * br
            */
            for (int i = 0; i < 3; i++)
            {
                rgb[i] *= hsb[2];
                result[i] = (int)(rgb[i] + 0.5);
            }
            return result;
        }

        /// <summary>
        /// Convert RGB value to HSB value
        /// </summary>
        /// <param name="rgb">RGB Value</param>
        /// <returns></returns>
        public static float[] RGBToHSB(int[] rgb)
        {
            var result = new float[3];
            return result;
        }

        /// <summary>
        /// get color from rgb value
        /// </summary>
        /// <param name="r"></param>
        /// <param name="g"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static Color ColorFromRGB(int r,int g,int b)
        {
            var color = Color.FromArgb(255, (byte)r, (byte)g, (byte)b);
            return color;
        }
        public static Color ColorFromRGB(int[] rgb)
        {
            var color = ColorFromRGB(rgb[0], rgb[1], rgb[2]);
            return color;
        }
    }
}

自定义Xaml控件

<UserControl
    x:Class="CWColorPicker.UI.CWColorPicker"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:CWColorPicker.UI"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="150"
    d:DesignWidth="150">

    <Grid x:Name="ColorPanel">
        <Image x:Name="ColorImage" Source="ms-appx:///Resource/color-pan.png" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" PointerPressed="ColorImage_PointerPressed" Margin="0"></Image>
    </Grid>
</UserControl>
namespace CWColorPicker.UI
{
    public sealed partial class CWColorPicker : UserControl
    {

        /// <summary>
        /// current selected color
        /// </summary>
        public Color Color
        {
            get { return (Color)GetValue(ColorProperty); }
            set { SetValue(ColorProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Color.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ColorProperty =
            DependencyProperty.Register("Color", typeof(Color), typeof(CWColorPicker), new PropertyMetadata(0));

        /// <summary>
        /// current ponit in color picker
        /// </summary>
        public Point ColorPoint
        {
            get { return (Point)GetValue(ColorPointProperty); }
            set { SetValue(ColorPointProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ColorPoint.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ColorPointProperty =
            DependencyProperty.Register("ColorPoint", typeof(Point), typeof(CWColorPicker), new PropertyMetadata(0));

        /// <summary>
        /// ColorSelected Event
        /// </summary>
        public event EventHandler<CWColorSelectedArgs> ColorSelected;

        private void ColorChange(float[] hsb)
        {
            if (ColorSelected != null)
            {
                ColorSelected(this, new CWColorSelectedArgs(CWColorService.ColorFromRGB(CWColorService.HSBToRGB(hsb))));
            }
        }

        private void ColorChange(Color color)
        {
            if (ColorSelected != null)
            {
                ColorSelected(this, new CWColorSelectedArgs(color));
            }
        }

        public CWColorPicker()
        {
            this.InitializeComponent();
            initPanelImage();

        }

        /// <summary>
        /// load resource image from dll
        /// </summary>
        private async void initPanelImage()
        {
            var panel = new BitmapImage();
            var imageStream = Assembly.Load(new AssemblyName("CWColorPicker")).GetManifestResourceStream("CWColorPicker.Resource.color-pan.png");
            await panel.SetSourceAsync(imageStream.AsRandomAccessStream());
            this.ColorImage.Source = panel;
        }

        /// <summary>
        /// calculate the color according to the touch point
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ColorImage_PointerPressed(object sender, PointerRoutedEventArgs e)
        {
            // Debug.WriteLine("pressed");
            //  Debug.WriteLine(e.GetCurrentPoint(this.ColorPanel).Position);

            var position = e.GetCurrentPoint(this.ColorImage).Position;
            var hsb = new float[3];
            hsb[2] = 1.0f;
            hsb[0] = (float)(int)(position.X / this.ColorImage.ActualWidth * 360);
            hsb[1] = float.Parse((position.Y / this.ColorImage.ActualHeight).ToString("0.00"));
            this.Color = CWColorService.ColorFromRGB(CWColorService.HSBToRGB(hsb));
            this.ColorPoint = position;
            ColorChange(this.Color);
        }

    }
}

其他代码及完整项目可以在Github上获取,地址:https://github.com/ChangweiZhang/CWColorPicker

实现效果

时间: 2024-10-10 13:43:12

Win10手记-取色器ColorPicker的实现的相关文章

win10下, TakeColor取色器错位 指针偏移问题 解决方法

当win10的屏幕缩放比例不是100%时,屏幕取色器ColorPix指针会发生偏移 解决: 1.右击 —> 属性 —> 兼容性 2.勾选"高DPI缩放替代" 原文地址:https://www.cnblogs.com/FengZeng666/p/12539762.html

TakeColor 屏幕取色器 8.0 中文绿色版

软件名称: TakeColor 屏幕取色器软件语言: 简体中文授权方式: 免费软件运行环境: Win8 / Win7 / Vista / WinXP软件大小: 210KB图片预览: 软件简介:使用方便的屏幕取色器,别的取色工具总是用鼠标点击来取色的,这个工具可以直接用alt+c快键捷来完成屏幕取色 软件下载页面:http://www.bkill.com/download/23831.html 软件下载地址:电信下载 联通下载

给大家介绍一个java取色器工具

Java取色器中调用了robot方法的getPixelColor方法下面我们来看robot类中方法的具体实现如下 getPixelColor public Color getPixelColor(int x, int y) 返回给定屏幕坐标处的像素颜色. 参数: x - 像素的 X 位置 y - 像素的 Y 位置 返回: 像素的颜色 取色器通过x,y坐标返回颜色值 我通可以通过定义鼠标监听来获得鼠标的x,y坐标然后来获得要取的位置的颜色值 具体例子如下 public void mouseClic

powerpoint取色器有什么用|ppt取色器使用教程

在使用powerpoint过程中常常发现一些功能我们很少用到,其实是自己不会用的原因,关于powerpoint取色器有什么用呢?接下来我们一起来学一下ppt取色器使用教程. powerpoint取色器有什么用 ppt取色器使用教程 ppt取色器简介 想要自己的幻灯片跟图片的颜色吻合那就要用到取色器这个功能了,但是取色器的运用也是有一定的技巧的.辛苦地尝试精确匹配形状和图片的颜色,配合PowerPoint2013演示文稿的其他部分,为您的幻灯片提供富有凝聚力的外观,您是否已经厌倦?使用 Power

jsColor取色器插件的基本用法

最近项目中用到了一款取色器插件,非常简洁.实用. 官网地址:http://jscolor.com/ 使用方法:1.引入js文件. <script type="text/javascript" src="jscolor/jscolor.js"></script> 2.设置文本框class并设置默认显示颜色. <input class="color" type="text" value="f

C#取色器

闲来无事,就写了一个取色器.原理其实很简单,只需要两步, 获取鼠标光标的位置, 获取当前鼠标光标的位置的RGB颜色值. 获取鼠标光标的位置: System.Drawing.Point p = MousePosition; 获取指定坐标的RGB颜色值,这里我们需要用到1个WIN32的API函数:GetPixel. GetPixel函数的作用是检索坐标点的像素的RGB颜色值,函数原型为COLORREF GetPixel(HDC hdc, int nXPos, int nYPos) 由于这个是系统提供

使用谷歌浏览器取色器取色

首先需要调到开发者模式,然后再点击图下的标识. 接着变成图标,点击就可以出现取色器. 原文地址:https://www.cnblogs.com/apolloren/p/12233060.html

设置Win10文件资源管理器默认打开“这台电脑”

当Windows系统进入Win7之后,任务栏默认的文件资源管理器图标功能是“库”:Win8/Win8.1的这一按钮打开的是“这台电脑”.进入Win10之后,目前这一功能默认变为“快速访问”(曾经被称为“主页”).当然,很多用户还是习惯于打开“这台电脑”,所以微软现在给了这部分用户一个选择的机会. 方法很简单,操作如下: 1.打开任意一个文件资源管理器,然后在“查看”标签页中点击“选项”按钮 2.在弹出的窗口顶部下拉菜单中,选择“这台电脑” 3.单击确定后,再次点击任务栏“文件资源管理器”按钮就可

win10照片查看器不能看jpg等格式图片

1.首先,我们需要使用注册表编辑器来开启Win10系统照片查看器功能,因为其实这个功能是被隐藏了,那么按下Windows徽标键+R键,打开运行命令窗口,输入“regedit”命令. 2.打开注册表编辑器之后,我们双击左侧的目录,依次打开HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft目录. 3.在Microsoft目录下,我们需要找到Windows Photo Viewer\Capabilities\FileAssociations目录项,直到看到该子目录下的一系列关键