ColorHelper.cs 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. using System;
  2. using System.Drawing;
  3. using System.Text;
  4. namespace Optimizer
  5. {
  6. public static class ColorHelper
  7. {
  8. public static void HSVFromRGB(Color color, out double hue, out double saturation, out double value)
  9. {
  10. double min, max, delta, r, g, b;
  11. r = (double)color.R / 255d;
  12. g = (double)color.G / 255d;
  13. b = (double)color.B / 255d;
  14. min = Math.Min(r, Math.Min(g, b));
  15. max = Math.Max(r, Math.Max(g, b));
  16. value = max;
  17. delta = max - min;
  18. if (max != 0)
  19. saturation = delta / max;
  20. else
  21. {
  22. saturation = 0;
  23. hue = -1;
  24. return;
  25. }
  26. if (r == max)
  27. hue = (g - b) / delta;
  28. else if (g == max)
  29. hue = 2 + (b - r) / delta;
  30. else
  31. hue = 4 + (r - g) / delta;
  32. hue *= 60;
  33. if (hue < 0)
  34. hue += 360;
  35. }
  36. public static Color ColorFromHSV(double hue, double saturation, double value)
  37. {
  38. try
  39. {
  40. int i;
  41. double f, p, q, t, r, g, b;
  42. if (saturation == 0)
  43. {
  44. r = g = b = value;
  45. return Color.FromArgb((int)(255 * r), (int)(255 * g), (int)(255 * b));
  46. }
  47. hue /= 60;
  48. i = (int)Math.Floor(hue);
  49. f = hue - i;
  50. p = value * (1 - saturation);
  51. q = value * (1 - saturation * f);
  52. t = value * (1 - saturation * (1 - f));
  53. switch (i)
  54. {
  55. case 0:
  56. r = value;
  57. g = t;
  58. b = p;
  59. break;
  60. case 1:
  61. r = q;
  62. g = value;
  63. b = p;
  64. break;
  65. case 2:
  66. r = p;
  67. g = value;
  68. b = t;
  69. break;
  70. case 3:
  71. r = p;
  72. g = q;
  73. b = value;
  74. break;
  75. case 4:
  76. r = t;
  77. g = p;
  78. b = value;
  79. break;
  80. default:
  81. r = value;
  82. g = p;
  83. b = q;
  84. break;
  85. }
  86. return Color.FromArgb((int)(255 * r), (int)(255 * g), (int)(255 * b));
  87. }
  88. catch
  89. {
  90. }
  91. return Color.Empty;
  92. }
  93. public static Color ChangeColorBrightness(Color color, double darkenAmount)
  94. {
  95. HslColor hslColor = new HslColor(color);
  96. hslColor.L *= darkenAmount;
  97. return hslColor;
  98. }
  99. }
  100. [Serializable]
  101. public struct HslColor
  102. {
  103. #region Constants
  104. public static readonly HslColor Empty;
  105. #endregion
  106. #region Fields
  107. private double hue;
  108. private double saturation;
  109. private double luminance;
  110. private int alpha;
  111. private bool isEmpty;
  112. #endregion
  113. #region Static Constructors
  114. static HslColor()
  115. {
  116. Empty = new HslColor
  117. {
  118. IsEmpty = true
  119. };
  120. }
  121. #endregion
  122. #region Public Constructors
  123. public HslColor(double h, double s, double l)
  124. : this(255, h, s, l) { }
  125. public HslColor(int a, double h, double s, double l)
  126. {
  127. this.alpha = a;
  128. this.hue = Math.Min(359, h);
  129. this.saturation = Math.Min(1, s);
  130. this.luminance = Math.Min(1, l);
  131. isEmpty = false;
  132. }
  133. public HslColor(Color color)
  134. {
  135. this.alpha = color.A;
  136. this.hue = color.GetHue();
  137. this.saturation = color.GetSaturation();
  138. this.luminance = color.GetBrightness();
  139. isEmpty = false;
  140. }
  141. #endregion
  142. #region Operators
  143. public static bool operator ==(HslColor left, HslColor right)
  144. {
  145. return (((left.A == right.A) && (left.H == right.H)) && ((left.S == right.S) && (left.L == right.L)));
  146. }
  147. public static bool operator !=(HslColor left, HslColor right)
  148. {
  149. return !(left == right);
  150. }
  151. public static implicit operator HslColor(Color color)
  152. {
  153. return new HslColor(color);
  154. }
  155. public static implicit operator Color(HslColor color)
  156. {
  157. return color.ToRgbColor();
  158. }
  159. #endregion
  160. #region Overridden Methods
  161. public override bool Equals(object obj)
  162. {
  163. if (obj is HslColor color)
  164. {
  165. if (((this.A == color.A) && (this.H == color.H)) && ((this.S == color.S) && (this.L == color.L)))
  166. {
  167. return true;
  168. }
  169. }
  170. return false;
  171. }
  172. public override int GetHashCode()
  173. {
  174. return (((this.alpha.GetHashCode() ^ this.hue.GetHashCode()) ^ this.saturation.GetHashCode()) ^ this.luminance.GetHashCode());
  175. }
  176. public override string ToString()
  177. {
  178. StringBuilder builder;
  179. builder = new StringBuilder();
  180. builder.Append(this.GetType().Name);
  181. builder.Append(" [");
  182. builder.Append("H=");
  183. builder.Append(this.H);
  184. builder.Append(", S=");
  185. builder.Append(this.S);
  186. builder.Append(", L=");
  187. builder.Append(this.L);
  188. builder.Append("]");
  189. return builder.ToString();
  190. }
  191. #endregion
  192. #region Public Members
  193. public double H
  194. {
  195. get { return this.hue; }
  196. set
  197. {
  198. this.hue = value;
  199. this.hue = (this.hue > 359.0) ? 0 : ((this.hue < 0.0) ? 359 : this.hue);
  200. }
  201. }
  202. public double S
  203. {
  204. get { return this.saturation; }
  205. set { this.saturation = Math.Min(1, Math.Max(0, value)); }
  206. }
  207. public double L
  208. {
  209. get { return this.luminance; }
  210. set { this.luminance = Math.Min(1, Math.Max(0, value)); }
  211. }
  212. public int A
  213. {
  214. get { return this.alpha; }
  215. set { this.alpha = Math.Min(0, Math.Max(255, value)); }
  216. }
  217. public bool IsEmpty
  218. {
  219. get { return isEmpty; }
  220. internal set { isEmpty = value; }
  221. }
  222. public Color ToRgbColor()
  223. {
  224. return this.ToRgbColor(this.A);
  225. }
  226. public Color ToRgbColor(int alpha)
  227. {
  228. double q;
  229. if (this.L < 0.5)
  230. {
  231. q = this.L * (1 + this.S);
  232. }
  233. else
  234. {
  235. q = this.L + this.S - (this.L * this.S);
  236. }
  237. double p = 2 * this.L - q;
  238. double hk = this.H / 360;
  239. // r,g,b colors
  240. double[] tc = new[]
  241. {
  242. hk + (1d / 3d), hk, hk - (1d / 3d)
  243. };
  244. double[] colors = new[]
  245. {
  246. 0.0, 0.0, 0.0
  247. };
  248. for (int color = 0; color < colors.Length; color++)
  249. {
  250. if (tc[color] < 0)
  251. {
  252. tc[color] += 1;
  253. }
  254. if (tc[color] > 1)
  255. {
  256. tc[color] -= 1;
  257. }
  258. if (tc[color] < (1d / 6d))
  259. {
  260. colors[color] = p + ((q - p) * 6 * tc[color]);
  261. }
  262. else if (tc[color] >= (1d / 6d) && tc[color] < (1d / 2d))
  263. {
  264. colors[color] = q;
  265. }
  266. else if (tc[color] >= (1d / 2d) && tc[color] < (2d / 3d))
  267. {
  268. colors[color] = p + ((q - p) * 6 * (2d / 3d - tc[color]));
  269. }
  270. else
  271. {
  272. colors[color] = p;
  273. }
  274. colors[color] *= 255;
  275. }
  276. return Color.FromArgb(alpha, (int)colors[0], (int)colors[1], (int)colors[2]);
  277. }
  278. #endregion
  279. }
  280. }