[12762] | 1 | using System;
|
---|
| 2 | using System.Xml;
|
---|
| 3 | using System.Linq;
|
---|
| 4 | using System.Text;
|
---|
| 5 | using System.Collections.Generic;
|
---|
| 6 | using System.Text.RegularExpressions;
|
---|
| 7 |
|
---|
| 8 | using System.Windows;
|
---|
| 9 | using System.Windows.Media;
|
---|
| 10 | using System.Windows.Media.Imaging;
|
---|
| 11 |
|
---|
| 12 | using SharpVectors.Dom.Css;
|
---|
| 13 | using SharpVectors.Dom.Svg;
|
---|
| 14 | using SharpVectors.Renderers.Utils;
|
---|
| 15 |
|
---|
| 16 | namespace SharpVectors.Renderers.Wpf
|
---|
| 17 | {
|
---|
| 18 | public class WpfRendering : WpfRenderingBase
|
---|
| 19 | {
|
---|
| 20 | #region Private Fields
|
---|
| 21 |
|
---|
| 22 | private static Regex _reUrl = new Regex(@"^url\((?<uri>.+)\)$", RegexOptions.Compiled);
|
---|
| 23 |
|
---|
| 24 | private Geometry _clipGeometry;
|
---|
| 25 | private Transform _transformMatrix;
|
---|
| 26 | private Brush _maskBrush;
|
---|
| 27 |
|
---|
| 28 | private SvgUnitType _clipPathUnits;
|
---|
| 29 |
|
---|
| 30 | private SvgUnitType _maskUnits;
|
---|
| 31 |
|
---|
| 32 | private SvgUnitType _maskContentUnits;
|
---|
| 33 |
|
---|
| 34 | #endregion
|
---|
| 35 |
|
---|
| 36 | #region Constructor and Destructor
|
---|
| 37 |
|
---|
| 38 | public WpfRendering(SvgElement element)
|
---|
| 39 | : base(element)
|
---|
| 40 | {
|
---|
| 41 | _maskUnits = SvgUnitType.UserSpaceOnUse;
|
---|
| 42 | _clipPathUnits = SvgUnitType.UserSpaceOnUse;
|
---|
| 43 | _maskContentUnits = SvgUnitType.UserSpaceOnUse;
|
---|
| 44 | }
|
---|
| 45 |
|
---|
| 46 | #endregion
|
---|
| 47 |
|
---|
| 48 | #region Public Properties
|
---|
| 49 |
|
---|
| 50 | public Transform Transform
|
---|
| 51 | {
|
---|
| 52 | get
|
---|
| 53 | {
|
---|
| 54 | return _transformMatrix;
|
---|
| 55 | }
|
---|
| 56 | set
|
---|
| 57 | {
|
---|
| 58 | _transformMatrix = value;
|
---|
| 59 | }
|
---|
| 60 | }
|
---|
| 61 |
|
---|
| 62 | public Geometry ClipGeometry
|
---|
| 63 | {
|
---|
| 64 | get
|
---|
| 65 | {
|
---|
| 66 | return _clipGeometry;
|
---|
| 67 | }
|
---|
| 68 | set
|
---|
| 69 | {
|
---|
| 70 | _clipGeometry = value;
|
---|
| 71 | }
|
---|
| 72 | }
|
---|
| 73 |
|
---|
| 74 | public SvgUnitType ClipUnits
|
---|
| 75 | {
|
---|
| 76 | get
|
---|
| 77 | {
|
---|
| 78 | return _clipPathUnits;
|
---|
| 79 | }
|
---|
| 80 | }
|
---|
| 81 |
|
---|
| 82 | public Brush Masking
|
---|
| 83 | {
|
---|
| 84 | get
|
---|
| 85 | {
|
---|
| 86 | return _maskBrush;
|
---|
| 87 | }
|
---|
| 88 | set
|
---|
| 89 | {
|
---|
| 90 | _maskBrush = value;
|
---|
| 91 | }
|
---|
| 92 | }
|
---|
| 93 |
|
---|
| 94 | public SvgUnitType MaskUnits
|
---|
| 95 | {
|
---|
| 96 | get
|
---|
| 97 | {
|
---|
| 98 | return _maskUnits;
|
---|
| 99 | }
|
---|
| 100 | }
|
---|
| 101 |
|
---|
| 102 | public SvgUnitType MaskContentUnits
|
---|
| 103 | {
|
---|
| 104 | get
|
---|
| 105 | {
|
---|
| 106 | return _maskContentUnits;
|
---|
| 107 | }
|
---|
| 108 | }
|
---|
| 109 |
|
---|
| 110 | #endregion
|
---|
| 111 |
|
---|
| 112 | #region Public Methods
|
---|
| 113 |
|
---|
| 114 | public override void BeforeRender(WpfDrawingRenderer renderer)
|
---|
| 115 | {
|
---|
| 116 | if (renderer == null)
|
---|
| 117 | {
|
---|
| 118 | return;
|
---|
| 119 | }
|
---|
| 120 |
|
---|
| 121 | _maskUnits = SvgUnitType.UserSpaceOnUse;
|
---|
| 122 | _clipPathUnits = SvgUnitType.UserSpaceOnUse;
|
---|
| 123 | _maskContentUnits = SvgUnitType.UserSpaceOnUse;
|
---|
| 124 |
|
---|
| 125 | WpfDrawingContext context = renderer.Context;
|
---|
| 126 |
|
---|
| 127 | SetQuality(context);
|
---|
| 128 | SetTransform(context);
|
---|
| 129 | SetClip(context);
|
---|
| 130 | SetMask(context);
|
---|
| 131 | }
|
---|
| 132 |
|
---|
| 133 | public override void AfterRender(WpfDrawingRenderer renderer)
|
---|
| 134 | {
|
---|
| 135 | _clipGeometry = null;
|
---|
| 136 | _transformMatrix = null;
|
---|
| 137 | _maskBrush = null;
|
---|
| 138 |
|
---|
| 139 | _maskUnits = SvgUnitType.UserSpaceOnUse;
|
---|
| 140 | _clipPathUnits = SvgUnitType.UserSpaceOnUse;
|
---|
| 141 | _maskContentUnits = SvgUnitType.UserSpaceOnUse;
|
---|
| 142 | }
|
---|
| 143 |
|
---|
| 144 | #endregion
|
---|
| 145 |
|
---|
| 146 | #region Public Static Methods
|
---|
| 147 |
|
---|
| 148 | public static WpfRendering Create(ISvgElement element)
|
---|
| 149 | {
|
---|
| 150 | if (element == null)
|
---|
| 151 | {
|
---|
| 152 | return null;
|
---|
| 153 | }
|
---|
| 154 |
|
---|
| 155 | SvgRenderingHint hint = element.RenderingHint;
|
---|
| 156 | // For the shapes and text contents...
|
---|
| 157 | if (hint == SvgRenderingHint.Shape)
|
---|
| 158 | {
|
---|
| 159 | return new WpfPathRendering((SvgElement)element);
|
---|
| 160 | }
|
---|
| 161 | if (hint == SvgRenderingHint.Text)
|
---|
| 162 | {
|
---|
| 163 | return new WpfTextRendering((SvgElement)element);
|
---|
| 164 | }
|
---|
| 165 |
|
---|
| 166 | string localName = element.LocalName;
|
---|
| 167 | if (String.IsNullOrEmpty(localName))
|
---|
| 168 | {
|
---|
| 169 | return new WpfRendering((SvgElement)element);
|
---|
| 170 | }
|
---|
| 171 |
|
---|
| 172 | switch (localName)
|
---|
| 173 | {
|
---|
| 174 | case "svg":
|
---|
| 175 | return new WpfSvgRendering((SvgElement)element);
|
---|
| 176 | case "g":
|
---|
| 177 | return new WpfGroupRendering((SvgElement)element);
|
---|
| 178 | case "a":
|
---|
| 179 | return new WpfARendering((SvgElement)element);
|
---|
| 180 | case "use":
|
---|
| 181 | return new WpfUseRendering((SvgElement)element);
|
---|
| 182 | case "switch":
|
---|
| 183 | return new WpfSwitchRendering((SvgElement)element);
|
---|
| 184 | case "image":
|
---|
| 185 | return new WpfImageRendering((SvgElement)element);
|
---|
| 186 | case "marker":
|
---|
| 187 | return new WpfMarkerRendering((SvgElement)element);
|
---|
| 188 | }
|
---|
| 189 |
|
---|
| 190 | return new WpfRendering((SvgElement)element);
|
---|
| 191 | }
|
---|
| 192 |
|
---|
| 193 | /// <summary>
|
---|
| 194 | /// Generates a new <see cref="RenderingNode">RenderingNode</see> that
|
---|
| 195 | /// corresponds to the given Uri.
|
---|
| 196 | /// </summary>
|
---|
| 197 | /// <param name="baseUri">
|
---|
| 198 | /// The base Uri.
|
---|
| 199 | /// </param>
|
---|
| 200 | /// <param name="url">
|
---|
| 201 | /// The url.
|
---|
| 202 | /// </param>
|
---|
| 203 | /// <returns>
|
---|
| 204 | /// The generated <see cref="RenderingNode">RenderingNode</see> that
|
---|
| 205 | /// corresponds to the given Uri.
|
---|
| 206 | /// </returns>
|
---|
| 207 | public static WpfRendering CreateByUri(SvgDocument document, string baseUri, string url)
|
---|
| 208 | {
|
---|
| 209 | if (url.StartsWith("#"))
|
---|
| 210 | {
|
---|
| 211 | // do nothing
|
---|
| 212 | }
|
---|
| 213 | else if (baseUri != "")
|
---|
| 214 | {
|
---|
| 215 | Uri absoluteUri = new Uri(new Uri(baseUri), url);
|
---|
| 216 | url = absoluteUri.AbsoluteUri;
|
---|
| 217 | }
|
---|
| 218 | else
|
---|
| 219 | {
|
---|
| 220 | // TODO: Handle xml:base here?
|
---|
| 221 | // Right now just skip this... it can't be resolved, must assume it is absolute
|
---|
| 222 | }
|
---|
| 223 | ISvgElement elm = document.GetNodeByUri(url) as ISvgElement;
|
---|
| 224 |
|
---|
| 225 | if (elm != null)
|
---|
| 226 | {
|
---|
| 227 | return WpfRendering.Create(elm);
|
---|
| 228 | }
|
---|
| 229 | else
|
---|
| 230 | {
|
---|
| 231 | return null;
|
---|
| 232 | }
|
---|
| 233 | }
|
---|
| 234 |
|
---|
| 235 | #endregion
|
---|
| 236 |
|
---|
| 237 | #region Protected Methods
|
---|
| 238 |
|
---|
| 239 | protected SvgTitleElement GetTitleElement()
|
---|
| 240 | {
|
---|
| 241 | if (_svgElement == null)
|
---|
| 242 | {
|
---|
| 243 | return null;
|
---|
| 244 | }
|
---|
| 245 |
|
---|
| 246 | SvgTitleElement titleElement = null;
|
---|
| 247 | foreach (XmlNode node in _svgElement.ChildNodes)
|
---|
| 248 | {
|
---|
| 249 | if (node.NodeType == XmlNodeType.Element &&
|
---|
| 250 | String.Equals(node.LocalName, "title", StringComparison.OrdinalIgnoreCase))
|
---|
| 251 | {
|
---|
| 252 | titleElement = node as SvgTitleElement;
|
---|
| 253 | break;
|
---|
| 254 | }
|
---|
| 255 | }
|
---|
| 256 |
|
---|
| 257 | return titleElement;
|
---|
| 258 | }
|
---|
| 259 |
|
---|
| 260 | protected void SetClip(WpfDrawingContext context)
|
---|
| 261 | {
|
---|
| 262 | _clipPathUnits = SvgUnitType.UserSpaceOnUse;
|
---|
| 263 |
|
---|
| 264 | if (_svgElement == null)
|
---|
| 265 | {
|
---|
| 266 | return;
|
---|
| 267 | }
|
---|
| 268 |
|
---|
| 269 | #region Clip with clip
|
---|
| 270 |
|
---|
| 271 | // see http://www.w3.org/TR/SVG/masking.html#OverflowAndClipProperties
|
---|
| 272 | if (_svgElement is ISvgSvgElement || _svgElement is ISvgMarkerElement ||
|
---|
| 273 | _svgElement is ISvgSymbolElement || _svgElement is ISvgPatternElement)
|
---|
| 274 | {
|
---|
| 275 | // check overflow property
|
---|
| 276 | CssValue overflow = _svgElement.GetComputedCssValue("overflow", String.Empty) as CssValue;
|
---|
| 277 | // TODO: clip can have "rect(10 10 auto 10)"
|
---|
| 278 | CssPrimitiveValue clip = _svgElement.GetComputedCssValue("clip", String.Empty) as CssPrimitiveValue;
|
---|
| 279 |
|
---|
| 280 | string sOverflow = null;
|
---|
| 281 |
|
---|
| 282 | if (overflow != null || overflow.CssText == "")
|
---|
| 283 | {
|
---|
| 284 | sOverflow = overflow.CssText;
|
---|
| 285 | }
|
---|
| 286 | else
|
---|
| 287 | {
|
---|
| 288 | if (this is ISvgSvgElement)
|
---|
| 289 | sOverflow = "hidden";
|
---|
| 290 | }
|
---|
| 291 |
|
---|
| 292 | if (sOverflow != null)
|
---|
| 293 | {
|
---|
| 294 | // "If the 'overflow' property has a value other than hidden or scroll, the property has no effect (i.e., a clipping rectangle is not created)."
|
---|
| 295 | if (sOverflow == "hidden" || sOverflow == "scroll")
|
---|
| 296 | {
|
---|
| 297 | Rect clipRect = Rect.Empty;
|
---|
| 298 | if (clip != null && clip.PrimitiveType == CssPrimitiveType.Rect)
|
---|
| 299 | {
|
---|
| 300 | if (_svgElement is ISvgSvgElement)
|
---|
| 301 | {
|
---|
| 302 | ISvgSvgElement svgElement = (ISvgSvgElement)_svgElement;
|
---|
| 303 | SvgRect viewPort = svgElement.Viewport as SvgRect;
|
---|
| 304 | clipRect = WpfConvert.ToRect(viewPort);
|
---|
| 305 | ICssRect clipShape = (CssRect)clip.GetRectValue();
|
---|
| 306 | if (clipShape.Top.PrimitiveType != CssPrimitiveType.Ident)
|
---|
| 307 | clipRect.Y += clipShape.Top.GetFloatValue(CssPrimitiveType.Number);
|
---|
| 308 | if (clipShape.Left.PrimitiveType != CssPrimitiveType.Ident)
|
---|
| 309 | clipRect.X += clipShape.Left.GetFloatValue(CssPrimitiveType.Number);
|
---|
| 310 | if (clipShape.Right.PrimitiveType != CssPrimitiveType.Ident)
|
---|
| 311 | clipRect.Width = (clipRect.Right - clipRect.X) - clipShape.Right.GetFloatValue(CssPrimitiveType.Number);
|
---|
| 312 | if (clipShape.Bottom.PrimitiveType != CssPrimitiveType.Ident)
|
---|
| 313 | clipRect.Height = (clipRect.Bottom - clipRect.Y) - clipShape.Bottom.GetFloatValue(CssPrimitiveType.Number);
|
---|
| 314 | }
|
---|
| 315 | }
|
---|
| 316 | else if (clip == null || (clip.PrimitiveType == CssPrimitiveType.Ident && clip.GetStringValue() == "auto"))
|
---|
| 317 | {
|
---|
| 318 | if (_svgElement is ISvgSvgElement)
|
---|
| 319 | {
|
---|
| 320 | ISvgSvgElement svgElement = (ISvgSvgElement)_svgElement;
|
---|
| 321 | SvgRect viewPort = svgElement.Viewport as SvgRect;
|
---|
| 322 | clipRect = WpfConvert.ToRect(viewPort);
|
---|
| 323 | }
|
---|
| 324 | else if (_svgElement is ISvgMarkerElement ||
|
---|
| 325 | _svgElement is ISvgSymbolElement ||
|
---|
| 326 | _svgElement is ISvgPatternElement)
|
---|
| 327 | {
|
---|
| 328 | // TODO: what to do here?
|
---|
| 329 | }
|
---|
| 330 | }
|
---|
| 331 | if (clipRect != Rect.Empty)
|
---|
| 332 | {
|
---|
| 333 | _clipGeometry = new RectangleGeometry(clipRect);
|
---|
| 334 | //gr.SetClip(clipRect);
|
---|
| 335 | }
|
---|
| 336 | }
|
---|
| 337 | }
|
---|
| 338 | }
|
---|
| 339 | #endregion
|
---|
| 340 |
|
---|
| 341 | #region Clip with clip-path
|
---|
| 342 |
|
---|
| 343 | SvgRenderingHint hint = _svgElement.RenderingHint;
|
---|
| 344 |
|
---|
| 345 | if (hint == SvgRenderingHint.Image)
|
---|
| 346 | {
|
---|
| 347 | }
|
---|
| 348 |
|
---|
| 349 | // see: http://www.w3.org/TR/SVG/masking.html#EstablishingANewClippingPath
|
---|
| 350 |
|
---|
| 351 | if (hint == SvgRenderingHint.Shape || hint == SvgRenderingHint.Text ||
|
---|
| 352 | hint == SvgRenderingHint.Clipping || hint == SvgRenderingHint.Masking ||
|
---|
| 353 | hint == SvgRenderingHint.Containment || hint == SvgRenderingHint.Image)
|
---|
| 354 | {
|
---|
| 355 | CssPrimitiveValue clipPath = _svgElement.GetComputedCssValue("clip-path", String.Empty) as CssPrimitiveValue;
|
---|
| 356 |
|
---|
| 357 | if (clipPath != null && clipPath.PrimitiveType == CssPrimitiveType.Uri)
|
---|
| 358 | {
|
---|
| 359 | string absoluteUri = _svgElement.ResolveUri(clipPath.GetStringValue());
|
---|
| 360 |
|
---|
| 361 | SvgClipPathElement eClipPath = _svgElement.OwnerDocument.GetNodeByUri(absoluteUri) as SvgClipPathElement;
|
---|
| 362 |
|
---|
| 363 | if (eClipPath != null)
|
---|
| 364 | {
|
---|
| 365 | GeometryCollection geomColl = CreateClippingRegion(eClipPath, context);
|
---|
| 366 | if (geomColl == null || geomColl.Count == 0)
|
---|
| 367 | {
|
---|
| 368 | return;
|
---|
| 369 | }
|
---|
| 370 | Geometry gpClip = geomColl[0];
|
---|
| 371 | int geomCount = geomColl.Count;
|
---|
| 372 | if (geomCount > 1)
|
---|
| 373 | {
|
---|
| 374 | //GeometryGroup clipGroup = new GeometryGroup();
|
---|
| 375 | //clipGroup.Children.Add(gpClip);
|
---|
| 376 | for (int k = 1; k < geomCount; k++)
|
---|
| 377 | {
|
---|
| 378 | gpClip = CombinedGeometry.Combine(gpClip, geomColl[k],
|
---|
| 379 | GeometryCombineMode.Union, null);
|
---|
| 380 | //clipGroup.Children.Add(geomColl[k]);
|
---|
| 381 | }
|
---|
| 382 |
|
---|
| 383 | //clipGroup.Children.Reverse();
|
---|
| 384 |
|
---|
| 385 | //gpClip = clipGroup;
|
---|
| 386 | }
|
---|
| 387 |
|
---|
| 388 | if (gpClip == null || gpClip.IsEmpty())
|
---|
| 389 | {
|
---|
| 390 | return;
|
---|
| 391 | }
|
---|
| 392 |
|
---|
| 393 | _clipPathUnits = (SvgUnitType)eClipPath.ClipPathUnits.AnimVal;
|
---|
| 394 |
|
---|
| 395 | //if (_clipPathUnits == SvgUnitType.ObjectBoundingBox)
|
---|
| 396 | //{
|
---|
| 397 | // SvgTransformableElement transElement = _svgElement as SvgTransformableElement;
|
---|
| 398 |
|
---|
| 399 | // if (transElement != null)
|
---|
| 400 | // {
|
---|
| 401 | // ISvgRect bbox = transElement.GetBBox();
|
---|
| 402 |
|
---|
| 403 | // // scale clipping path
|
---|
| 404 | // gpClip.Transform = new ScaleTransform(bbox.Width, bbox.Height);
|
---|
| 405 | // //gr.SetClip(gpClip);
|
---|
| 406 |
|
---|
| 407 | // // offset clip
|
---|
| 408 | // //TODO--PAUL gr.TranslateClip((float)bbox.X, (float)bbox.Y);
|
---|
| 409 |
|
---|
| 410 | // _clipGeometry = gpClip;
|
---|
| 411 | // }
|
---|
| 412 | // else
|
---|
| 413 | // {
|
---|
| 414 | // throw new NotImplementedException("clip-path with SvgUnitType.ObjectBoundingBox "
|
---|
| 415 | // + "not supported for this type of element: " + _svgElement.GetType());
|
---|
| 416 | // }
|
---|
| 417 | //}
|
---|
| 418 | //else
|
---|
| 419 | {
|
---|
| 420 | //gr.SetClip(gpClip);
|
---|
| 421 |
|
---|
| 422 | _clipGeometry = gpClip;
|
---|
| 423 | }
|
---|
| 424 | }
|
---|
| 425 | }
|
---|
| 426 | }
|
---|
| 427 |
|
---|
| 428 | #endregion
|
---|
| 429 | }
|
---|
| 430 |
|
---|
| 431 | protected void SetMask(WpfDrawingContext context)
|
---|
| 432 | {
|
---|
| 433 | _maskUnits = SvgUnitType.UserSpaceOnUse;
|
---|
| 434 | _maskContentUnits = SvgUnitType.UserSpaceOnUse;
|
---|
| 435 |
|
---|
| 436 | CssPrimitiveValue maskPath = _svgElement.GetComputedCssValue(
|
---|
| 437 | "mask", String.Empty) as CssPrimitiveValue;
|
---|
| 438 |
|
---|
| 439 | if (maskPath != null && maskPath.PrimitiveType == CssPrimitiveType.Uri)
|
---|
| 440 | {
|
---|
| 441 | string absoluteUri = _svgElement.ResolveUri(maskPath.GetStringValue());
|
---|
| 442 |
|
---|
| 443 | SvgMaskElement maskElement =
|
---|
| 444 | _svgElement.OwnerDocument.GetNodeByUri(absoluteUri) as SvgMaskElement;
|
---|
| 445 |
|
---|
| 446 | if (maskElement != null)
|
---|
| 447 | {
|
---|
| 448 | WpfDrawingRenderer renderer = new WpfDrawingRenderer();
|
---|
| 449 | renderer.Window = _svgElement.OwnerDocument.Window as SvgWindow;
|
---|
| 450 |
|
---|
| 451 | WpfDrawingSettings settings = context.Settings.Clone();
|
---|
| 452 | settings.TextAsGeometry = true;
|
---|
| 453 | WpfDrawingContext maskContext = new WpfDrawingContext(true,
|
---|
| 454 | settings);
|
---|
| 455 |
|
---|
| 456 | maskContext.Initialize(null, context.FontFamilyVisitor, null);
|
---|
| 457 |
|
---|
| 458 | renderer.RenderMask(maskElement, maskContext);
|
---|
| 459 | Drawing image = renderer.Drawing;
|
---|
| 460 |
|
---|
| 461 | Rect bounds = new Rect(0, 0, 1, 1);
|
---|
| 462 | //Rect destRect = GetMaskDestRect(maskElement, bounds);
|
---|
| 463 |
|
---|
| 464 | //destRect = bounds;
|
---|
| 465 |
|
---|
| 466 | //DrawingImage drawImage = new DrawingImage(image);
|
---|
| 467 |
|
---|
| 468 | //DrawingVisual drawingVisual = new DrawingVisual();
|
---|
| 469 | //DrawingContext drawingContext = drawingVisual.RenderOpen();
|
---|
| 470 | //drawingContext.DrawDrawing(image);
|
---|
| 471 | //drawingContext.Close();
|
---|
| 472 |
|
---|
| 473 | //RenderTargetBitmap drawImage = new RenderTargetBitmap((int)200,
|
---|
| 474 | // (int)200, 96, 96, PixelFormats.Pbgra32);
|
---|
| 475 | //drawImage.Render(drawingVisual);
|
---|
| 476 |
|
---|
| 477 | //ImageBrush imageBrush = new ImageBrush(drawImage);
|
---|
| 478 | //imageBrush.Viewbox = image.Bounds;
|
---|
| 479 | //imageBrush.Viewport = image.Bounds;
|
---|
| 480 | //imageBrush.ViewboxUnits = BrushMappingMode.Absolute;
|
---|
| 481 | //imageBrush.ViewportUnits = BrushMappingMode.Absolute;
|
---|
| 482 | //imageBrush.TileMode = TileMode.None;
|
---|
| 483 | //imageBrush.Stretch = Stretch.None;
|
---|
| 484 |
|
---|
| 485 | //this.Masking = imageBrush;
|
---|
| 486 |
|
---|
| 487 | DrawingBrush maskBrush = new DrawingBrush(image);
|
---|
| 488 | //tb.Viewbox = new Rect(0, 0, destRect.Width, destRect.Height);
|
---|
| 489 | //tb.Viewport = new Rect(0, 0, destRect.Width, destRect.Height);
|
---|
| 490 | maskBrush.Viewbox = image.Bounds;
|
---|
| 491 | maskBrush.Viewport = image.Bounds;
|
---|
| 492 | maskBrush.ViewboxUnits = BrushMappingMode.Absolute;
|
---|
| 493 | maskBrush.ViewportUnits = BrushMappingMode.Absolute;
|
---|
| 494 | maskBrush.TileMode = TileMode.None;
|
---|
| 495 | maskBrush.Stretch = Stretch.Uniform;
|
---|
| 496 |
|
---|
| 497 | ////maskBrush.AlignmentX = AlignmentX.Center;
|
---|
| 498 | ////maskBrush.AlignmentY = AlignmentY.Center;
|
---|
| 499 |
|
---|
| 500 | this.Masking = maskBrush;
|
---|
| 501 |
|
---|
| 502 | _maskUnits = (SvgUnitType)maskElement.MaskUnits.AnimVal;
|
---|
| 503 | _maskContentUnits = (SvgUnitType)maskElement.MaskContentUnits.AnimVal;
|
---|
| 504 |
|
---|
| 505 | }
|
---|
| 506 | }
|
---|
| 507 | }
|
---|
| 508 |
|
---|
| 509 | private static double CalcPatternUnit(SvgMaskElement maskElement, SvgLength length,
|
---|
| 510 | SvgLengthDirection dir, Rect bounds)
|
---|
| 511 | {
|
---|
| 512 | if (maskElement.MaskUnits.AnimVal.Equals(SvgUnitType.UserSpaceOnUse))
|
---|
| 513 | {
|
---|
| 514 | return length.Value;
|
---|
| 515 | }
|
---|
| 516 | else
|
---|
| 517 | {
|
---|
| 518 | double calcValue = length.ValueInSpecifiedUnits;
|
---|
| 519 | if (dir == SvgLengthDirection.Horizontal)
|
---|
| 520 | {
|
---|
| 521 | calcValue *= bounds.Width;
|
---|
| 522 | }
|
---|
| 523 | else
|
---|
| 524 | {
|
---|
| 525 | calcValue *= bounds.Height;
|
---|
| 526 | }
|
---|
| 527 | if (length.UnitType == SvgLengthType.Percentage)
|
---|
| 528 | {
|
---|
| 529 | calcValue /= 100F;
|
---|
| 530 | }
|
---|
| 531 |
|
---|
| 532 | return calcValue;
|
---|
| 533 | }
|
---|
| 534 | }
|
---|
| 535 |
|
---|
| 536 | private static Rect GetMaskDestRect(SvgMaskElement maskElement, Rect bounds)
|
---|
| 537 | {
|
---|
| 538 | Rect result = new Rect(0, 0, 0, 0);
|
---|
| 539 |
|
---|
| 540 | result.X = CalcPatternUnit(maskElement, maskElement.X.AnimVal as SvgLength,
|
---|
| 541 | SvgLengthDirection.Horizontal, bounds);
|
---|
| 542 | result.Y = CalcPatternUnit(maskElement, maskElement.Y.AnimVal as SvgLength,
|
---|
| 543 | SvgLengthDirection.Vertical, bounds);
|
---|
| 544 |
|
---|
| 545 | result.Width = CalcPatternUnit(maskElement, maskElement.Width.AnimVal as SvgLength,
|
---|
| 546 | SvgLengthDirection.Horizontal, bounds);
|
---|
| 547 | result.Height = CalcPatternUnit(maskElement, maskElement.Height.AnimVal as SvgLength,
|
---|
| 548 | SvgLengthDirection.Vertical, bounds);
|
---|
| 549 |
|
---|
| 550 | return result;
|
---|
| 551 | }
|
---|
| 552 |
|
---|
| 553 | protected void SetQuality(WpfDrawingContext context)
|
---|
| 554 | {
|
---|
| 555 | //Graphics graphics = gr.Graphics;
|
---|
| 556 |
|
---|
| 557 | //string colorRendering = _svgElement.GetComputedStringValue("color-rendering", String.Empty);
|
---|
| 558 | //switch (colorRendering)
|
---|
| 559 | //{
|
---|
| 560 | // case "optimizeSpeed":
|
---|
| 561 | // graphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighSpeed;
|
---|
| 562 | // break;
|
---|
| 563 | // case "optimizeQuality":
|
---|
| 564 | // graphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
|
---|
| 565 | // break;
|
---|
| 566 | // default:
|
---|
| 567 | // // "auto"
|
---|
| 568 | // // todo: could use AssumeLinear for slightly better
|
---|
| 569 | // graphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.Default;
|
---|
| 570 | // break;
|
---|
| 571 | //}
|
---|
| 572 |
|
---|
| 573 | //if (element is SvgTextContentElement)
|
---|
| 574 | //{
|
---|
| 575 | // // Unfortunately the text rendering hints are not applied because the
|
---|
| 576 | // // text path is recorded and painted to the Graphics object as a path
|
---|
| 577 | // // not as text.
|
---|
| 578 | // string textRendering = _svgElement.GetComputedStringValue("text-rendering", String.Empty);
|
---|
| 579 | // switch (textRendering)
|
---|
| 580 | // {
|
---|
| 581 | // case "optimizeSpeed":
|
---|
| 582 | // graphics.SmoothingMode = SmoothingMode.HighSpeed;
|
---|
| 583 | // //graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SingleBitPerPixel;
|
---|
| 584 | // break;
|
---|
| 585 | // case "optimizeLegibility":
|
---|
| 586 | // graphics.SmoothingMode = SmoothingMode.HighQuality;
|
---|
| 587 | // //graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
|
---|
| 588 | // break;
|
---|
| 589 | // case "geometricPrecision":
|
---|
| 590 | // graphics.SmoothingMode = SmoothingMode.AntiAlias;
|
---|
| 591 | // //graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
|
---|
| 592 | // break;
|
---|
| 593 | // default:
|
---|
| 594 | // // "auto"
|
---|
| 595 | // graphics.SmoothingMode = SmoothingMode.AntiAlias;
|
---|
| 596 | // //graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SystemDefault;
|
---|
| 597 | // break;
|
---|
| 598 | // }
|
---|
| 599 | //}
|
---|
| 600 | //else
|
---|
| 601 | //{
|
---|
| 602 | // string shapeRendering = _svgElement.GetComputedStringValue("shape-rendering", String.Empty);
|
---|
| 603 | // switch (shapeRendering)
|
---|
| 604 | // {
|
---|
| 605 | // case "optimizeSpeed":
|
---|
| 606 | // graphics.SmoothingMode = SmoothingMode.HighSpeed;
|
---|
| 607 | // break;
|
---|
| 608 | // case "crispEdges":
|
---|
| 609 | // graphics.SmoothingMode = SmoothingMode.None;
|
---|
| 610 | // break;
|
---|
| 611 | // case "geometricPrecision":
|
---|
| 612 | // graphics.SmoothingMode = SmoothingMode.HighQuality;
|
---|
| 613 | // break;
|
---|
| 614 | // default:
|
---|
| 615 | // // "auto"
|
---|
| 616 | // graphics.SmoothingMode = SmoothingMode.AntiAlias;
|
---|
| 617 | // break;
|
---|
| 618 | // }
|
---|
| 619 | //}
|
---|
| 620 | }
|
---|
| 621 |
|
---|
| 622 | protected void SetTransform(WpfDrawingContext context)
|
---|
| 623 | {
|
---|
| 624 | _transformMatrix = null;
|
---|
| 625 |
|
---|
| 626 | ISvgTransformable transElm = _svgElement as ISvgTransformable;
|
---|
| 627 | if (transElm != null)
|
---|
| 628 | {
|
---|
| 629 | SvgTransformList svgTList = (SvgTransformList)transElm.Transform.AnimVal;
|
---|
| 630 | SvgMatrix svgMatrix = ((SvgTransformList)transElm.Transform.AnimVal).TotalMatrix;
|
---|
| 631 |
|
---|
| 632 | if (svgMatrix.IsIdentity)
|
---|
| 633 | {
|
---|
| 634 | return;
|
---|
| 635 | }
|
---|
| 636 |
|
---|
| 637 | _transformMatrix = new MatrixTransform(svgMatrix.A, svgMatrix.B, svgMatrix.C,
|
---|
| 638 | svgMatrix.D, svgMatrix.E, svgMatrix.F);
|
---|
| 639 | }
|
---|
| 640 | }
|
---|
| 641 |
|
---|
| 642 | protected void FitToViewbox(WpfDrawingContext context, Rect elementBounds)
|
---|
| 643 | {
|
---|
| 644 | ISvgFitToViewBox fitToView = _svgElement as ISvgFitToViewBox;
|
---|
| 645 | if (fitToView == null)
|
---|
| 646 | {
|
---|
| 647 | return;
|
---|
| 648 | }
|
---|
| 649 |
|
---|
| 650 | SvgPreserveAspectRatio spar = (SvgPreserveAspectRatio)fitToView.PreserveAspectRatio.AnimVal;
|
---|
| 651 |
|
---|
| 652 | double[] transformArray = spar.FitToViewBox((SvgRect)fitToView.ViewBox.AnimVal,
|
---|
| 653 | new SvgRect(elementBounds.X, elementBounds.Y, elementBounds.Width, elementBounds.Height));
|
---|
| 654 |
|
---|
| 655 | double translateX = transformArray[0];
|
---|
| 656 | double translateY = transformArray[1];
|
---|
| 657 | double scaleX = transformArray[2];
|
---|
| 658 | double scaleY = transformArray[3];
|
---|
| 659 |
|
---|
| 660 | Transform translateMatrix = null;
|
---|
| 661 | Transform scaleMatrix = null;
|
---|
| 662 | //if (translateX >= 0 && translateY >= 0)
|
---|
| 663 | {
|
---|
| 664 | translateMatrix = new TranslateTransform(translateX, translateY);
|
---|
| 665 | }
|
---|
| 666 | if ((float)scaleX != 1.0f && (float)scaleY != 1.0f)
|
---|
| 667 | {
|
---|
| 668 | scaleMatrix = new ScaleTransform(scaleX, scaleY);
|
---|
| 669 | }
|
---|
| 670 |
|
---|
| 671 | if (translateMatrix != null && scaleMatrix != null)
|
---|
| 672 | {
|
---|
| 673 | // Create a TransformGroup to contain the transforms
|
---|
| 674 | // and add the transforms to it.
|
---|
| 675 | TransformGroup transformGroup = new TransformGroup();
|
---|
| 676 | transformGroup.Children.Add(scaleMatrix);
|
---|
| 677 | transformGroup.Children.Add(translateMatrix);
|
---|
| 678 |
|
---|
| 679 | this.Transform = transformGroup;
|
---|
| 680 | }
|
---|
| 681 | else if (translateMatrix != null)
|
---|
| 682 | {
|
---|
| 683 | this.Transform = translateMatrix;
|
---|
| 684 | }
|
---|
| 685 | else if (scaleMatrix != null)
|
---|
| 686 | {
|
---|
| 687 | this.Transform = scaleMatrix;
|
---|
| 688 | }
|
---|
| 689 | }
|
---|
| 690 |
|
---|
| 691 | protected void FitToViewbox(WpfDrawingContext context, SvgElement svgElement, Rect elementBounds)
|
---|
| 692 | {
|
---|
| 693 | if (svgElement == null)
|
---|
| 694 | {
|
---|
| 695 | return;
|
---|
| 696 | }
|
---|
| 697 | ISvgFitToViewBox fitToView = svgElement as ISvgFitToViewBox;
|
---|
| 698 | if (fitToView == null)
|
---|
| 699 | {
|
---|
| 700 | return;
|
---|
| 701 | }
|
---|
| 702 |
|
---|
| 703 | SvgPreserveAspectRatio spar = (SvgPreserveAspectRatio)fitToView.PreserveAspectRatio.AnimVal;
|
---|
| 704 |
|
---|
| 705 | double[] transformArray = spar.FitToViewBox((SvgRect)fitToView.ViewBox.AnimVal,
|
---|
| 706 | new SvgRect(elementBounds.X, elementBounds.Y, elementBounds.Width, elementBounds.Height));
|
---|
| 707 |
|
---|
| 708 | double translateX = transformArray[0];
|
---|
| 709 | double translateY = transformArray[1];
|
---|
| 710 | double scaleX = transformArray[2];
|
---|
| 711 | double scaleY = transformArray[3];
|
---|
| 712 |
|
---|
| 713 | Transform translateMatrix = null;
|
---|
| 714 | Transform scaleMatrix = null;
|
---|
| 715 | //if (translateX > 0 && translateY > 0)
|
---|
| 716 | {
|
---|
| 717 | translateMatrix = new TranslateTransform(translateX, translateY);
|
---|
| 718 | }
|
---|
| 719 | if ((float)scaleX != 1.0f && (float)scaleY != 1.0f)
|
---|
| 720 | {
|
---|
| 721 | scaleMatrix = new ScaleTransform(scaleX, scaleY);
|
---|
| 722 | }
|
---|
| 723 |
|
---|
| 724 | if (translateMatrix != null && scaleMatrix != null)
|
---|
| 725 | {
|
---|
| 726 | // Create a TransformGroup to contain the transforms
|
---|
| 727 | // and add the transforms to it.
|
---|
| 728 | TransformGroup transformGroup = new TransformGroup();
|
---|
| 729 | transformGroup.Children.Add(scaleMatrix);
|
---|
| 730 | transformGroup.Children.Add(translateMatrix);
|
---|
| 731 |
|
---|
| 732 | this.Transform = transformGroup;
|
---|
| 733 | }
|
---|
| 734 | else if (translateMatrix != null)
|
---|
| 735 | {
|
---|
| 736 | this.Transform = translateMatrix;
|
---|
| 737 | }
|
---|
| 738 | else if (scaleMatrix != null)
|
---|
| 739 | {
|
---|
| 740 | this.Transform = scaleMatrix;
|
---|
| 741 | }
|
---|
| 742 | }
|
---|
| 743 |
|
---|
| 744 | #endregion
|
---|
| 745 |
|
---|
| 746 | #region Private Methods
|
---|
| 747 |
|
---|
| 748 | private GeometryCollection CreateClippingRegion(SvgClipPathElement clipPath,
|
---|
| 749 | WpfDrawingContext context)
|
---|
| 750 | {
|
---|
| 751 | GeometryCollection geomColl = new GeometryCollection();
|
---|
| 752 |
|
---|
| 753 | foreach (XmlNode node in clipPath.ChildNodes)
|
---|
| 754 | {
|
---|
| 755 | if (node.NodeType != XmlNodeType.Element)
|
---|
| 756 | {
|
---|
| 757 | continue;
|
---|
| 758 | }
|
---|
| 759 |
|
---|
| 760 | // Handle a case where the clip element has "use" element as a child...
|
---|
| 761 | if (String.Equals(node.LocalName, "use"))
|
---|
| 762 | {
|
---|
| 763 | SvgUseElement useElement = (SvgUseElement)node;
|
---|
| 764 |
|
---|
| 765 | XmlElement refEl = useElement.ReferencedElement;
|
---|
| 766 | if (refEl != null)
|
---|
| 767 | {
|
---|
| 768 | XmlElement refElParent = (XmlElement)refEl.ParentNode;
|
---|
| 769 | useElement.OwnerDocument.Static = true;
|
---|
| 770 | useElement.CopyToReferencedElement(refEl);
|
---|
| 771 | refElParent.RemoveChild(refEl);
|
---|
| 772 | useElement.AppendChild(refEl);
|
---|
| 773 |
|
---|
| 774 | foreach (XmlNode useChild in useElement.ChildNodes)
|
---|
| 775 | {
|
---|
| 776 | if (useChild.NodeType != XmlNodeType.Element)
|
---|
| 777 | {
|
---|
| 778 | continue;
|
---|
| 779 | }
|
---|
| 780 |
|
---|
| 781 | SvgStyleableElement element = useChild as SvgStyleableElement;
|
---|
| 782 | if (element != null && element.RenderingHint == SvgRenderingHint.Shape)
|
---|
| 783 | {
|
---|
| 784 | Geometry childPath = CreateGeometry(element, context.OptimizePath);
|
---|
| 785 |
|
---|
| 786 | if (childPath != null)
|
---|
| 787 | {
|
---|
| 788 | geomColl.Add(childPath);
|
---|
| 789 | }
|
---|
| 790 | }
|
---|
| 791 | }
|
---|
| 792 |
|
---|
| 793 | useElement.RemoveChild(refEl);
|
---|
| 794 | useElement.RestoreReferencedElement(refEl);
|
---|
| 795 | refElParent.AppendChild(refEl);
|
---|
| 796 | useElement.OwnerDocument.Static = false;
|
---|
| 797 | }
|
---|
| 798 | }
|
---|
| 799 | else
|
---|
| 800 | {
|
---|
| 801 | SvgStyleableElement element = node as SvgStyleableElement;
|
---|
| 802 | if (element != null)
|
---|
| 803 | {
|
---|
| 804 | if (element.RenderingHint == SvgRenderingHint.Shape)
|
---|
| 805 | {
|
---|
| 806 | Geometry childPath = CreateGeometry(element, context.OptimizePath);
|
---|
| 807 |
|
---|
| 808 | if (childPath != null)
|
---|
| 809 | {
|
---|
| 810 | geomColl.Add(childPath);
|
---|
| 811 | }
|
---|
| 812 | }
|
---|
| 813 | else if (element.RenderingHint == SvgRenderingHint.Text)
|
---|
| 814 | {
|
---|
| 815 | GeometryCollection textGeomColl = GetTextClippingRegion(element, context);
|
---|
| 816 | if (textGeomColl != null)
|
---|
| 817 | {
|
---|
| 818 | for (int i = 0; i < textGeomColl.Count; i++)
|
---|
| 819 | {
|
---|
| 820 | geomColl.Add(textGeomColl[i]);
|
---|
| 821 | }
|
---|
| 822 | }
|
---|
| 823 | }
|
---|
| 824 | }
|
---|
| 825 | }
|
---|
| 826 | }
|
---|
| 827 |
|
---|
| 828 | return geomColl;
|
---|
| 829 | }
|
---|
| 830 |
|
---|
| 831 | private GeometryCollection GetTextClippingRegion(SvgStyleableElement element,
|
---|
| 832 | WpfDrawingContext context)
|
---|
| 833 | {
|
---|
| 834 | GeometryCollection geomColl = new GeometryCollection();
|
---|
| 835 |
|
---|
| 836 | WpfDrawingRenderer renderer = new WpfDrawingRenderer();
|
---|
| 837 | renderer.Window = _svgElement.OwnerDocument.Window as SvgWindow;
|
---|
| 838 |
|
---|
| 839 | WpfDrawingSettings settings = context.Settings.Clone();
|
---|
| 840 | settings.TextAsGeometry = true;
|
---|
| 841 | WpfDrawingContext clipContext = new WpfDrawingContext(true,
|
---|
| 842 | settings);
|
---|
| 843 | clipContext.RenderingClipRegion = true;
|
---|
| 844 |
|
---|
| 845 | clipContext.Initialize(null, context.FontFamilyVisitor, null);
|
---|
| 846 |
|
---|
| 847 | renderer.Render(element, clipContext);
|
---|
| 848 |
|
---|
| 849 | DrawingGroup rootGroup = renderer.Drawing as DrawingGroup;
|
---|
| 850 | if (rootGroup != null && rootGroup.Children.Count == 1)
|
---|
| 851 | {
|
---|
| 852 | DrawingGroup textGroup = rootGroup.Children[0] as DrawingGroup;
|
---|
| 853 | if (textGroup != null)
|
---|
| 854 | {
|
---|
| 855 | ExtractGeometry(textGroup, geomColl);
|
---|
| 856 | }
|
---|
| 857 | }
|
---|
| 858 |
|
---|
| 859 | return geomColl;
|
---|
| 860 | }
|
---|
| 861 |
|
---|
| 862 | private static void ExtractGeometry(DrawingGroup group, GeometryCollection geomColl)
|
---|
| 863 | {
|
---|
| 864 | if (geomColl == null)
|
---|
| 865 | {
|
---|
| 866 | return;
|
---|
| 867 | }
|
---|
| 868 |
|
---|
| 869 | DrawingCollection drawings = group.Children;
|
---|
| 870 | int textItem = drawings.Count;
|
---|
| 871 | for (int i = 0; i < textItem; i++)
|
---|
| 872 | {
|
---|
| 873 | Drawing drawing = drawings[i];
|
---|
| 874 | GeometryDrawing aDrawing = drawing as GeometryDrawing;
|
---|
| 875 | if (aDrawing != null)
|
---|
| 876 | {
|
---|
| 877 | Geometry aGeometry = aDrawing.Geometry;
|
---|
| 878 | if (aGeometry != null)
|
---|
| 879 | {
|
---|
| 880 | GeometryGroup geomGroup = aGeometry as GeometryGroup;
|
---|
| 881 | if (geomGroup != null)
|
---|
| 882 | {
|
---|
| 883 | GeometryCollection children = geomGroup.Children;
|
---|
| 884 | for (int j = 0; j < children.Count; j++)
|
---|
| 885 | {
|
---|
| 886 | geomColl.Add(children[j]);
|
---|
| 887 | }
|
---|
| 888 | }
|
---|
| 889 | else
|
---|
| 890 | {
|
---|
| 891 | geomColl.Add(aGeometry);
|
---|
| 892 | }
|
---|
| 893 | }
|
---|
| 894 | }
|
---|
| 895 | else
|
---|
| 896 | {
|
---|
| 897 | DrawingGroup innerGroup = drawing as DrawingGroup;
|
---|
| 898 | if (innerGroup != null)
|
---|
| 899 | {
|
---|
| 900 | ExtractGeometry(innerGroup, geomColl);
|
---|
| 901 | }
|
---|
| 902 | }
|
---|
| 903 | }
|
---|
| 904 | }
|
---|
| 905 |
|
---|
| 906 |
|
---|
| 907 | #endregion
|
---|
| 908 |
|
---|
| 909 | #region Geometry Methods
|
---|
| 910 |
|
---|
| 911 | public static Geometry CreateGeometry(ISvgElement element, bool optimizePath)
|
---|
| 912 | {
|
---|
| 913 | if (element == null || element.RenderingHint != SvgRenderingHint.Shape)
|
---|
| 914 | {
|
---|
| 915 | return null;
|
---|
| 916 | }
|
---|
| 917 |
|
---|
| 918 | string localName = element.LocalName;
|
---|
| 919 | switch (localName)
|
---|
| 920 | {
|
---|
| 921 | case "ellipse":
|
---|
| 922 | return CreateGeometry((SvgEllipseElement)element);
|
---|
| 923 | case "rect":
|
---|
| 924 | return CreateGeometry((SvgRectElement)element);
|
---|
| 925 | case "line":
|
---|
| 926 | return CreateGeometry((SvgLineElement)element);
|
---|
| 927 | case "path":
|
---|
| 928 | if (optimizePath)
|
---|
| 929 | {
|
---|
| 930 | return CreateGeometryEx((SvgPathElement)element);
|
---|
| 931 | }
|
---|
| 932 | else
|
---|
| 933 | {
|
---|
| 934 | return CreateGeometry((SvgPathElement)element);
|
---|
| 935 | }
|
---|
| 936 | case "circle":
|
---|
| 937 | return CreateGeometry((SvgCircleElement)element);
|
---|
| 938 | case "polyline":
|
---|
| 939 | return CreateGeometry((SvgPolylineElement)element);
|
---|
| 940 | case "polygon":
|
---|
| 941 | return CreateGeometry((SvgPolygonElement)element);
|
---|
| 942 | }
|
---|
| 943 |
|
---|
| 944 | return null;
|
---|
| 945 | }
|
---|
| 946 |
|
---|
| 947 | #region SvgEllipseElement Geometry
|
---|
| 948 |
|
---|
| 949 | public static Geometry CreateGeometry(SvgEllipseElement element)
|
---|
| 950 | {
|
---|
| 951 | double _cx = Math.Round(element.Cx.AnimVal.Value, 4);
|
---|
| 952 | double _cy = Math.Round(element.Cy.AnimVal.Value, 4);
|
---|
| 953 | double _rx = Math.Round(element.Rx.AnimVal.Value, 4);
|
---|
| 954 | double _ry = Math.Round(element.Ry.AnimVal.Value, 4);
|
---|
| 955 |
|
---|
| 956 | if (_rx <= 0 || _ry <= 0)
|
---|
| 957 | {
|
---|
| 958 | return null;
|
---|
| 959 | }
|
---|
| 960 |
|
---|
| 961 | /*if (_cx <= 1 && _cy <= 1 && _rx <= 1 && _ry <= 1)
|
---|
| 962 | {
|
---|
| 963 | gp.AddEllipse(_cx-_rx, _cy-_ry, _rx*2, _ry*2);
|
---|
| 964 | }
|
---|
| 965 | else
|
---|
| 966 | {
|
---|
| 967 | gp.AddEllipse(_cx-_rx, _cy-_ry, _rx*2 - 1, _ry*2 - 1);
|
---|
| 968 | }*/
|
---|
| 969 | //gp.AddEllipse(_cx - _rx, _cy - _ry, _rx * 2, _ry * 2);
|
---|
| 970 |
|
---|
| 971 | EllipseGeometry geometry = new EllipseGeometry(new Point(_cx, _cy),
|
---|
| 972 | _rx, _ry);
|
---|
| 973 |
|
---|
| 974 | return geometry;
|
---|
| 975 | }
|
---|
| 976 |
|
---|
| 977 | #endregion
|
---|
| 978 |
|
---|
| 979 | #region SvgRectElement Geometry
|
---|
| 980 |
|
---|
| 981 | public static Geometry CreateGeometry(SvgRectElement element)
|
---|
| 982 | {
|
---|
| 983 | double dx = Math.Round(element.X.AnimVal.Value, 4);
|
---|
| 984 | double dy = Math.Round(element.Y.AnimVal.Value, 4);
|
---|
| 985 | double width = Math.Round(element.Width.AnimVal.Value, 4);
|
---|
| 986 | double height = Math.Round(element.Height.AnimVal.Value, 4);
|
---|
| 987 | double rx = Math.Round(element.Rx.AnimVal.Value, 4);
|
---|
| 988 | double ry = Math.Round(element.Ry.AnimVal.Value, 4);
|
---|
| 989 |
|
---|
| 990 | if (width <= 0 || height <= 0)
|
---|
| 991 | {
|
---|
| 992 | return null;
|
---|
| 993 | }
|
---|
| 994 | if (rx <= 0 && ry > 0)
|
---|
| 995 | {
|
---|
| 996 | rx = ry;
|
---|
| 997 | }
|
---|
| 998 | else if (rx > 0 && ry <= 0)
|
---|
| 999 | {
|
---|
| 1000 | ry = rx;
|
---|
| 1001 | }
|
---|
| 1002 |
|
---|
| 1003 | return new RectangleGeometry(new Rect(dx, dy, width, height), rx, ry);
|
---|
| 1004 | }
|
---|
| 1005 |
|
---|
| 1006 | #endregion
|
---|
| 1007 |
|
---|
| 1008 | #region SvgLineElement Geometry
|
---|
| 1009 |
|
---|
| 1010 | public static Geometry CreateGeometry(SvgLineElement element)
|
---|
| 1011 | {
|
---|
| 1012 | return new LineGeometry(new Point(Math.Round(element.X1.AnimVal.Value, 4),
|
---|
| 1013 | Math.Round(element.Y1.AnimVal.Value, 4)),
|
---|
| 1014 | new Point(Math.Round(element.X2.AnimVal.Value, 4), Math.Round(element.Y2.AnimVal.Value, 4)));
|
---|
| 1015 | }
|
---|
| 1016 |
|
---|
| 1017 | #endregion
|
---|
| 1018 |
|
---|
| 1019 | #region SvgPathElement Geometry
|
---|
| 1020 |
|
---|
| 1021 | public static Geometry CreateGeometryEx(SvgPathElement element)
|
---|
| 1022 | {
|
---|
| 1023 | PathGeometry geometry = new PathGeometry();
|
---|
| 1024 |
|
---|
| 1025 | string pathScript = element.PathScript;
|
---|
| 1026 | if (String.IsNullOrEmpty(pathScript))
|
---|
| 1027 | {
|
---|
| 1028 | return geometry;
|
---|
| 1029 | }
|
---|
| 1030 |
|
---|
| 1031 | string fillRule = element.GetPropertyValue("fill-rule");
|
---|
| 1032 | string clipRule = element.GetAttribute("clip-rule");
|
---|
| 1033 | if (!String.IsNullOrEmpty(clipRule) &&
|
---|
| 1034 | String.Equals(clipRule, "evenodd") || String.Equals(clipRule, "nonzero"))
|
---|
| 1035 | {
|
---|
| 1036 | fillRule = clipRule;
|
---|
| 1037 | }
|
---|
| 1038 | if (fillRule == "evenodd")
|
---|
| 1039 | geometry.FillRule = FillRule.EvenOdd;
|
---|
| 1040 | else if (fillRule == "nonzero")
|
---|
| 1041 | geometry.FillRule = FillRule.Nonzero;
|
---|
| 1042 |
|
---|
| 1043 | try
|
---|
| 1044 | {
|
---|
| 1045 | geometry.Figures = PathFigureCollection.Parse(pathScript);
|
---|
| 1046 | }
|
---|
| 1047 | catch
|
---|
| 1048 | {
|
---|
| 1049 | }
|
---|
| 1050 |
|
---|
| 1051 | return geometry;
|
---|
| 1052 | }
|
---|
| 1053 |
|
---|
| 1054 | public static Geometry CreateGeometry(SvgPathElement element)
|
---|
| 1055 | {
|
---|
| 1056 | PathGeometry geometry = new PathGeometry();
|
---|
| 1057 |
|
---|
| 1058 | string fillRule = element.GetPropertyValue("fill-rule");
|
---|
| 1059 | string clipRule = element.GetAttribute("clip-rule");
|
---|
| 1060 | if (!String.IsNullOrEmpty(clipRule) &&
|
---|
| 1061 | String.Equals(clipRule, "evenodd") || String.Equals(clipRule, "nonzero"))
|
---|
| 1062 | {
|
---|
| 1063 | fillRule = clipRule;
|
---|
| 1064 | }
|
---|
| 1065 | if (fillRule == "evenodd")
|
---|
| 1066 | geometry.FillRule = FillRule.EvenOdd;
|
---|
| 1067 | else if (fillRule == "nonzero")
|
---|
| 1068 | geometry.FillRule = FillRule.Nonzero;
|
---|
| 1069 |
|
---|
| 1070 | SvgPointF initPoint = new SvgPointF(0, 0);
|
---|
| 1071 | SvgPointF lastPoint = new SvgPointF(0, 0);
|
---|
| 1072 |
|
---|
| 1073 | ISvgPathSeg segment = null;
|
---|
| 1074 | SvgPathSegMoveto pathMoveTo = null;
|
---|
| 1075 | SvgPathSegLineto pathLineTo = null;
|
---|
| 1076 | SvgPathSegCurveto pathCurveTo = null;
|
---|
| 1077 | SvgPathSegArc pathArc = null;
|
---|
| 1078 |
|
---|
| 1079 | ISvgPathSegList segments = element.PathSegList;
|
---|
| 1080 | int nElems = segments.NumberOfItems;
|
---|
| 1081 |
|
---|
| 1082 | PathFigure pathFigure = null;
|
---|
| 1083 |
|
---|
| 1084 | for (int i = 0; i < nElems; i++)
|
---|
| 1085 | {
|
---|
| 1086 | segment = segments.GetItem(i);
|
---|
| 1087 |
|
---|
| 1088 | if (DynamicCast.Cast(segment, out pathMoveTo))
|
---|
| 1089 | {
|
---|
| 1090 | if (pathFigure != null)
|
---|
| 1091 | {
|
---|
| 1092 | pathFigure.IsClosed = false;
|
---|
| 1093 | pathFigure.IsFilled = true;
|
---|
| 1094 | geometry.Figures.Add(pathFigure);
|
---|
| 1095 | pathFigure = null;
|
---|
| 1096 | }
|
---|
| 1097 |
|
---|
| 1098 | lastPoint = initPoint = pathMoveTo.AbsXY;
|
---|
| 1099 |
|
---|
| 1100 | pathFigure = new PathFigure();
|
---|
| 1101 | pathFigure.StartPoint = new Point(initPoint.ValueX, initPoint.ValueY);
|
---|
| 1102 | }
|
---|
| 1103 | else if (DynamicCast.Cast(segment, out pathLineTo))
|
---|
| 1104 | {
|
---|
| 1105 | SvgPointF p = pathLineTo.AbsXY;
|
---|
| 1106 | pathFigure.Segments.Add(new LineSegment(new Point(p.ValueX, p.ValueY), true));
|
---|
| 1107 |
|
---|
| 1108 | lastPoint = p;
|
---|
| 1109 | }
|
---|
| 1110 | else if (DynamicCast.Cast(segment, out pathCurveTo))
|
---|
| 1111 | {
|
---|
| 1112 | SvgPointF xy = pathCurveTo.AbsXY;
|
---|
| 1113 | SvgPointF x1y1 = pathCurveTo.CubicX1Y1;
|
---|
| 1114 | SvgPointF x2y2 = pathCurveTo.CubicX2Y2;
|
---|
| 1115 | pathFigure.Segments.Add(new BezierSegment(new Point(x1y1.ValueX, x1y1.ValueY),
|
---|
| 1116 | new Point(x2y2.ValueX, x2y2.ValueY), new Point(xy.ValueX, xy.ValueY), true));
|
---|
| 1117 |
|
---|
| 1118 | lastPoint = xy;
|
---|
| 1119 | }
|
---|
| 1120 | else if (DynamicCast.Cast(segment, out pathArc))
|
---|
| 1121 | {
|
---|
| 1122 | SvgPointF p = pathArc.AbsXY;
|
---|
| 1123 | if (lastPoint.Equals(p))
|
---|
| 1124 | {
|
---|
| 1125 | // If the endpoints (x, y) and (x0, y0) are identical, then this
|
---|
| 1126 | // is equivalent to omitting the elliptical arc segment entirely.
|
---|
| 1127 | }
|
---|
| 1128 | else if (pathArc.R1 == 0 || pathArc.R2 == 0)
|
---|
| 1129 | {
|
---|
| 1130 | // Ensure radii are valid
|
---|
| 1131 | pathFigure.Segments.Add(new LineSegment(new Point(p.ValueX, p.ValueY), true));
|
---|
| 1132 | }
|
---|
| 1133 | else
|
---|
| 1134 | {
|
---|
| 1135 | CalculatedArcValues calcValues = pathArc.GetCalculatedArcValues();
|
---|
| 1136 |
|
---|
| 1137 | pathFigure.Segments.Add(new ArcSegment(new Point(p.ValueX, p.ValueY),
|
---|
| 1138 | new Size(pathArc.R1, pathArc.R2), pathArc.Angle, pathArc.LargeArcFlag,
|
---|
| 1139 | pathArc.SweepFlag ? SweepDirection.Clockwise : SweepDirection.Counterclockwise,
|
---|
| 1140 | true));
|
---|
| 1141 | }
|
---|
| 1142 |
|
---|
| 1143 | lastPoint = p;
|
---|
| 1144 | }
|
---|
| 1145 | else if (segment is SvgPathSegClosePath)
|
---|
| 1146 | {
|
---|
| 1147 | if (pathFigure != null)
|
---|
| 1148 | {
|
---|
| 1149 | pathFigure.IsClosed = true;
|
---|
| 1150 | pathFigure.IsFilled = true;
|
---|
| 1151 | geometry.Figures.Add(pathFigure);
|
---|
| 1152 | pathFigure = null;
|
---|
| 1153 | }
|
---|
| 1154 |
|
---|
| 1155 | lastPoint = initPoint;
|
---|
| 1156 | }
|
---|
| 1157 | }
|
---|
| 1158 |
|
---|
| 1159 | if (pathFigure != null)
|
---|
| 1160 | {
|
---|
| 1161 | pathFigure.IsClosed = false;
|
---|
| 1162 | pathFigure.IsFilled = true;
|
---|
| 1163 | geometry.Figures.Add(pathFigure);
|
---|
| 1164 | }
|
---|
| 1165 |
|
---|
| 1166 | return geometry;
|
---|
| 1167 | }
|
---|
| 1168 |
|
---|
| 1169 | #endregion
|
---|
| 1170 |
|
---|
| 1171 | #region SvgCircleElement Geometry
|
---|
| 1172 |
|
---|
| 1173 | public static Geometry CreateGeometry(SvgCircleElement element)
|
---|
| 1174 | {
|
---|
| 1175 | double _cx = Math.Round(element.Cx.AnimVal.Value, 4);
|
---|
| 1176 | double _cy = Math.Round(element.Cy.AnimVal.Value, 4);
|
---|
| 1177 | double _r = Math.Round(element.R.AnimVal.Value, 4);
|
---|
| 1178 |
|
---|
| 1179 | if (_r <= 0)
|
---|
| 1180 | {
|
---|
| 1181 | return null;
|
---|
| 1182 | }
|
---|
| 1183 |
|
---|
| 1184 | EllipseGeometry geometry = new EllipseGeometry(new Point(_cx, _cy), _r, _r);
|
---|
| 1185 |
|
---|
| 1186 | return geometry;
|
---|
| 1187 | }
|
---|
| 1188 |
|
---|
| 1189 | #endregion
|
---|
| 1190 |
|
---|
| 1191 | #region SvgPolylineElement Geometry
|
---|
| 1192 |
|
---|
| 1193 | public static Geometry CreateGeometry(SvgPolylineElement element)
|
---|
| 1194 | {
|
---|
| 1195 | ISvgPointList list = element.AnimatedPoints;
|
---|
| 1196 | ulong nElems = list.NumberOfItems;
|
---|
| 1197 | if (nElems == 0)
|
---|
| 1198 | {
|
---|
| 1199 | return null;
|
---|
| 1200 | }
|
---|
| 1201 |
|
---|
| 1202 | PointCollection points = new PointCollection((int)nElems);
|
---|
| 1203 |
|
---|
| 1204 | for (uint i = 0; i < nElems; i++)
|
---|
| 1205 | {
|
---|
| 1206 | ISvgPoint point = list.GetItem(i);
|
---|
| 1207 | points.Add(new Point(Math.Round(point.X, 4), Math.Round(point.Y, 4)));
|
---|
| 1208 | }
|
---|
| 1209 | PolyLineSegment polyline = new PolyLineSegment();
|
---|
| 1210 | polyline.Points = points;
|
---|
| 1211 |
|
---|
| 1212 | PathFigure polylineFigure = new PathFigure();
|
---|
| 1213 | polylineFigure.StartPoint = points[0];
|
---|
| 1214 | polylineFigure.IsClosed = false;
|
---|
| 1215 | polylineFigure.IsFilled = true;
|
---|
| 1216 |
|
---|
| 1217 | polylineFigure.Segments.Add(polyline);
|
---|
| 1218 |
|
---|
| 1219 | PathGeometry geometry = new PathGeometry();
|
---|
| 1220 |
|
---|
| 1221 | string fillRule = element.GetPropertyValue("fill-rule");
|
---|
| 1222 | string clipRule = element.GetAttribute("clip-rule");
|
---|
| 1223 | if (!String.IsNullOrEmpty(clipRule) &&
|
---|
| 1224 | String.Equals(clipRule, "evenodd") || String.Equals(clipRule, "nonzero"))
|
---|
| 1225 | {
|
---|
| 1226 | fillRule = clipRule;
|
---|
| 1227 | }
|
---|
| 1228 | if (fillRule == "evenodd")
|
---|
| 1229 | geometry.FillRule = FillRule.EvenOdd;
|
---|
| 1230 | else if (fillRule == "nonzero")
|
---|
| 1231 | geometry.FillRule = FillRule.Nonzero;
|
---|
| 1232 |
|
---|
| 1233 | geometry.Figures.Add(polylineFigure);
|
---|
| 1234 |
|
---|
| 1235 | return geometry;
|
---|
| 1236 | }
|
---|
| 1237 |
|
---|
| 1238 | #endregion
|
---|
| 1239 |
|
---|
| 1240 | #region SvgPolygonElement Geometry
|
---|
| 1241 |
|
---|
| 1242 | public static Geometry CreateGeometry(SvgPolygonElement element)
|
---|
| 1243 | {
|
---|
| 1244 | ISvgPointList list = element.AnimatedPoints;
|
---|
| 1245 | ulong nElems = list.NumberOfItems;
|
---|
| 1246 | if (nElems == 0)
|
---|
| 1247 | {
|
---|
| 1248 | return null;
|
---|
| 1249 | }
|
---|
| 1250 |
|
---|
| 1251 | PointCollection points = new PointCollection((int)nElems);
|
---|
| 1252 |
|
---|
| 1253 | for (uint i = 0; i < nElems; i++)
|
---|
| 1254 | {
|
---|
| 1255 | ISvgPoint point = list.GetItem(i);
|
---|
| 1256 | points.Add(new Point(Math.Round(point.X, 4), Math.Round(point.Y, 4)));
|
---|
| 1257 | }
|
---|
| 1258 |
|
---|
| 1259 | PolyLineSegment polyline = new PolyLineSegment();
|
---|
| 1260 | polyline.Points = points;
|
---|
| 1261 |
|
---|
| 1262 | PathFigure polylineFigure = new PathFigure();
|
---|
| 1263 | polylineFigure.StartPoint = points[0];
|
---|
| 1264 | polylineFigure.IsClosed = true;
|
---|
| 1265 | polylineFigure.IsFilled = true;
|
---|
| 1266 |
|
---|
| 1267 | polylineFigure.Segments.Add(polyline);
|
---|
| 1268 |
|
---|
| 1269 | PathGeometry geometry = new PathGeometry();
|
---|
| 1270 |
|
---|
| 1271 | string fillRule = element.GetPropertyValue("fill-rule");
|
---|
| 1272 | string clipRule = element.GetAttribute("clip-rule");
|
---|
| 1273 | if (!String.IsNullOrEmpty(clipRule) &&
|
---|
| 1274 | String.Equals(clipRule, "evenodd") || String.Equals(clipRule, "nonzero"))
|
---|
| 1275 | {
|
---|
| 1276 | fillRule = clipRule;
|
---|
| 1277 | }
|
---|
| 1278 | if (fillRule == "evenodd")
|
---|
| 1279 | geometry.FillRule = FillRule.EvenOdd;
|
---|
| 1280 | else if (fillRule == "nonzero")
|
---|
| 1281 | geometry.FillRule = FillRule.Nonzero;
|
---|
| 1282 |
|
---|
| 1283 | geometry.Figures.Add(polylineFigure);
|
---|
| 1284 |
|
---|
| 1285 | return geometry;
|
---|
| 1286 | }
|
---|
| 1287 |
|
---|
| 1288 | #endregion
|
---|
| 1289 |
|
---|
| 1290 | #endregion
|
---|
| 1291 |
|
---|
| 1292 | #region Marker Methods
|
---|
| 1293 |
|
---|
| 1294 | protected static string ExtractMarkerUrl(string propValue)
|
---|
| 1295 | {
|
---|
| 1296 | Match match = _reUrl.Match(propValue);
|
---|
| 1297 | if (match.Success)
|
---|
| 1298 | {
|
---|
| 1299 | return match.Groups["uri"].Value;
|
---|
| 1300 | }
|
---|
| 1301 | else
|
---|
| 1302 | {
|
---|
| 1303 | return String.Empty;
|
---|
| 1304 | }
|
---|
| 1305 | }
|
---|
| 1306 |
|
---|
| 1307 | protected static void RenderMarkers(WpfDrawingRenderer renderer,
|
---|
| 1308 | SvgStyleableElement styleElm, WpfDrawingContext gr)
|
---|
| 1309 | {
|
---|
| 1310 | // OPTIMIZE
|
---|
| 1311 |
|
---|
| 1312 | if (styleElm is ISharpMarkerHost)
|
---|
| 1313 | {
|
---|
| 1314 | string markerStartUrl = ExtractMarkerUrl(styleElm.GetPropertyValue("marker-start", "marker"));
|
---|
| 1315 | string markerMiddleUrl = ExtractMarkerUrl(styleElm.GetPropertyValue("marker-mid", "marker"));
|
---|
| 1316 | string markerEndUrl = ExtractMarkerUrl(styleElm.GetPropertyValue("marker-end", "marker"));
|
---|
| 1317 |
|
---|
| 1318 | if (markerStartUrl.Length > 0)
|
---|
| 1319 | {
|
---|
| 1320 | WpfMarkerRendering markerRenderer = CreateByUri(styleElm.OwnerDocument,
|
---|
| 1321 | styleElm.BaseURI, markerStartUrl) as WpfMarkerRendering;
|
---|
| 1322 | if (markerRenderer != null)
|
---|
| 1323 | {
|
---|
| 1324 | markerRenderer.RenderMarker(renderer, gr, SvgMarkerPosition.Start, styleElm);
|
---|
| 1325 | }
|
---|
| 1326 | }
|
---|
| 1327 |
|
---|
| 1328 | if (markerMiddleUrl.Length > 0)
|
---|
| 1329 | {
|
---|
| 1330 | // TODO markerMiddleUrl != markerStartUrl
|
---|
| 1331 | WpfMarkerRendering markerRenderer = CreateByUri(styleElm.OwnerDocument,
|
---|
| 1332 | styleElm.BaseURI, markerMiddleUrl) as WpfMarkerRendering;
|
---|
| 1333 | if (markerRenderer != null)
|
---|
| 1334 | {
|
---|
| 1335 | markerRenderer.RenderMarker(renderer, gr, SvgMarkerPosition.Mid, styleElm);
|
---|
| 1336 | }
|
---|
| 1337 | }
|
---|
| 1338 |
|
---|
| 1339 | if (markerEndUrl.Length > 0)
|
---|
| 1340 | {
|
---|
| 1341 | // TODO: markerEndUrl != markerMiddleUrl
|
---|
| 1342 | WpfMarkerRendering markerRenderer = CreateByUri(styleElm.OwnerDocument,
|
---|
| 1343 | styleElm.BaseURI, markerEndUrl) as WpfMarkerRendering;
|
---|
| 1344 | if (markerRenderer != null)
|
---|
| 1345 | {
|
---|
| 1346 | markerRenderer.RenderMarker(renderer, gr, SvgMarkerPosition.End, styleElm);
|
---|
| 1347 | }
|
---|
| 1348 | }
|
---|
| 1349 | }
|
---|
| 1350 | }
|
---|
| 1351 |
|
---|
| 1352 | #endregion
|
---|
| 1353 |
|
---|
| 1354 | #region IDisposable Members
|
---|
| 1355 |
|
---|
| 1356 | protected override void Dispose(bool disposing)
|
---|
| 1357 | {
|
---|
| 1358 | base.Dispose(disposing);
|
---|
| 1359 | }
|
---|
| 1360 |
|
---|
| 1361 | #endregion
|
---|
| 1362 | }
|
---|
| 1363 | }
|
---|