2025-04-24 20:56:44 +08:00
|
|
|
|
using System;
|
2024-09-22 11:05:41 +08:00
|
|
|
|
using System.Linq;
|
|
|
|
|
|
|
2025-04-24 20:56:44 +08:00
|
|
|
|
using WPFluent.Controls;
|
|
|
|
|
|
|
2024-09-22 11:05:41 +08:00
|
|
|
|
|
2025-02-10 20:53:40 +08:00
|
|
|
|
namespace WPFluent.Extensions
|
2024-09-22 11:05:41 +08:00
|
|
|
|
{
|
|
|
|
|
|
public static class HsbExtensions
|
|
|
|
|
|
{
|
2025-02-10 20:53:40 +08:00
|
|
|
|
private static bool IsCloseTo(this double value, double target, double tolerance = double.Epsilon) => Math.Abs(
|
|
|
|
|
|
value - target) <
|
|
|
|
|
|
tolerance;
|
|
|
|
|
|
|
2024-09-22 11:05:41 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 将 HSB(色相、饱和度、亮度)颜色空间转换为 Color 对象。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="hsb"></param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
/// <exception cref="InvalidOperationException"></exception>
|
2025-04-24 20:56:44 +08:00
|
|
|
|
public static Color ToColor(this Controls.Hsb hsb)
|
2024-09-22 11:05:41 +08:00
|
|
|
|
{
|
|
|
|
|
|
//0~1
|
|
|
|
|
|
var hue = hsb.Hue;
|
|
|
|
|
|
var saturation = hsb.Saturation;
|
|
|
|
|
|
var brightness = hsb.Brightness;
|
|
|
|
|
|
var opacity = hsb.Opacity;
|
|
|
|
|
|
brightness *= 255;
|
|
|
|
|
|
//饱和度为0,直接返回亮度值
|
2025-04-24 20:56:44 +08:00
|
|
|
|
if (saturation.IsCloseTo(0))
|
2024-09-22 11:05:41 +08:00
|
|
|
|
return Color.FromArgb((byte)brightness, (byte)brightness, (byte)brightness, (byte)brightness);
|
|
|
|
|
|
opacity *= 255;
|
|
|
|
|
|
//处理色相超出范围
|
2025-04-24 20:56:44 +08:00
|
|
|
|
if (hue.IsCloseTo(360))
|
2024-09-22 11:05:41 +08:00
|
|
|
|
hue = 0;
|
2025-04-24 20:56:44 +08:00
|
|
|
|
while (hue > 360)
|
2024-09-22 11:05:41 +08:00
|
|
|
|
hue -= 360;
|
2025-04-24 20:56:44 +08:00
|
|
|
|
while (hue < 0)
|
2024-09-22 11:05:41 +08:00
|
|
|
|
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值"),
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
2025-02-10 20:53:40 +08:00
|
|
|
|
|
2024-09-22 11:05:41 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 将 Color 对象转换为 HSB(色相、饱和度、亮度)颜色空间。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="color"></param>
|
|
|
|
|
|
/// <returns></returns>
|
2025-04-24 20:56:44 +08:00
|
|
|
|
public static Controls.Hsb ToHsb(this Color color)
|
2024-09-22 11:05:41 +08:00
|
|
|
|
{
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
2025-04-24 20:56:44 +08:00
|
|
|
|
if (max.IsCloseTo(min))
|
2024-09-22 11:05:41 +08:00
|
|
|
|
{
|
|
|
|
|
|
hue = 0; // 无色,未定义
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2025-04-24 20:56:44 +08:00
|
|
|
|
if (max.IsCloseTo(r))
|
2024-09-22 11:05:41 +08:00
|
|
|
|
{
|
|
|
|
|
|
hue = (g - b) / delta + (g < b ? 6 : 0);
|
|
|
|
|
|
}
|
2025-04-24 20:56:44 +08:00
|
|
|
|
else if (max.IsCloseTo(g))
|
2024-09-22 11:05:41 +08:00
|
|
|
|
{
|
|
|
|
|
|
hue = (b - r) / delta + 2;
|
|
|
|
|
|
}
|
2025-04-24 20:56:44 +08:00
|
|
|
|
else if (max.IsCloseTo(b))
|
2024-09-22 11:05:41 +08:00
|
|
|
|
{
|
|
|
|
|
|
hue = (r - g) / delta + 4;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
hue *= 60;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-02-10 20:53:40 +08:00
|
|
|
|
return new Hsb(hue, saturation, brightness, a);
|
2024-09-22 11:05:41 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|