SvgColourConverter.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Drawing;
  4. using System.Globalization;
  5. using System.Linq;
  6. using System.Text;
  7. using System.Threading;
  8. #pragma warning disable
  9. namespace Svg
  10. {
  11. /// <summary>
  12. /// Converts string representations of colours into <see cref="Color"/> objects.
  13. /// </summary>
  14. public class SvgColourConverter : ColorConverter
  15. {
  16. /// <summary>
  17. /// Converts the given object to the converter's native type.
  18. /// </summary>
  19. /// <param name="context">A <see cref="T:System.ComponentModel.TypeDescriptor"/> that provides a format context. You can use this object to get additional information about the environment from which this converter is being invoked.</param>
  20. /// <param name="culture">A <see cref="T:System.Globalization.CultureInfo"/> that specifies the culture to represent the color.</param>
  21. /// <param name="value">The object to convert.</param>
  22. /// <returns>
  23. /// An <see cref="T:System.Object"/> representing the converted value.
  24. /// </returns>
  25. /// <exception cref="T:System.ArgumentException">The conversion cannot be performed.</exception>
  26. /// <PermissionSet>
  27. /// <IPermission class="System.Security.Permissions.FileIOPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Unrestricted="true"/>
  28. /// </PermissionSet>
  29. public override object ConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
  30. {
  31. string colour = value as string;
  32. if (colour != null)
  33. {
  34. var oldCulture = Thread.CurrentThread.CurrentCulture;
  35. try {
  36. Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.InvariantCulture;
  37. colour = colour.Trim();
  38. if (colour.StartsWith("rgb"))
  39. {
  40. try
  41. {
  42. int start = colour.IndexOf("(") + 1;
  43. //get the values from the RGB string
  44. string[] values = colour.Substring(start, colour.IndexOf(")") - start).Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries);
  45. //determine the alpha value if this is an RGBA (it will be the 4th value if there is one)
  46. int alphaValue = 255;
  47. if (values.Length > 3)
  48. {
  49. //the alpha portion of the rgba is not an int 0-255 it is a decimal between 0 and 1
  50. //so we have to determine the corosponding byte value
  51. var alphastring = values[3];
  52. if (alphastring.StartsWith("."))
  53. {
  54. alphastring = "0" + alphastring;
  55. }
  56. var alphaDecimal = decimal.Parse(alphastring);
  57. if (alphaDecimal <= 1)
  58. {
  59. alphaValue = (int)Math.Round(alphaDecimal * 255);
  60. }
  61. else
  62. {
  63. alphaValue = (int)Math.Round(alphaDecimal);
  64. }
  65. }
  66. Color colorpart;
  67. if (values[0].Trim().EndsWith("%"))
  68. {
  69. colorpart = System.Drawing.Color.FromArgb(alphaValue, (int)Math.Round(255 * float.Parse(values[0].Trim().TrimEnd('%')) / 100f),
  70. (int)Math.Round(255 * float.Parse(values[1].Trim().TrimEnd('%')) / 100f),
  71. (int)Math.Round(255 * float.Parse(values[2].Trim().TrimEnd('%')) / 100f));
  72. }
  73. else
  74. {
  75. colorpart = System.Drawing.Color.FromArgb(alphaValue, int.Parse(values[0]), int.Parse(values[1]), int.Parse(values[2]));
  76. }
  77. return colorpart;
  78. }
  79. catch
  80. {
  81. throw new SvgException("Colour is in an invalid format: '" + colour + "'");
  82. }
  83. }
  84. // HSL support
  85. else if (colour.StartsWith("hsl")) {
  86. try
  87. {
  88. int start = colour.IndexOf("(") + 1;
  89. //get the values from the RGB string
  90. string[] values = colour.Substring(start, colour.IndexOf(")") - start).Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries);
  91. if (values[1].EndsWith("%"))
  92. {
  93. values[1] = values[1].TrimEnd('%');
  94. }
  95. if (values[2].EndsWith("%"))
  96. {
  97. values[2] = values[2].TrimEnd('%');
  98. }
  99. // Get the HSL values in a range from 0 to 1.
  100. double h = double.Parse(values[0]) / 360.0;
  101. double s = double.Parse(values[1]) / 100.0;
  102. double l = double.Parse(values[2]) / 100.0;
  103. // Convert the HSL color to an RGB color
  104. Color colorpart = Hsl2Rgb(h, s, l);
  105. return colorpart;
  106. }
  107. catch
  108. {
  109. throw new SvgException("Colour is in an invalid format: '" + colour + "'");
  110. }
  111. }
  112. else if (colour.StartsWith("#") && colour.Length == 4)
  113. {
  114. colour = string.Format(culture, "#{0}{0}{1}{1}{2}{2}", colour[1], colour[2], colour[3]);
  115. return base.ConvertFrom(context, culture, colour);
  116. }
  117. switch (colour.ToLowerInvariant())
  118. {
  119. case "activeborder": return SystemColors.ActiveBorder;
  120. case "activecaption": return SystemColors.ActiveCaption;
  121. case "appworkspace": return SystemColors.AppWorkspace;
  122. case "background": return SystemColors.Desktop;
  123. case "buttonface": return SystemColors.Control;
  124. case "buttonhighlight": return SystemColors.ControlLightLight;
  125. case "buttonshadow": return SystemColors.ControlDark;
  126. case "buttontext": return SystemColors.ControlText;
  127. case "captiontext": return SystemColors.ActiveCaptionText;
  128. case "graytext": return SystemColors.GrayText;
  129. case "highlight": return SystemColors.Highlight;
  130. case "highlighttext": return SystemColors.HighlightText;
  131. case "inactiveborder": return SystemColors.InactiveBorder;
  132. case "inactivecaption": return SystemColors.InactiveCaption;
  133. case "inactivecaptiontext": return SystemColors.InactiveCaptionText;
  134. case "infobackground": return SystemColors.Info;
  135. case "infotext": return SystemColors.InfoText;
  136. case "menu": return SystemColors.Menu;
  137. case "menutext": return SystemColors.MenuText;
  138. case "scrollbar": return SystemColors.ScrollBar;
  139. case "threeddarkshadow": return SystemColors.ControlDarkDark;
  140. case "threedface": return SystemColors.Control;
  141. case "threedhighlight": return SystemColors.ControlLight;
  142. case "threedlightshadow": return SystemColors.ControlLightLight;
  143. case "window": return SystemColors.Window;
  144. case "windowframe": return SystemColors.WindowFrame;
  145. case "windowtext": return SystemColors.WindowText;
  146. }
  147. }
  148. finally
  149. {
  150. // Make sure to set back the old culture even an error occurred.
  151. Thread.CurrentThread.CurrentCulture = oldCulture;
  152. }
  153. }
  154. return base.ConvertFrom(context, culture, value);
  155. }
  156. public override bool CanConvertFrom(System.ComponentModel.ITypeDescriptorContext context, Type sourceType)
  157. {
  158. if (sourceType == typeof(string))
  159. {
  160. return true;
  161. }
  162. return base.CanConvertFrom(context, sourceType);
  163. }
  164. public override bool CanConvertTo(System.ComponentModel.ITypeDescriptorContext context, Type destinationType)
  165. {
  166. if (destinationType == typeof(string))
  167. {
  168. return true;
  169. }
  170. return base.CanConvertTo(context, destinationType);
  171. }
  172. public override object ConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
  173. {
  174. if (destinationType == typeof(string))
  175. {
  176. var colour = (Color)value;
  177. return "#" + colour.R.ToString("X2", null) + colour.G.ToString("X2", null) + colour.B.ToString("X2", null);
  178. }
  179. return base.ConvertTo(context, culture, value, destinationType);
  180. }
  181. /// <summary>
  182. /// Converts HSL color (with HSL specified from 0 to 1) to RGB color.
  183. /// Taken from http://www.geekymonkey.com/Programming/CSharp/RGB2HSL_HSL2RGB.htm
  184. /// </summary>
  185. /// <param name="h"></param>
  186. /// <param name="sl"></param>
  187. /// <param name="l"></param>
  188. /// <returns></returns>
  189. private static Color Hsl2Rgb( double h, double sl, double l ) {
  190. double r = l; // default to gray
  191. double g = l;
  192. double b = l;
  193. double v = (l <= 0.5) ? (l * (1.0 + sl)) : (l + sl - l * sl);
  194. if (v > 0)
  195. {
  196. double m;
  197. double sv;
  198. int sextant;
  199. double fract, vsf, mid1, mid2;
  200. m = l + l - v;
  201. sv = (v - m ) / v;
  202. h *= 6.0;
  203. sextant = (int)h;
  204. fract = h - sextant;
  205. vsf = v * sv * fract;
  206. mid1 = m + vsf;
  207. mid2 = v - vsf;
  208. switch (sextant)
  209. {
  210. case 0:
  211. r = v;
  212. g = mid1;
  213. b = m;
  214. break;
  215. case 1:
  216. r = mid2;
  217. g = v;
  218. b = m;
  219. break;
  220. case 2:
  221. r = m;
  222. g = v;
  223. b = mid1;
  224. break;
  225. case 3:
  226. r = m;
  227. g = mid2;
  228. b = v;
  229. break;
  230. case 4:
  231. r = mid1;
  232. g = m;
  233. b = v;
  234. break;
  235. case 5:
  236. r = v;
  237. g = m;
  238. b = mid2;
  239. break;
  240. }
  241. }
  242. Color rgb = Color.FromArgb( (int)Math.Round( r * 255.0 ), (int)Math.Round( g * 255.0 ), (int)Math.Round( b * 255.0 ) );
  243. return rgb;
  244. }
  245. }
  246. }
  247. #pragma warning restore