SvgPatternServer.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using System.Drawing.Drawing2D;
  5. using System.Drawing;
  6. using System.ComponentModel;
  7. using Svg.Transforms;
  8. using System.Linq;
  9. #pragma warning disable
  10. namespace Svg
  11. {
  12. /// <summary>
  13. /// A pattern is used to fill or stroke an object using a pre-defined graphic object which can be replicated ("tiled") at fixed intervals in x and y to cover the areas to be painted.
  14. /// </summary>
  15. [SvgElement("pattern")]
  16. public sealed class SvgPatternServer : SvgPaintServer, ISvgViewPort, ISvgSupportsCoordinateUnits
  17. {
  18. private SvgUnit _width;
  19. private SvgUnit _height;
  20. private SvgUnit _x;
  21. private SvgUnit _y;
  22. private SvgPaintServer _inheritGradient;
  23. private SvgViewBox _viewBox;
  24. private SvgCoordinateUnits _patternUnits = SvgCoordinateUnits.Inherit;
  25. private SvgCoordinateUnits _patternContentUnits = SvgCoordinateUnits.Inherit;
  26. [SvgAttribute("overflow")]
  27. public SvgOverflow Overflow
  28. {
  29. get { return this.Attributes.GetAttribute<SvgOverflow>("overflow"); }
  30. set { this.Attributes["overflow"] = value; }
  31. }
  32. /// <summary>
  33. /// Specifies a supplemental transformation which is applied on top of any
  34. /// transformations necessary to create a new pattern coordinate system.
  35. /// </summary>
  36. [SvgAttribute("viewBox")]
  37. public SvgViewBox ViewBox
  38. {
  39. get { return this._viewBox; }
  40. set { this._viewBox = value; }
  41. }
  42. /// <summary>
  43. /// Gets or sets the aspect of the viewport.
  44. /// </summary>
  45. /// <value></value>
  46. [SvgAttribute("preserveAspectRatio")]
  47. public SvgAspectRatio AspectRatio
  48. {
  49. get;
  50. set;
  51. }
  52. /// <summary>
  53. /// Gets or sets the width of the pattern.
  54. /// </summary>
  55. [SvgAttribute("width")]
  56. public SvgUnit Width
  57. {
  58. get { return this._width; }
  59. set { this._width = value; }
  60. }
  61. /// <summary>
  62. /// Gets or sets the width of the pattern.
  63. /// </summary>
  64. [SvgAttribute("patternUnits")]
  65. public SvgCoordinateUnits PatternUnits
  66. {
  67. get { return this._patternUnits; }
  68. set { this._patternUnits = value; }
  69. }
  70. /// <summary>
  71. /// Gets or sets the width of the pattern.
  72. /// </summary>
  73. [SvgAttribute("patternContentUnits")]
  74. public SvgCoordinateUnits PatternContentUnits
  75. {
  76. get { return this._patternContentUnits; }
  77. set { this._patternContentUnits = value; }
  78. }
  79. /// <summary>
  80. /// Gets or sets the height of the pattern.
  81. /// </summary>
  82. [SvgAttribute("height")]
  83. public SvgUnit Height
  84. {
  85. get { return this._height; }
  86. set { this._height = value; }
  87. }
  88. /// <summary>
  89. /// Gets or sets the X-axis location of the pattern.
  90. /// </summary>
  91. [SvgAttribute("x")]
  92. public SvgUnit X
  93. {
  94. get { return this._x; }
  95. set { this._x = value; }
  96. }
  97. /// <summary>
  98. /// Gets or sets the Y-axis location of the pattern.
  99. /// </summary>
  100. [SvgAttribute("y")]
  101. public SvgUnit Y
  102. {
  103. get { return this._y; }
  104. set { this._y = value; }
  105. }
  106. /// <summary>
  107. /// Gets or sets another gradient fill from which to inherit the stops from.
  108. /// </summary>
  109. [SvgAttribute("href", SvgAttributeAttribute.XLinkNamespace)]
  110. public SvgPaintServer InheritGradient
  111. {
  112. get { return this._inheritGradient; }
  113. set
  114. {
  115. this._inheritGradient = value;
  116. }
  117. }
  118. [SvgAttribute("patternTransform")]
  119. public SvgTransformCollection PatternTransform
  120. {
  121. get { return (this.Attributes.GetAttribute<SvgTransformCollection>("patternTransform")); }
  122. set { this.Attributes["patternTransform"] = value; }
  123. }
  124. private Matrix EffectivePatternTransform
  125. {
  126. get
  127. {
  128. var transform = new Matrix();
  129. if (PatternTransform != null)
  130. {
  131. transform.Multiply(PatternTransform.GetMatrix());
  132. }
  133. return transform;
  134. }
  135. }
  136. /// <summary>
  137. /// Initializes a new instance of the <see cref="SvgPatternServer"/> class.
  138. /// </summary>
  139. public SvgPatternServer()
  140. {
  141. this._x = SvgUnit.None;
  142. this._y = SvgUnit.None;
  143. this._width = SvgUnit.None;
  144. this._height = SvgUnit.None;
  145. }
  146. private SvgUnit NormalizeUnit(SvgUnit orig)
  147. {
  148. return (orig.Type == SvgUnitType.Percentage && this.PatternUnits == SvgCoordinateUnits.ObjectBoundingBox ?
  149. new SvgUnit(SvgUnitType.User, orig.Value / 100) :
  150. orig);
  151. }
  152. /// <summary>
  153. /// Gets a <see cref="Brush"/> representing the current paint server.
  154. /// </summary>
  155. /// <param name="renderingElement">The owner <see cref="SvgVisualElement"/>.</param>
  156. /// <param name="opacity">The opacity of the brush.</param>
  157. public override Brush GetBrush(SvgVisualElement renderingElement, ISvgRenderer renderer, float opacity, bool forStroke = false)
  158. {
  159. var chain = new List<SvgPatternServer>();
  160. var curr = this;
  161. while (curr != null)
  162. {
  163. chain.Add(curr);
  164. curr = SvgDeferredPaintServer.TryGet<SvgPatternServer>(curr._inheritGradient, renderingElement);
  165. }
  166. var childElem = chain.Where((p) => p.Children != null && p.Children.Count > 0).FirstOrDefault();
  167. if (childElem == null) return null;
  168. var widthElem = chain.Where((p) => p.Width != null && p.Width != SvgUnit.None).FirstOrDefault();
  169. var heightElem = chain.Where((p) => p.Height != null && p.Height != SvgUnit.None).FirstOrDefault();
  170. if (widthElem == null && heightElem == null) return null;
  171. var viewBoxElem = chain.Where((p) => p.ViewBox != null && p.ViewBox != SvgViewBox.Empty).FirstOrDefault();
  172. var viewBox = viewBoxElem == null ? SvgViewBox.Empty : viewBoxElem.ViewBox;
  173. var xElem = chain.Where((p) => p.X != null && p.X != SvgUnit.None).FirstOrDefault();
  174. var yElem = chain.Where((p) => p.Y != null && p.Y != SvgUnit.None).FirstOrDefault();
  175. var xUnit = xElem == null ? SvgUnit.Empty : xElem.X;
  176. var yUnit = yElem == null ? SvgUnit.Empty : yElem.Y;
  177. var patternUnitElem = chain.Where((p) => p.PatternUnits != SvgCoordinateUnits.Inherit).FirstOrDefault();
  178. var patternUnits = (patternUnitElem == null ? SvgCoordinateUnits.ObjectBoundingBox : patternUnitElem.PatternUnits);
  179. var patternContentUnitElem = chain.Where((p) => p.PatternContentUnits != SvgCoordinateUnits.Inherit).FirstOrDefault();
  180. var patternContentUnits = (patternContentUnitElem == null ? SvgCoordinateUnits.UserSpaceOnUse : patternContentUnitElem.PatternContentUnits);
  181. try
  182. {
  183. if (patternUnits == SvgCoordinateUnits.ObjectBoundingBox) renderer.SetBoundable(renderingElement);
  184. using (var patternMatrix = new Matrix())
  185. {
  186. var bounds = renderer.GetBoundable().Bounds;
  187. var xScale = (patternUnits == SvgCoordinateUnits.ObjectBoundingBox ? bounds.Width : 1);
  188. var yScale = (patternUnits == SvgCoordinateUnits.ObjectBoundingBox ? bounds.Height : 1);
  189. float x = xScale * NormalizeUnit(xUnit).ToDeviceValue(renderer, UnitRenderingType.Horizontal, this);
  190. float y = yScale * NormalizeUnit(yUnit).ToDeviceValue(renderer, UnitRenderingType.Vertical, this);
  191. float width = xScale * NormalizeUnit(widthElem.Width).ToDeviceValue(renderer, UnitRenderingType.Horizontal, this);
  192. float height = yScale * NormalizeUnit(heightElem.Height).ToDeviceValue(renderer, UnitRenderingType.Vertical, this);
  193. // Apply a scale if needed
  194. patternMatrix.Scale((patternContentUnits == SvgCoordinateUnits.ObjectBoundingBox ? bounds.Width : 1) *
  195. (viewBox.Width > 0 ? width / viewBox.Width : 1),
  196. (patternContentUnits == SvgCoordinateUnits.ObjectBoundingBox ? bounds.Height : 1) *
  197. (viewBox.Height > 0 ? height / viewBox.Height : 1), MatrixOrder.Prepend);
  198. Bitmap image = new Bitmap((int)width, (int)height);
  199. using (var iRenderer = SvgRenderer.FromImage(image))
  200. {
  201. iRenderer.SetBoundable((_patternContentUnits == SvgCoordinateUnits.ObjectBoundingBox) ? new GenericBoundable(0, 0, width, height) : renderer.GetBoundable());
  202. iRenderer.Transform = patternMatrix;
  203. iRenderer.SmoothingMode = SmoothingMode.AntiAlias;
  204. iRenderer.SetClip(new Region(new RectangleF(0, 0,
  205. viewBox.Width > 0 ? viewBox.Width : width,
  206. viewBox.Height > 0 ? viewBox.Height : height)));
  207. foreach (SvgElement child in childElem.Children)
  208. {
  209. child.RenderElement(iRenderer);
  210. }
  211. }
  212. TextureBrush textureBrush = new TextureBrush(image);
  213. var brushTransform = EffectivePatternTransform.Clone();
  214. brushTransform.Translate(x, y, MatrixOrder.Append);
  215. textureBrush.Transform = brushTransform;
  216. return textureBrush;
  217. }
  218. }
  219. finally
  220. {
  221. if (this.PatternUnits == SvgCoordinateUnits.ObjectBoundingBox) renderer.PopBoundable();
  222. }
  223. }
  224. public override SvgElement DeepCopy()
  225. {
  226. return DeepCopy<SvgPatternServer>();
  227. }
  228. public override SvgElement DeepCopy<T>()
  229. {
  230. var newObj = base.DeepCopy<T>() as SvgPatternServer;
  231. newObj.Overflow = this.Overflow;
  232. newObj.ViewBox = this.ViewBox;
  233. newObj.AspectRatio = this.AspectRatio;
  234. newObj.X = this.X;
  235. newObj.Y = this.Y;
  236. newObj.Width = this.Width;
  237. newObj.Height = this.Height;
  238. return newObj;
  239. }
  240. public SvgCoordinateUnits GetUnits()
  241. {
  242. return _patternUnits;
  243. }
  244. }
  245. }
  246. #pragma warning restore