2
0

ColorHelper.cs 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  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. { }
  126. public HslColor(int a, double h, double s, double l)
  127. {
  128. this.alpha = a;
  129. this.hue = Math.Min(359, h);
  130. this.saturation = Math.Min(1, s);
  131. this.luminance = Math.Min(1, l);
  132. isEmpty = false;
  133. }
  134. public HslColor(Color color)
  135. {
  136. this.alpha = color.A;
  137. this.hue = color.GetHue();
  138. this.saturation = color.GetSaturation();
  139. this.luminance = color.GetBrightness();
  140. isEmpty = false;
  141. }
  142. #endregion
  143. #region Operators
  144. public static bool operator ==(HslColor left, HslColor right)
  145. {
  146. return (((left.A == right.A) && (left.H == right.H)) && ((left.S == right.S) && (left.L == right.L)));
  147. }
  148. public static bool operator !=(HslColor left, HslColor right)
  149. {
  150. return !(left == right);
  151. }
  152. public static implicit operator HslColor(Color color)
  153. {
  154. return new HslColor(color);
  155. }
  156. public static implicit operator Color(HslColor color)
  157. {
  158. return color.ToRgbColor();
  159. }
  160. #endregion
  161. #region Overridden Methods
  162. public override bool Equals(object obj)
  163. {
  164. if (obj is HslColor color)
  165. {
  166. if (((this.A == color.A) && (this.H == color.H)) && ((this.S == color.S) && (this.L == color.L)))
  167. {
  168. return true;
  169. }
  170. }
  171. return false;
  172. }
  173. public override int GetHashCode()
  174. {
  175. return (((this.alpha.GetHashCode() ^ this.hue.GetHashCode()) ^ this.saturation.GetHashCode()) ^ this.luminance.GetHashCode());
  176. }
  177. public override string ToString()
  178. {
  179. StringBuilder builder;
  180. builder = new StringBuilder();
  181. builder.Append(this.GetType().Name);
  182. builder.Append(" [");
  183. builder.Append("H=");
  184. builder.Append(this.H);
  185. builder.Append(", S=");
  186. builder.Append(this.S);
  187. builder.Append(", L=");
  188. builder.Append(this.L);
  189. builder.Append("]");
  190. return builder.ToString();
  191. }
  192. #endregion
  193. #region Public Members
  194. public double H
  195. {
  196. get { return this.hue; }
  197. set
  198. {
  199. this.hue = value;
  200. this.hue = (this.hue > 359.0) ? 0 : ((this.hue < 0.0) ? 359 : this.hue);
  201. }
  202. }
  203. public double S
  204. {
  205. get { return this.saturation; }
  206. set { this.saturation = Math.Min(1, Math.Max(0, value)); }
  207. }
  208. public double L
  209. {
  210. get { return this.luminance; }
  211. set { this.luminance = Math.Min(1, Math.Max(0, value)); }
  212. }
  213. public int A
  214. {
  215. get { return this.alpha; }
  216. set { this.alpha = Math.Min(0, Math.Max(255, value)); }
  217. }
  218. public bool IsEmpty
  219. {
  220. get { return isEmpty; }
  221. internal set { isEmpty = value; }
  222. }
  223. public Color ToRgbColor()
  224. {
  225. return this.ToRgbColor(this.A);
  226. }
  227. public Color ToRgbColor(int alpha)
  228. {
  229. double q;
  230. if (this.L < 0.5)
  231. {
  232. q = this.L * (1 + this.S);
  233. }
  234. else
  235. {
  236. q = this.L + this.S - (this.L * this.S);
  237. }
  238. double p = 2 * this.L - q;
  239. double hk = this.H / 360;
  240. // r,g,b colors
  241. double[] tc = new[]
  242. {
  243. hk + (1d / 3d), hk, hk - (1d / 3d)
  244. };
  245. double[] colors = new[]
  246. {
  247. 0.0, 0.0, 0.0
  248. };
  249. for (int color = 0; color < colors.Length; color++)
  250. {
  251. if (tc[color] < 0)
  252. {
  253. tc[color] += 1;
  254. }
  255. if (tc[color] > 1)
  256. {
  257. tc[color] -= 1;
  258. }
  259. if (tc[color] < (1d / 6d))
  260. {
  261. colors[color] = p + ((q - p) * 6 * tc[color]);
  262. }
  263. else if (tc[color] >= (1d / 6d) && tc[color] < (1d / 2d))
  264. {
  265. colors[color] = q;
  266. }
  267. else if (tc[color] >= (1d / 2d) && tc[color] < (2d / 3d))
  268. {
  269. colors[color] = p + ((q - p) * 6 * (2d / 3d - tc[color]));
  270. }
  271. else
  272. {
  273. colors[color] = p;
  274. }
  275. colors[color] *= 255;
  276. }
  277. return Color.FromArgb(alpha, (int)colors[0], (int)colors[1], (int)colors[2]);
  278. }
  279. #endregion
  280. }
  281. }