zoukankan      html  css  js  c++  java
  • 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

     

    实现效果

  • 相关阅读:
    第五周:项目日记(3)
    第四周:项目日记(2)
    第三周:项目日记(1)
    需求获取常见的方法是进行客户访谈,结合你的实践谈谈会遇到什么问题,你是怎么解决的?
    面向过程(或者叫结构化)分析方法与面向对象分析方法到底区别在哪里?请根据自己的理解简明扼要的回答。
    你认为一些军事方面的软件系统采用什么样的开发模型比较合适?
    第八周作业
    第七周作业
    当下大部分互联网创业公司为什么都愿意采用增量模型来做开发?
    第五周作业
  • 原文地址:https://www.cnblogs.com/mantgh/p/4912078.html
Copyright © 2011-2022 走看看