using ryCommon;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;

namespace ryControls
{
    #region RGB / HSV / HSL 颜色模型类
    /// <summary>
    /// 类      名:ColorHSL
    /// 功      能:H 色相 \ S 饱和度(纯度) \ L 亮度 颜色模型 
    /// 日      期:2015-02-08
    /// 修      改:2015-03-20
    /// 作      者:ls9512
    /// </summary>
    public class ColorHSL
    {
        /// <summary>
        /// HSL颜色
        /// </summary>
        /// <param name="h"></param>
        /// <param name="s"></param>
        /// <param name="l"></param>
        public ColorHSL(int h, int s, int l)
        {
            this._h = h;
            this._s = s;
            this._l = l;
        }

        private int _h;
        private int _s;
        private int _l;

        /// <summary>
        /// 色相
        /// </summary>
        public int H
        {
            get { return this._h; }
            set
            {
                this._h = value;
                this._h = this._h > 360 ? 360 : this._h;
                this._h = this._h < 0 ? 0 : this._h;
            }
        }

        /// <summary>
        /// 饱和度(纯度)
        /// </summary>
        public int S
        {
            get { return this._s; }
            set
            {
                this._s = value;
                this._s = this._s > 255 ? 255 : this._s;
                this._s = this._s < 0 ? 0 : this._s;
            }
        }

        /// <summary>
        /// 饱和度
        /// </summary>
        public int L
        {
            get { return this._l; }
            set
            {
                this._l = value;
                this._l = this._l > 255 ? 255 : this._l;
                this._l = this._l < 0 ? 0 : this._l;
            }
        }
    }

    /// <summary>
    /// 类      名:ColorHSV
    /// 功      能:H 色相 \ S 饱和度(纯度) \ V 明度 颜色模型 
    /// 日      期:2015-01-22
    /// 修      改:2015-03-20
    /// 作      者:ls9512
    /// </summary>
    public class ColorHSV
    {
        /// <summary>
        /// 构造方法
        /// </summary>
        /// <param name="h"></param>
        /// <param name="s"></param>
        /// <param name="v"></param>
        public ColorHSV(int h, int s, int v)
        {
            this._h = h;
            this._s = s;
            this._v = v;
        }

        private int _h;
        private int _s;
        private int _v;

        /// <summary>
        /// 色相
        /// </summary>
        public int H
        {
            get { return this._h; }
            set
            {
                this._h = value;
                this._h = this._h > 360 ? 360 : this._h;
                this._h = this._h < 0 ? 0 : this._h;
            }
        }

        /// <summary>
        /// 饱和度(纯度)
        /// </summary>
        public int S
        {
            get { return this._s; }
            set
            {
                this._s = value;
                this._s = this._s > 255 ? 255 : this._s;
                this._s = this._s < 0 ? 0 : this._s;
            }
        }

        /// <summary>
        /// 明度
        /// </summary>
        public int V
        {
            get { return this._v; }
            set
            {
                this._v = value;
                this._v = this._v > 255 ? 255 : this._v;
                this._v = this._v < 0 ? 0 : this._v;
            }
        }
    }

    /// <summary>
    /// 类      名:ColorRGB
    /// 功      能:R 红色 \ G 绿色 \ B 蓝色 颜色模型
    ///                 所有颜色模型的基类,RGB是用于输出到屏幕的颜色模式,所以所有模型都将转换成RGB输出
    /// 日      期:2015-01-22
    /// 修      改:2015-03-20
    /// 作      者:ls9512
    /// </summary>
    public class ColorRGB
    {
        /// <summary>
        /// 构造方法
        /// </summary>
        /// <param name="r"></param>
        /// <param name="g"></param>
        /// <param name="b"></param>
        public ColorRGB(int r, int g, int b)
        {
            this._r = r;
            this._g = g;
            this._b = b;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="color"></param>
        public ColorRGB(Color color)
        {
            this._r = color.R;
            this._g = color.G;
            this._b = color.B;
        }
        private int _r;
        private int _g;
        private int _b;

        /// <summary>
        /// 红色
        /// </summary>
        public int R
        {
            get { return this._r; }
            set
            {
                this._r = value;
                this._r = this._r > 255 ? 255 : this._r;
                this._r = this._r < 0 ? 0 : this._r;
            }
        }

        /// <summary>
        /// 绿色
        /// </summary>
        public int G
        {
            get { return this._g; }
            set
            {
                this._g = value;
                this._g = this._g > 255 ? 255 : this._g;
                this._g = this._g < 0 ? 0 : this._g;
            }
        }

        /// <summary>
        /// 蓝色
        /// </summary>
        public int B
        {
            get { return this._b; }
            set
            {
                this._b = value;
                this._b = this._b > 255 ? 255 : this._b;
                this._b = this._b < 0 ? 0 : this._b;
            }
        }

        /// <summary>
        /// 获取实际颜色
        /// </summary>
        /// <returns></returns>
        public Color GetColor()
        {
            return Color.FromArgb(this._r, this._g, this._b);
        }
    }
    #endregion

