ColorHelper.cs 8.1 KB

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