using System; using System.Linq; using WPFluent.Controls; namespace WPFluent.Extensions { public static class HsbExtensions { private static bool IsCloseTo(this double value, double target, double tolerance = double.Epsilon) => Math.Abs( value - target) < tolerance; /// /// 将 HSB(色相、饱和度、亮度)颜色空间转换为 Color 对象。 /// /// /// /// public static Color ToColor(this Controls.Hsb hsb) { //0~1 var hue = hsb.Hue; var saturation = hsb.Saturation; var brightness = hsb.Brightness; var opacity = hsb.Opacity; brightness *= 255; //饱和度为0,直接返回亮度值 if (saturation.IsCloseTo(0)) return Color.FromArgb((byte)brightness, (byte)brightness, (byte)brightness, (byte)brightness); opacity *= 255; //处理色相超出范围 if (hue.IsCloseTo(360)) hue = 0; while (hue > 360) hue -= 360; while (hue < 0) hue += 360; //通过色相返回颜色 hue /= 60; //以60作为一个区间,通过switch判断 var i = (int)Math.Floor(hue); //计算出色相值在当前区间内的偏移量 var f = hue - i; //计算出低饱和度情况下的亮度值 var p = brightness * (1 - saturation); //计算出中间饱和度情况下的亮度值 var q = brightness * (1 - saturation * f); //计算出高饱和度情况下的亮度值 var t = brightness * (1 - saturation * (1 - f)); return i switch { //[0~60)红色区间 0 => Color.FromArgb((byte)opacity, (byte)brightness, (byte)t, (byte)p), //[60~120)黄色区间 1 => Color.FromArgb((byte)opacity, (byte)q, (byte)brightness, (byte)p), //[120~180)绿色区间 2 => Color.FromArgb((byte)opacity, (byte)p, (byte)brightness, (byte)t), //[180~240)青色区间 3 => Color.FromArgb((byte)opacity, (byte)p, (byte)q, (byte)brightness), //[240~300)蓝色区间 4 => Color.FromArgb((byte)opacity, (byte)t, (byte)p, (byte)brightness), //[300~360)洋红色区间 5 => Color.FromArgb((byte)opacity, (byte)brightness, (byte)p, (byte)q), _ => throw new InvalidOperationException("不可用的HSB值"), }; } /// /// 将 Color 对象转换为 HSB(色相、饱和度、亮度)颜色空间。 /// /// /// public static Controls.Hsb ToHsb(this Color color) { double r = color.R; double g = color.G; double b = color.B; double a = color.A; r /= 255; g /= 255; b /= 255; a /= 255; var rgb = new[] { r, g, b }; var max = rgb.Max(); var min = rgb.Min(); var brightness = max; var hue = max; var delta = max - min; var saturation = max.IsCloseTo(0) ? 0 : delta / max; if (max.IsCloseTo(min)) { hue = 0; // 无色,未定义 } else { if (max.IsCloseTo(r)) { hue = (g - b) / delta + (g < b ? 6 : 0); } else if (max.IsCloseTo(g)) { hue = (b - r) / delta + 2; } else if (max.IsCloseTo(b)) { hue = (r - g) / delta + 4; } hue *= 60; } return new Hsb(hue, saturation, brightness, a); } } }