    /// <summary>
    /// 类      名:ColorHelper
    /// 功      能:提供从RGB到HSV/HSL色彩空间的相互转换
    /// 日      期:2015-02-08
    /// 修      改:2015-03-20
    /// 作      者:ls9512
    /// </summary>
    public static class ColorHelper
    {
        /// <summary>
        /// RGB转换HSV
        /// </summary>
        /// <param name="rgb"></param>
        /// <returns></returns>
        public static ColorHSV RgbToHsv(ColorRGB rgb)
        {
            float min, max, tmp, H, S, V;
            float R = rgb.R * 1.0f / 255, G = rgb.G * 1.0f / 255, B = rgb.B * 1.0f / 255;
            tmp = Math.Min(R, G);
            min = Math.Min(tmp, B);
            tmp = Math.Max(R, G);
            max = Math.Max(tmp, B);
            // H
            H = 0;
            if (max == min)
            {
                H = 0;
            }
            else if (max == R && G > B)
            {
                H = 60 * (G - B) * 1.0f / (max - min) + 0;
            }
            else if (max == R && G < B)
            {
                H = 60 * (G - B) * 1.0f / (max - min) + 360;
            }
            else if (max == G)
            {
                H = H = 60 * (B - R) * 1.0f / (max - min) + 120;
            }
            else if (max == B)
            {
                H = H = 60 * (R - G) * 1.0f / (max - min) + 240;
            }
            // S
            if (max == 0)
            {
                S = 0;
            }
            else
            {
                S = (max - min) * 1.0f / max;
            }
            // V
            V = max;
            return new ColorHSV((int)H, (int)(S * 255), (int)(V * 255));
        }

        /// <summary>
        /// HSV转换RGB
        /// </summary>
        /// <param name="hsv"></param>
        /// <returns></returns>
        public static ColorRGB HsvToRgb(ColorHSV hsv)
        {
            if (hsv.H == 360) hsv.H = 359; // 360为全黑,原因不明
            float R = 0f, G = 0f, B = 0f;
            if (hsv.S == 0)
            {
                return new ColorRGB(hsv.V, hsv.V, hsv.V);
            }
            float S = hsv.S * 1.0f / 255, V = hsv.V * 1.0f / 255;
            int H1 = (int)(hsv.H * 1.0f / 60), H = hsv.H;
            float F = H * 1.0f / 60 - H1;
            float P = V * (1.0f - S);
            float Q = V * (1.0f - F * S);
            float T = V * (1.0f - (1.0f - F) * S);
            switch (H1)
            {
                case 0: R = V; G = T; B = P; break;
                case 1: R = Q; G = V; B = P; break;
                case 2: R = P; G = V; B = T; break;
                case 3: R = P; G = Q; B = V; break;
                case 4: R = T; G = P; B = V; break;
                case 5: R = V; G = P; B = Q; break;
            }
            R = R * 255;
            G = G * 255;
            B = B * 255;
            while (R > 255) R -= 255;
            while (R < 0) R += 255;
            while (G > 255) G -= 255;
            while (G < 0) G += 255;
            while (B > 255) B -= 255;
            while (B < 0) B += 255;
            return new ColorRGB((int)R, (int)G, (int)B);
        }

        /// <summary>
        /// RGB转换HSL
        /// </summary>
        /// <param name="rgb"></param>
        /// <returns></returns>
        public static ColorHSL RgbToHsl(ColorRGB rgb)
        {
            float min, max, tmp, H, S, L;
            float R = rgb.R * 1.0f / 255, G = rgb.G * 1.0f / 255, B = rgb.B * 1.0f / 255;
            tmp = Math.Min(R, G);
            min = Math.Min(tmp, B);
            tmp = Math.Max(R, G);
            max = Math.Max(tmp, B);
            // H
            H = 0;
            if (max == min)
            {
                H = 0;  // 此时H应为未定义,通常写为0
            }
            else if (max == R && G > B)
            {
                H = 60 * (G - B) * 1.0f / (max - min) + 0;
            }
            else if (max == R && G < B)
            {
                H = 60 * (G - B) * 1.0f / (max - min) + 360;
            }
            else if (max == G)
            {
                H = H = 60 * (B - R) * 1.0f / (max - min) + 120;
            }
            else if (max == B)
            {
                H = H = 60 * (R - G) * 1.0f / (max - min) + 240;
            }
            // L 
            L = 0.5f * (max + min);
            // S
            S = 0;
            if (L == 0 || max == min)
            {
                S = 0;
            }
            else if (0 < L && L < 0.5)
            {
                S = (max - min) / (L * 2);
            }
            else if (L > 0.5)
            {
                S = (max - min) / (2 - 2 * L);
            }
            return new ColorHSL((int)H, (int)(S * 255), (int)(L * 255));
        }

