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);
}
}
}