ColorHelper.cs 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Drawing;
  4. using System.Linq;
  5. using System.Text;
  6. using System.Threading.Tasks;
  7. /// <summary>
  8. /// 颜色自动生成帮助类
  9. /// </summary>
  10. public static class ColorHelper
  11. {
  12. private static readonly Dictionary<string, Color> _colorCache = new Dictionary<string, Color>();//颜色缓存
  13. private static readonly Dictionary<string, string> _htmlColorCache = new Dictionary<string, string>();//颜色缓存
  14. /// <summary>
  15. /// 判断color是否为HtmlColor(HtmlColor格式如#A1B2C3)
  16. /// </summary>
  17. /// <param name="color"></param>
  18. /// <returns></returns>
  19. public static bool IsHtmlColor(string color)
  20. {
  21. if (color == null)
  22. color = "#CC3333";
  23. if (!color.StartsWith("#")) return false;
  24. if (color.Length != 7) return false;
  25. string r = color.Substring(1, 2);
  26. string g = color.Substring(3, 2);
  27. string b = color.Substring(5, 2);
  28. bool r1 = byte.TryParse(r, System.Globalization.NumberStyles.HexNumber, null, out _);
  29. bool r2 = byte.TryParse(g, System.Globalization.NumberStyles.HexNumber, null, out _);
  30. bool r3 = byte.TryParse(b, System.Globalization.NumberStyles.HexNumber, null, out _);
  31. return r1 & r2 & r3;
  32. }
  33. /// <summary>
  34. /// 根据key得到一种易识别的颜色,相同的key会得到相同的颜色(若要使多个key得到的颜色具有高对比度,请先调用GenerateColor)
  35. /// </summary>
  36. /// <param name="key"></param>
  37. /// <returns></returns>
  38. public static Color GetColor(string key)
  39. {
  40. if (key == null) key = "";
  41. if (_colorCache.ContainsKey(key))
  42. return _colorCache[key];
  43. Random random = new Random(key.GetHashCode());
  44. var H = random.Next(0, 360);//色调
  45. var S = random.NextDouble();//饱和度
  46. var L = random.NextDouble();//亮度
  47. S = 0.7 + S * 0.2; // [0.7 - 0.9] 排除过灰颜色
  48. L = 0.4 + L * 0.4; // [0.4 - 0.8] 排除过亮过暗色
  49. byte r, g, b;
  50. if (S == 0)
  51. {
  52. r = g = b = (byte)(L * 255);
  53. }
  54. else
  55. {
  56. double v1, v2;
  57. double hue = H / 360d;
  58. v2 = (L < 0.5) ? (L * (1 + S)) : ((L + S) - (L * S));
  59. v1 = 2 * L - v2;
  60. r = (byte)(255 * HueToRGB(v1, v2, hue + (1.0f / 3)));
  61. g = (byte)(255 * HueToRGB(v1, v2, hue));
  62. b = (byte)(255 * HueToRGB(v1, v2, hue - (1.0f / 3)));
  63. }
  64. var color = Color.FromArgb(r, g, b);
  65. var rgbhtml = ColorTranslator.ToHtml(color);
  66. if (!_colorCache.ContainsKey(key))
  67. _colorCache.Add(key, color);
  68. if (!_htmlColorCache.ContainsKey(key))
  69. _htmlColorCache.Add(key, rgbhtml);
  70. return color;
  71. }
  72. /// <summary>
  73. /// 根据key得到一种易识别的颜色,相同的key会得到相同的颜色(若要使多个key得到的颜色具有高对比度,请先调用GenerateColor)
  74. /// </summary>
  75. /// <param name="key"></param>
  76. /// <returns></returns>
  77. public static string GetHtmlColor(string key)
  78. {
  79. if (key == null) key = "";
  80. if (_htmlColorCache.ContainsKey(key))
  81. return _htmlColorCache[key];
  82. string rgbhtml = ColorTranslator.ToHtml(GetColor(key));
  83. return rgbhtml;
  84. }
  85. /// <summary>
  86. /// 提前生成多个易识别且不相近的颜色,生成后通过GetColor或CetHtmlColor获取
  87. /// </summary>
  88. /// <param name="keys">所有颜色对应的key,个数超过360时效果不佳</param>
  89. /// <returns></returns>
  90. public static void GenerateColor(IEnumerable<string> keys)
  91. {
  92. _colorCache.Clear();
  93. _htmlColorCache.Clear();
  94. keys = keys.Distinct();
  95. int idx = 0;
  96. List<(int H, double S, double L)> list = new List<(int H, double S, double L)>();
  97. int count = keys.Count();
  98. int value = 360 / count;
  99. if (value == 0) value = 1;
  100. foreach (var key in keys)
  101. {
  102. Random random = new Random(key.GetHashCode());
  103. int H = random.Next(idx * value, (idx + 1) * value);//色调
  104. H %= 360;
  105. double S = random.NextDouble();//饱和度
  106. double L = random.NextDouble();//亮度
  107. S = 0.7 + S * 0.2; // [0.7 - 0.9] 排除过灰颜色
  108. L = 0.4 + L * 0.4; // [0.4 - 0.8] 排除过亮过暗色
  109. byte r, g, b;
  110. if (S == 0)
  111. {
  112. r = g = b = (byte)(L * 255);
  113. }
  114. else
  115. {
  116. double v1, v2;
  117. double hue = H / 360d;
  118. v2 = (L < 0.5) ? (L * (1 + S)) : ((L + S) - (L * S));
  119. v1 = 2 * L - v2;
  120. r = (byte)(255 * HueToRGB(v1, v2, hue + (1.0f / 3)));
  121. g = (byte)(255 * HueToRGB(v1, v2, hue));
  122. b = (byte)(255 * HueToRGB(v1, v2, hue - (1.0f / 3)));
  123. }
  124. list.Add((H, S, L));
  125. var color = Color.FromArgb(r, g, b);
  126. var rgbhtml = ColorTranslator.ToHtml(color);
  127. if (!_colorCache.ContainsKey(key))
  128. _colorCache.Add(key, color);
  129. else
  130. _colorCache[key] = color;
  131. if (!_htmlColorCache.ContainsKey(key))
  132. _htmlColorCache.Add(key, rgbhtml);
  133. else
  134. _htmlColorCache[key] = rgbhtml;
  135. idx++;
  136. }
  137. }
  138. private static double HueToRGB(double v1, double v2, double vH)
  139. {
  140. if (vH < 0)
  141. vH += 1;
  142. if (vH > 1)
  143. vH -= 1;
  144. if ((6 * vH) < 1)
  145. return (v1 + (v2 - v1) * 6 * vH);
  146. if ((2 * vH) < 1)
  147. return v2;
  148. if ((3 * vH) < 2)
  149. return (v1 + (v2 - v1) * ((2.0f / 3) - vH) * 6);
  150. return v1;
  151. }
  152. }