        /// <summary>
        /// HSL转换RGB
        /// </summary>
        /// <param name="hsl">H, S and L input range = 0 -1.0</param>
        /// <returns></returns>
        public static ColorRGB HslToRgb(ColorHSL hsl)
        {
            double R = 0;
            double G = 0;
            double B = 0;
            double var_1 = 0;
            double var_2 = 0;
            double H = hsl.H / 360d;
            double L = hsl.L / 255d;
            double S = hsl.S / 255d;
            if (hsl.S == 0)
            {
                R = hsl.L;
                G = hsl.L;
                B = hsl.L;
            }
            else
            {
                if (L < 0.5) { var_2 = L * (1 + S); }
                else { var_2 = (L + S) - (S * L); }
                var_1 = 2 * L - var_2;
                R = 255 * Hue_2_RGB(var_1, var_2, H + (1 / 3d));
                G = 255 * Hue_2_RGB(var_1, var_2, H);
                B = 255 * Hue_2_RGB(var_1, var_2, H - (1 / 3d));
            }
            return new ColorRGB(R.ToInt(),G.ToInt(), B.ToInt());
        }
        static double Hue_2_RGB(double v1, double v2, double vH)
        {
            if (vH < 0) vH += 1;
            if (vH > 1) vH -= 1;
            if (6.0 * vH < 1) return v1 + (v2 - v1) * 6.0 * vH;
            if (2.0 * vH < 1) return v2;
            if (3.0 * vH < 2) return v1 + (v2 - v1) * ((2.0 / 3.0) - vH) * 6.0;
            return (v1);
        }
        /// <summary>
        /// RGB转CMYK
        /// </summary>
        /// <param name="rgb"></param>
        /// <param name="c"></param>
        /// <param name="m"></param>
        /// <param name="y"></param>
        /// <param name="k"></param>
        public static void RGB2CMYK(ColorRGB rgb, out double c, out double m, out double y, out double k)
        {
            RGB2CMYK(rgb.R, rgb.G,rgb.B,out c,out m,out y,out k);
        }
        /// <summary>
        /// RGB转CMYK
        /// </summary>
        /// <param name="red"></param>
        /// <param name="green"></param>
        /// <param name="blue"></param>
        /// <param name="c"></param>
        /// <param name="m"></param>
        /// <param name="y"></param>
        /// <param name="k"></param>
        public static void RGB2CMYK(int red, int green, int blue, out double c, out double m, out double y, out double k)
        {
            c = (double)(255 - red) / 255;
            m = (double)(255 - green) / 255;
            y = (double)(255 - blue) / 255;

            k = (double)Math.Min(c, Math.Min(m, y));
            if (k == 1.0)
            {
                c = m = y = 0;k = 100;
            }
            else
            {
                c = (c - k)*100 / (1 - k);
                m = (m - k)*100 / (1 - k);
                y = (y - k)*100 / (1 - k);
                k = k * 100;
            }
        }
        /// <summary>
        /// CMYK转RGB
        /// </summary>
        /// <param name="c"></param>
        /// <param name="m"></param>
        /// <param name="y"></param>
        /// <param name="k"></param>
        /// <returns></returns>
        public static ColorRGB CMYK2RGB(double c, double m, double y, double k)
        {
           var r = Convert.ToInt32((1.0 - c/100d) * (1.0 - k / 100d) * 255.0);
           var g = Convert.ToInt32((1.0 - m / 100d) * (1.0 - k / 100d) * 255.0);
           var b = Convert.ToInt32((1.0 - y / 100d) * (1.0 - k / 100d) * 255.0);
            return new ColorRGB(r,g,b);
        }
        /// <summary>
        /// Standard-RGB → XYZ,X、Y、Z 使用 D65/2°标准光源.
        /// </summary>
        /// <param name="rgb"></param>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="z"></param>
        public static void RGB2XYZ(ColorRGB rgb,out double x,out double y,out double z)
        {
            double var_R = (rgb.R / 255d);
            double var_G = (rgb.G / 255d);
            double var_B = (rgb.B / 255d);
            if (var_R > 0.04045) { var_R = Math.Pow(((var_R + 0.055)/1.055),2.4); }
            else { var_R = var_R / 12.92; }
            if (var_G > 0.04045) { var_G = Math.Pow(((var_G + 0.055) / 1.055), 2.4); }
            else { var_G = var_G / 12.92; }
            if (var_B > 0.04045) { var_B = Math.Pow(((var_B + 0.055) / 1.055), 2.4); }
            else { var_B = var_B / 12.92; }
            var_R = var_R * 100;
            var_G = var_G * 100;
            var_B = var_B * 100;
            x = var_R * 0.4124 + var_G * 0.3576 + var_B * 0.1805;
            y = var_R * 0.2126 + var_G * 0.7152 + var_B * 0.0722;
            z = var_R * 0.0193 + var_G * 0.1192 + var_B * 0.9505;
        }
        /// <summary>
        /// XYZ → Standard-RGB,X、Y、Z 使用 D65/2°标准光源.
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="z"></param>
        /// <returns></returns>
        public static ColorRGB XYZ2RGB(double x,double y,double z)
        {
            double var_X = (x / 100d);
            double var_Y = (y / 100d);
            double var_Z = (z / 100d);
            double var_R = var_X * 3.2406 + var_Y * -1.5372 + var_Z * -0.4986;
            double var_G = var_X * -0.9689 + var_Y * 1.8758 + var_Z * 0.0415;
            double var_B = var_X * 0.0557 + var_Y * -0.2040 + var_Z * 1.0570;
            if (var_R > 0.0031308) { var_R = 1.055 * (Math.Pow(var_R,(1 / 2.4d))) - 0.055; }
            else { var_R = 12.92 * var_R; }
            if (var_G > 0.0031308) { var_G = 1.055 * (Math.Pow(var_G, (1 / 2.4d))) - 0.055; }
            else { var_G = 12.92 * var_G; }
            if (var_B > 0.0031308) { var_B = 1.055 * (Math.Pow(var_B, (1 / 2.4d))) - 0.055; }
            else { var_B = 12.92 * var_B; }
            return new ColorRGB((var_R * 255).ToInt(), (var_G * 255).ToInt(), (var_B * 255).ToInt());
        }
        /// <summary>
        /// XYZ → Adobe-RGB,X、Y、Z 使用 D65/2°标准光源.RGB Adobe 1998
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="z"></param>
        /// <returns></returns>
        public static ColorRGB XYZ2AdobeRGB(double x, double y, double z)
        {
            double var_X = (x / 100d);
            double var_Y = (y / 100d);
            double var_Z = (z / 100d);
            double var_R = var_X * 2.04137 + var_Y * -0.56495 + var_Z * -0.34469;
            double var_G = var_X * -0.96927 + var_Y * 1.87601 + var_Z * 0.04156;
            double var_B = var_X * 0.01345 + var_Y * -0.11839 + var_Z * 1.01541;
            var_R = Math.Pow(var_R, 1 / 2.19921875);
            var_G = Math.Pow(var_G, 1 / 2.19921875);
            var_B = Math.Pow(var_B, 1 / 2.19921875);
            return new ColorRGB((var_R * 255).ToInt(), (var_G * 255).ToInt(), (var_B * 255).ToInt());
        }
        /// <summary>
        /// Adobe-RGB → XYZ,X、Y、Z 使用 D65/2°标准光源.RGB Adobe 1998
        /// </summary>
        /// <param name="rgb"></param>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="z"></param>
        public static void AdobeRGB2XYZ(ColorRGB rgb, out double x, out double y, out double z)
        {
            double var_R = (rgb.R / 255d);
            double var_G = (rgb.G / 255d);
            double var_B = (rgb.B / 255d);
            var_R = Math.Pow(var_R, 2.19921875);
            var_G = Math.Pow(var_G, 2.19921875);
            var_B = Math.Pow(var_B, 2.19921875);
            var_R = var_R * 100;
            var_G = var_G * 100;
            var_B = var_B * 100;
            x = var_R * 0.57667 + var_G * 0.18555 + var_B * 0.18819;
            y = var_R * 0.29738 + var_G * 0.62735 + var_B * 0.07527;
            z = var_R * 0.02703 + var_G * 0.07069 + var_B * 0.99110;
        }
        /// <summary>
        /// Yxy转RGB
        /// </summary>
        /// <param name="Y"></param>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <returns></returns>
        public static ColorRGB Yxy2RGB(double Y, double x, double y)
        {
            double X = x * (Y / y);
            double Z = (1 - x - y) * (Y / y);
            return XYZ2RGB(X, Y, Z);
        }
        /// <summary>
        /// RGB转Yxy
        /// </summary>
        /// <param name="rgb"></param>
        /// <param name="Y"></param>
        /// <param name="x"></param>
        /// <param name="y"></param>
        public static void RGB2Yxy(ColorRGB rgb, out double Y, out double x, out double y)
        {
            RGB2XYZ(rgb, out double X, out Y, out double Z);
            x = X / (X + Y + Z);
            y = Y / (X + Y + Z);
        }
    }
}
