Win10手记-取色器ColorPicker的实现

来源:互联网 发布:township清除数据ios 编辑:程序博客网 时间:2024/06/10 09:26

最近个人项目需要用到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

 

实现效果


阅读全文
0 0
原创粉丝点击