124 lines
4.1 KiB
C#
124 lines
4.1 KiB
C#
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;
|
||
|
||
/// <summary>
|
||
/// 将 HSB(色相、饱和度、亮度)颜色空间转换为 Color 对象。
|
||
/// </summary>
|
||
/// <param name="hsb"></param>
|
||
/// <returns></returns>
|
||
/// <exception cref="InvalidOperationException"></exception>
|
||
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值"),
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 将 Color 对象转换为 HSB(色相、饱和度、亮度)颜色空间。
|
||
/// </summary>
|
||
/// <param name="color"></param>
|
||
/// <returns></returns>
|
||
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);
|
||
}
|
||
}
|
||
}
|