SvgTransformConverter.cs 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using System.Drawing;
  5. using System.Drawing.Drawing2D;
  6. using System.ComponentModel;
  7. using System.Text.RegularExpressions;
  8. using System.Globalization;
  9. using System.Linq;
  10. #pragma warning disable
  11. namespace Svg.Transforms
  12. {
  13. public class SvgTransformConverter : TypeConverter
  14. {
  15. private static IEnumerable<string> SplitTransforms(string transforms)
  16. {
  17. int transformEnd = 0;
  18. for (int i = 0; i < transforms.Length; i++)
  19. {
  20. if (transforms[i] == ')')
  21. {
  22. yield return transforms.Substring(transformEnd, i - transformEnd + 1).Trim();
  23. while (i < transforms.Length && !char.IsLetter(transforms[i])) i++;
  24. transformEnd = i;
  25. }
  26. }
  27. }
  28. /// <summary>
  29. /// Converts the given object to the type of this converter, using the specified context and culture information.
  30. /// </summary>
  31. /// <param name="context">An <see cref="T:System.ComponentModel.ITypeDescriptorContext"/> that provides a format context.</param>
  32. /// <param name="culture">The <see cref="T:System.Globalization.CultureInfo"/> to use as the current culture.</param>
  33. /// <param name="value">The <see cref="T:System.Object"/> to convert.</param>
  34. /// <returns>
  35. /// An <see cref="T:System.Object"/> that represents the converted value.
  36. /// </returns>
  37. /// <exception cref="T:System.NotSupportedException">The conversion cannot be performed. </exception>
  38. public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
  39. {
  40. if (value is string)
  41. {
  42. SvgTransformCollection transformList = new SvgTransformCollection();
  43. string[] parts;
  44. string contents;
  45. string transformName;
  46. foreach (string transform in SvgTransformConverter.SplitTransforms((string)value))
  47. {
  48. if (string.IsNullOrEmpty(transform))
  49. continue;
  50. parts = transform.Split('(', ')');
  51. transformName = parts[0].Trim();
  52. contents = parts[1].Trim();
  53. switch (transformName)
  54. {
  55. case "translate":
  56. string[] coords = contents.Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries);
  57. if (coords.Length == 0 || coords.Length > 2)
  58. {
  59. throw new FormatException("Translate transforms must be in the format 'translate(x [,y])'");
  60. }
  61. float x = float.Parse(coords[0].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture);
  62. if (coords.Length > 1)
  63. {
  64. float y = float.Parse(coords[1].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture);
  65. transformList.Add(new SvgTranslate(x, y));
  66. }
  67. else
  68. {
  69. transformList.Add(new SvgTranslate(x));
  70. }
  71. break;
  72. case "rotate":
  73. string[] args = contents.Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries);
  74. if (args.Length != 1 && args.Length != 3)
  75. {
  76. throw new FormatException("Rotate transforms must be in the format 'rotate(angle [cx cy ])'");
  77. }
  78. float angle = float.Parse(args[0], NumberStyles.Float, CultureInfo.InvariantCulture);
  79. if (args.Length == 1)
  80. {
  81. transformList.Add(new SvgRotate(angle));
  82. }
  83. else
  84. {
  85. float cx = float.Parse(args[1], NumberStyles.Float, CultureInfo.InvariantCulture);
  86. float cy = float.Parse(args[2], NumberStyles.Float, CultureInfo.InvariantCulture);
  87. transformList.Add(new SvgRotate(angle, cx, cy));
  88. }
  89. break;
  90. case "scale":
  91. string[] scales = contents.Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries);
  92. if (scales.Length == 0 || scales.Length > 2)
  93. {
  94. throw new FormatException("Scale transforms must be in the format 'scale(x [,y])'");
  95. }
  96. float sx = float.Parse(scales[0].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture);
  97. if (scales.Length > 1)
  98. {
  99. float sy = float.Parse(scales[1].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture);
  100. transformList.Add(new SvgScale(sx, sy));
  101. }
  102. else
  103. {
  104. transformList.Add(new SvgScale(sx));
  105. }
  106. break;
  107. case "matrix":
  108. string[] points = contents.Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries);
  109. if (points.Length != 6)
  110. {
  111. throw new FormatException("Matrix transforms must be in the format 'matrix(m11, m12, m21, m22, dx, dy)'");
  112. }
  113. List<float> mPoints = new List<float>();
  114. foreach (string point in points)
  115. {
  116. mPoints.Add(float.Parse(point.Trim(), NumberStyles.Float, CultureInfo.InvariantCulture));
  117. }
  118. transformList.Add(new SvgMatrix(mPoints));
  119. break;
  120. case "shear":
  121. string[] shears = contents.Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries);
  122. if (shears.Length == 0 || shears.Length > 2)
  123. {
  124. throw new FormatException("Shear transforms must be in the format 'shear(x [,y])'");
  125. }
  126. float hx = float.Parse(shears[0].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture);
  127. if (shears.Length > 1)
  128. {
  129. float hy = float.Parse(shears[1].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture);
  130. transformList.Add(new SvgShear(hx, hy));
  131. }
  132. else
  133. {
  134. transformList.Add(new SvgShear(hx));
  135. }
  136. break;
  137. case "skewX":
  138. float ax = float.Parse(contents, NumberStyles.Float, CultureInfo.InvariantCulture);
  139. transformList.Add(new SvgSkew(ax, 0));
  140. break;
  141. case "skewY":
  142. float ay = float.Parse(contents, NumberStyles.Float, CultureInfo.InvariantCulture);
  143. transformList.Add(new SvgSkew(0, ay));
  144. break;
  145. }
  146. }
  147. return transformList;
  148. }
  149. return base.ConvertFrom(context, culture, value);
  150. }
  151. public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
  152. {
  153. if (sourceType == typeof(string))
  154. {
  155. return true;
  156. }
  157. return base.CanConvertFrom(context, sourceType);
  158. }
  159. public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
  160. {
  161. if (destinationType == typeof(string))
  162. {
  163. return true;
  164. }
  165. return base.CanConvertTo(context, destinationType);
  166. }
  167. public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
  168. {
  169. if (destinationType == typeof(string))
  170. {
  171. var transforms = value as SvgTransformCollection;
  172. if (transforms != null)
  173. {
  174. return string.Join(" ", transforms.Select(t => t.WriteToString()).ToArray());
  175. }
  176. }
  177. return base.ConvertTo(context, culture, value, destinationType);
  178. }
  179. }
  180. }
  181. #pragma warning restore