using System;
using System.Windows.Media;
namespace TeamAAS.Theme
{
///
/// 颜色派生工具:HSL 空间的明度/饱和度调整与对比度计算。
/// 供 ThemeOverlay 做主色派生(hover 变体、暗色提亮、文字对比色),保证专业配色的可读性。
///
internal static class ColorUtility
{
/// 降低明度(0~1,如 0.12 = 深 12%),用于 hover/pressed 变体。
public static Color Darken(Color c, double amount)
{
RgbToHsl(c, out double h, out double s, out double l);
l = Clamp(l - amount);
return HslToRgb(h, s, l, c.A);
}
/// 提高明度(0~1),用于暗色主题下提亮主色保证对比度。
public static Color Lighten(Color c, double amount)
{
RgbToHsl(c, out double h, out double s, out double l);
l = Clamp(l + amount);
return HslToRgb(h, s, l, c.A);
}
/// WCAG 相对亮度(0~1),用于对比度判定。
public static double RelativeLuminance(Color c)
{
double R = Channel(c.R);
double G = Channel(c.G);
double B = Channel(c.B);
return 0.2126 * R + 0.7152 * G + 0.0722 * B;
}
///
/// 按背景亮度返回可读的文字色(WCAG AA):亮背景配深字 #212121,暗背景配白字。
/// 用于主色背景上的文字(ReverseTextColor),避免"浅色主色 + 白字"看不清。
///
public static Color ContrastText(Color background)
{
return RelativeLuminance(background) > 0.55
? Color.FromRgb(0x21, 0x21, 0x21)
: Colors.White;
}
private static double Channel(byte v)
{
double d = v / 255.0;
return d <= 0.03928 ? d / 12.92 : Math.Pow((d + 0.055) / 1.055, 2.4);
}
private static void RgbToHsl(Color c, out double h, out double s, out double l)
{
double r = c.R / 255.0;
double g = c.G / 255.0;
double b = c.B / 255.0;
double max = Math.Max(r, Math.Max(g, b));
double min = Math.Min(r, Math.Min(g, b));
l = (max + min) / 2.0;
if (max - min < 1e-9)
{
h = 0; s = 0;
return;
}
double d = max - min;
s = l > 0.5 ? d / (2.0 - max - min) : d / (max + min);
if (max == r) h = (g - b) / d + (g < b ? 6.0 : 0.0);
else if (max == g) h = (b - r) / d + 2.0;
else h = (r - g) / d + 4.0;
h /= 6.0;
}
private static Color HslToRgb(double h, double s, double l, byte alpha)
{
if (s < 1e-9)
{
byte gray = (byte)Math.Round(Clamp(l) * 255.0);
return Color.FromArgb(alpha, gray, gray, gray);
}
double q = l < 0.5 ? l * (1.0 + s) : l + s - l * s;
double p = 2.0 * l - q;
double r = HueToRgb(p, q, h + 1.0 / 3.0);
double g = HueToRgb(p, q, h);
double b = HueToRgb(p, q, h - 1.0 / 3.0);
return Color.FromArgb(
alpha,
(byte)Math.Round(r * 255.0),
(byte)Math.Round(g * 255.0),
(byte)Math.Round(b * 255.0));
}
private static double HueToRgb(double p, double q, double t)
{
if (t < 0.0) t += 1.0;
if (t > 1.0) t -= 1.0;
if (t < 1.0 / 6.0) return p + (q - p) * 6.0 * t;
if (t < 1.0 / 2.0) return q;
if (t < 2.0 / 3.0) return p + (q - p) * (2.0 / 3.0 - t) * 6.0;
return p;
}
private static double Clamp(double v)
{
return v < 0.0 ? 0.0 : (v > 1.0 ? 1.0 : v);
}
}
}