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