diff --git a/Nuget/Svg.1.6.0.nupkg b/Nuget/Svg.1.6.0.nupkg new file mode 100644 index 0000000000000000000000000000000000000000..63a200422789d95b8ff288a58b354d7e85c02e27 Binary files /dev/null and b/Nuget/Svg.1.6.0.nupkg differ diff --git a/Nuget/Svg.1.6.1.nupkg b/Nuget/Svg.1.6.1.nupkg new file mode 100644 index 0000000000000000000000000000000000000000..d99f0e41f500c7b5aa496830bcc55f668a0bab8b Binary files /dev/null and b/Nuget/Svg.1.6.1.nupkg differ diff --git a/Nuget/Svg.1.7.0.nupkg b/Nuget/Svg.1.7.0.nupkg new file mode 100644 index 0000000000000000000000000000000000000000..d59e62ee00eb8a22b60638eec0806730ce698cf1 Binary files /dev/null and b/Nuget/Svg.1.7.0.nupkg differ diff --git a/Nuget/Svg.nuspec b/Nuget/Svg.nuspec new file mode 100644 index 0000000000000000000000000000000000000000..15077fa99c69f1e870ba0d73a8d073a900b36b52 --- /dev/null +++ b/Nuget/Svg.nuspec @@ -0,0 +1,34 @@ + + + + Svg + $version$ + SVG Rendering Library + davescriven,jvenema,owaits,ddpruitt,Ralf1108,Tebjan Halm,and others + vvvv.org + http://opensource.org/licenses/MS-PL.html + https://github.com/vvvv/SVG + true + Public fork of the C# SVG rendering library on codeplex: https://svg.codeplex.com/ + +This started out as a minor modification to enable the writing of proper SVG strings. But now after almost two years we have so many fixes and improvements that we decided to share our current codebase to the public in order to improve it even further. + +So please feel free to fork it and open pull requests for any fix, improvement or feature you add. + +License: Microsoft Public License: https://svg.codeplex.com/license + Open source library to load/save and render SVG vector graphics. + merged github pull requests + svg, vector graphics, rendering + + + + + + + + + + + + + \ No newline at end of file diff --git a/Source/DataTypes/SvgAspectRatio.cs b/Source/DataTypes/SvgAspectRatio.cs index f44e4f7d1cc3d0676030e2e6b5d7e6049887025b..77ae817adac6f154100000e244d9ff7ca8477da7 100644 --- a/Source/DataTypes/SvgAspectRatio.cs +++ b/Source/DataTypes/SvgAspectRatio.cs @@ -1,4 +1,4 @@ -using System; +using Svg.DataTypes; using System.ComponentModel; namespace Svg @@ -6,9 +6,10 @@ namespace Svg /// /// Description of SvgAspectRatio. /// + [TypeConverter(typeof(SvgPreserveAspectRatioConverter))] public class SvgAspectRatio { - public SvgAspectRatio() + public SvgAspectRatio() : this(SvgPreserveAspectRatio.none) { } @@ -21,6 +22,7 @@ namespace Svg { this.Align = align; this.Slice = slice; + this.Defer = false; } public SvgPreserveAspectRatio Align @@ -34,7 +36,13 @@ namespace Svg get; set; } - + + public bool Defer + { + get; + set; + } + public override string ToString() { return TypeDescriptor.GetConverter(typeof(SvgPreserveAspectRatio)).ConvertToString(this.Align) + (Slice ? " slice" : ""); @@ -42,18 +50,17 @@ namespace Svg } - [TypeConverter(typeof(SvgPreserverAspectRatioConverter))] public enum SvgPreserveAspectRatio { - XMidYMid, //default - None, - XMinYMin, - XMidYMin, - XMaxYMin, - XMinYMid, - XMaxYMid, - XMinYMax, - XMidYMax, - XMaxYMax + xMidYMid, //default + none, + xMinYMin, + xMidYMin, + xMaxYMin, + xMinYMid, + xMaxYMid, + xMinYMax, + xMidYMax, + xMaxYMax } } diff --git a/Source/DataTypes/SvgAspectRatioConverter.cs b/Source/DataTypes/SvgAspectRatioConverter.cs new file mode 100644 index 0000000000000000000000000000000000000000..b7bf8e4b3119d1aa866c37618b44f21116eb6b85 --- /dev/null +++ b/Source/DataTypes/SvgAspectRatioConverter.cs @@ -0,0 +1,93 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Svg.DataTypes +{ + + //implementaton for preserve aspect ratio + public sealed class SvgPreserveAspectRatioConverter : TypeConverter + { + public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) + { + if (value == null) + { + return new SvgAspectRatio(); + } + + if (!(value is string)) + { + throw new ArgumentOutOfRangeException("value must be a string."); + } + + SvgPreserveAspectRatio eAlign = SvgPreserveAspectRatio.none; + bool bDefer = false; + bool bSlice = false; + + string[] sParts = (value as string).Split(new char[] {' '}, StringSplitOptions.RemoveEmptyEntries); + int nAlignIndex = 0; + if (sParts[0].Equals("defer")) + { + bDefer = true; + nAlignIndex++; + if(sParts.Length < 2) + throw new ArgumentOutOfRangeException("value is not a member of SvgPreserveAspectRatio"); + } + + if (!Enum.TryParse(sParts[nAlignIndex], out eAlign)) + throw new ArgumentOutOfRangeException("value is not a member of SvgPreserveAspectRatio"); + nAlignIndex++; + + if (sParts.Length > nAlignIndex) + { + switch (sParts[nAlignIndex]) + { + case "meet": + break; + case "slice": + bSlice = true; + break; + default: + throw new ArgumentOutOfRangeException("value is not a member of SvgPreserveAspectRatio"); + } + } + nAlignIndex++; + if(sParts.Length > nAlignIndex) + throw new ArgumentOutOfRangeException("value is not a member of SvgPreserveAspectRatio"); + + SvgAspectRatio pRet = new SvgAspectRatio(eAlign); + pRet.Slice = bSlice; + pRet.Defer = bDefer; + return (pRet); + } + + public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) + { + if (sourceType == typeof(string)) + { + return true; + } + + return base.CanConvertFrom(context, sourceType); + } + + public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) + { + if (destinationType == typeof(string)) + { + return true; + } + + return base.CanConvertTo(context, destinationType); + } + + public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) + { + return base.ConvertTo(context, culture, value, destinationType); + } + } +} diff --git a/Source/DataTypes/SvgMarkerUnits.cs b/Source/DataTypes/SvgMarkerUnits.cs index e876dd5d74bf2b9ee449c04c4d993a2603157628..9b0aa7869e57b88675b725cd341b739735583caf 100644 --- a/Source/DataTypes/SvgMarkerUnits.cs +++ b/Source/DataTypes/SvgMarkerUnits.cs @@ -1,13 +1,11 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +using System.ComponentModel; -namespace Svg +namespace Svg.DataTypes { - public enum SvgMarkerUnits - { - strokeWidth, - userSpaceOnUse - } + [TypeConverter(typeof(SvgMarkerUnitsConverter))] + public enum SvgMarkerUnits + { + strokeWidth, + userSpaceOnUse + } } diff --git a/Source/DataTypes/SvgOrient.cs b/Source/DataTypes/SvgOrient.cs index 8dd07d810022c962b176f098e3b039ca88f62a0f..e3fd1705b82956b3441c6638d332a325745e2d89 100644 --- a/Source/DataTypes/SvgOrient.cs +++ b/Source/DataTypes/SvgOrient.cs @@ -1,9 +1,5 @@ -using System; -using System.Collections.Generic; -using System.Text; +using Svg.DataTypes; using System.ComponentModel; -using System.Web.UI.WebControls; -using System.Globalization; namespace Svg { diff --git a/Source/Document Structure/SvgFragment.cs b/Source/Document Structure/SvgFragment.cs index a9fd3ee1b184e149239778e7fab0d92843f8a652..fabe78190ad8ea3af4ba497852ae699683ef1eff 100644 --- a/Source/Document Structure/SvgFragment.cs +++ b/Source/Document Structure/SvgFragment.cs @@ -100,11 +100,11 @@ namespace Svg /// Gets or sets the aspect of the viewport. /// /// - [SvgAttribute("preserveAspectRatio")] + [SvgAttribute("preserveAspectRatio")] public SvgAspectRatio AspectRatio { - get {return this.Attributes.GetAttribute("preserveAspectRatio"); } - set { this.Attributes["preserveAspectRatio"] = value; } + get { return this.Attributes.GetAttribute("preserveAspectRatio"); } + set { this.Attributes["preserveAspectRatio"] = value; } } /// @@ -117,10 +117,60 @@ namespace Svg if (!this.ViewBox.Equals(SvgViewBox.Empty)) { - renderer.TranslateTransform(_x, _y, MatrixOrder.Append); - renderer.TranslateTransform(-this.ViewBox.MinX, -this.ViewBox.MinY, MatrixOrder.Append); + float fScaleX = this.Width.ToDeviceValue() / this.ViewBox.Width; + float fScaleY = this.Height.ToDeviceValue() / this.ViewBox.Height; + float fMinX = -this.ViewBox.MinX; + float fMinY = -this.ViewBox.MinY; + + if (AspectRatio.Align != SvgPreserveAspectRatio.none) + { + fScaleX = Math.Min(fScaleX, fScaleY); + fScaleY = Math.Min(fScaleX, fScaleY); + float fViewMidX = (this.ViewBox.Width / 2) * fScaleX; + float fViewMidY = (this.ViewBox.Height / 2) * fScaleY; + float fMidX = this.Width.ToDeviceValue() / 2; + float fMidY = this.Height.ToDeviceValue() / 2; - renderer.ScaleTransform(this.Width.ToDeviceValue() / this.ViewBox.Width, this.Height.ToDeviceValue() / this.ViewBox.Height, MatrixOrder.Append); + switch (AspectRatio.Align) + { + case SvgPreserveAspectRatio.xMinYMin: + break; + case SvgPreserveAspectRatio.xMidYMin: + fMinX += (fMidX - fViewMidX) / fScaleX; + break; + case SvgPreserveAspectRatio.xMaxYMin: + fMinX += this.ViewBox.Width - this.Width.ToDeviceValue(); + break; + case SvgPreserveAspectRatio.xMinYMid: + fMinY += (fMidY - fViewMidY) / fScaleY; + break; + case SvgPreserveAspectRatio.xMidYMid: + fMinX += (fMidX - fViewMidX) / fScaleX; + fMinY += (fMidY - fViewMidY) / fScaleY; + break; + case SvgPreserveAspectRatio.xMaxYMid: + fMinX += this.ViewBox.Width - this.Width.ToDeviceValue(); + fMinY += (fMidY - fViewMidY) / fScaleY; + break; + case SvgPreserveAspectRatio.xMinYMax: + fMinY += this.ViewBox.Height - this.Height.ToDeviceValue(); + break; + case SvgPreserveAspectRatio.xMidYMax: + fMinX += (fMidX - fViewMidX) / fScaleX; + fMinY += this.ViewBox.Height - this.Height.ToDeviceValue(); + break; + case SvgPreserveAspectRatio.xMaxYMax: + fMinX += this.ViewBox.Width - this.Width.ToDeviceValue(); + fMinY += this.ViewBox.Height - this.Height.ToDeviceValue(); + break; + default: + break; + } + } + + renderer.TranslateTransform(_x, _y, MatrixOrder.Append); + renderer.TranslateTransform(fMinX, fMinY, MatrixOrder.Append); + renderer.ScaleTransform(fScaleX, fScaleY, MatrixOrder.Append); } } @@ -162,7 +212,7 @@ namespace Svg this.Height = new SvgUnit(SvgUnitType.Percentage, 100.0f); this.Width = new SvgUnit(SvgUnitType.Percentage, 100.0f); this.ViewBox = SvgViewBox.Empty; - this.AspectRatio = new SvgAspectRatio(SvgPreserveAspectRatio.None); + this.AspectRatio = new SvgAspectRatio(SvgPreserveAspectRatio.xMidYMid); } diff --git a/Source/Painting/EnumConverters.cs b/Source/Painting/EnumConverters.cs index f4780d11e8ff760c994ab6e1c9e3dcb5ced792ef..a13ae9fb74fa67fa8fc94b4c39ed135d4812c0fd 100644 --- a/Source/Painting/EnumConverters.cs +++ b/Source/Painting/EnumConverters.cs @@ -1,4 +1,5 @@ -using System; +using Svg.DataTypes; +using System; using System.ComponentModel; using System.Globalization; @@ -108,11 +109,6 @@ namespace Svg { } - //implementaton for preserve aspect ratio - public sealed class SvgPreserverAspectRatioConverter : EnumBaseConverter - { - } - public sealed class SvgStrokeLineCapConverter : EnumBaseConverter { } @@ -120,5 +116,8 @@ namespace Svg public sealed class SvgStrokeLineJoinConverter : EnumBaseConverter { } - + + public sealed class SvgMarkerUnitsConverter : EnumBaseConverter + { + } } diff --git a/Source/Painting/SvgMarker.cs b/Source/Painting/SvgMarker.cs index bf7f2143e8207ea5000f27721922eda3ed1649f2..1c9ec5d6aefeb9c36bc7348c00f02668988568d7 100644 --- a/Source/Painting/SvgMarker.cs +++ b/Source/Painting/SvgMarker.cs @@ -6,6 +6,8 @@ using System.Web; using System.Xml; using System.Xml.Serialization; using System.Drawing.Drawing2D; +using System.Drawing; +using Svg.DataTypes; namespace Svg { @@ -69,6 +71,35 @@ namespace Svg } + [SvgAttribute("markerWidth")] + public virtual SvgUnit MarkerWidth + { + get { return this.Attributes.GetAttribute("markerWidth"); } + set { this.Attributes["markerWidth"] = value; } + } + + [SvgAttribute("markerHeight")] + public virtual SvgUnit MarkerHeight + { + get { return this.Attributes.GetAttribute("markerHeight"); } + set { this.Attributes["markerHeight"] = value; } + } + + [SvgAttribute("markerUnits")] + public virtual SvgMarkerUnits MarkerUnits + { + get { return this.Attributes.GetAttribute("markerUnits"); } + set { this.Attributes["markerUnits"] = value; } + } + + public SvgMarker() + { + MarkerUnits = SvgMarkerUnits.strokeWidth; + MarkerHeight = 3; + MarkerWidth = 3; + Overflow = SvgOverflow.hidden; + } + public override System.Drawing.Drawing2D.GraphicsPath Path { get @@ -95,19 +126,6 @@ namespace Svg } } - //protected internal override void RenderStroke(SvgRenderer renderer) - //{ - // this.PushTransforms(renderer); - - // SvgElement parent = element._parent; - // element._parent = this; - // element.RenderElement(renderer); - // element._parent = parent; - - // this.PopTransforms(renderer); - //} - - public override SvgElement DeepCopy() { return DeepCopy(); @@ -125,5 +143,148 @@ namespace Svg return newObj; } - } + + /// + /// Render this marker using the slope of the given line segment + /// + /// + /// + /// + /// + public void RenderMarker(SvgRenderer pRenderer, SvgPath pOwner, PointF pRefPoint, PointF pMarkerPoint1, PointF pMarkerPoint2) + { + float xDiff = pMarkerPoint2.X - pMarkerPoint1.X; + float yDiff = pMarkerPoint2.Y - pMarkerPoint1.Y; + float fAngle1 = (float)(Math.Atan2(yDiff, xDiff) * 180.0 / Math.PI); + + RenderPart2(fAngle1, pRenderer, pOwner, pRefPoint); + } + + /// + /// Render this marker using the average of the slopes of the two given line segments + /// + /// + /// + /// + /// + /// + public void RenderMarker(SvgRenderer pRenderer, SvgPath pOwner, PointF pRefPoint, PointF pMarkerPoint1, PointF pMarkerPoint2, PointF pMarkerPoint3) + { + float xDiff = pMarkerPoint2.X - pMarkerPoint1.X; + float yDiff = pMarkerPoint2.Y - pMarkerPoint1.Y; + float fAngle1 = (float)(Math.Atan2(yDiff, xDiff) * 180.0 / Math.PI); + + xDiff = pMarkerPoint3.X - pMarkerPoint2.X; + yDiff = pMarkerPoint3.Y - pMarkerPoint2.Y; + float fAngle2 = (float)(Math.Atan2(yDiff, xDiff) * 180.0 / Math.PI); + + RenderPart2((fAngle1 + fAngle2) / 2, pRenderer, pOwner, pRefPoint); + } + + /// + /// Common code for rendering a marker once the orientation angle has been calculated + /// + /// + /// + /// + /// + private void RenderPart2(float fAngle, SvgRenderer pRenderer, SvgPath pOwner, PointF pMarkerPoint) + { + Pen pRenderPen = CreatePen(pOwner); + + GraphicsPath markerPath = GetClone(pOwner); + + Matrix transMatrix = new Matrix(); + transMatrix.Translate(pMarkerPoint.X, pMarkerPoint.Y); + if (Orient.IsAuto) + transMatrix.Rotate(fAngle); + else + transMatrix.Rotate(Orient.Angle); + switch (MarkerUnits) + { + case SvgMarkerUnits.strokeWidth: + transMatrix.Translate(AdjustForViewBoxWidth(-RefX * pOwner.StrokeWidth), AdjustForViewBoxHeight(-RefY * pOwner.StrokeWidth)); + break; + case SvgMarkerUnits.userSpaceOnUse: + transMatrix.Translate(-RefX, -RefY); + break; + } + markerPath.Transform(transMatrix); + pRenderer.DrawPath(pRenderPen, markerPath); + + SvgPaintServer pFill = Fill; + SvgFillRule pFillRule = FillRule; // TODO: What do we use the fill rule for? + float fOpacity = FillOpacity; + + if (pFill != null) + { + Brush pBrush = pFill.GetBrush(this, fOpacity); + pRenderer.FillPath(pBrush, markerPath); + pBrush.Dispose(); + } + pRenderPen.Dispose(); + markerPath.Dispose(); + transMatrix.Dispose(); + } + + /// + /// Create a pen that can be used to render this marker + /// + /// + /// + private Pen CreatePen(SvgPath pPath) + { + Brush pBrush = pPath.Stroke.GetBrush(this, Opacity); + switch (MarkerUnits) + { + case SvgMarkerUnits.strokeWidth: + return (new Pen(pBrush, StrokeWidth * pPath.StrokeWidth)); + case SvgMarkerUnits.userSpaceOnUse: + return (new Pen(pBrush, StrokeWidth)); + } + return (new Pen(pBrush, StrokeWidth)); + } + + /// + /// Get a clone of the current path, scaled for the stroke with + /// + /// + private GraphicsPath GetClone(SvgPath pPath) + { + GraphicsPath pRet = Path.Clone() as GraphicsPath; + switch (MarkerUnits) + { + case SvgMarkerUnits.strokeWidth: + Matrix transMatrix = new Matrix(); + transMatrix.Scale(AdjustForViewBoxWidth(pPath.StrokeWidth), AdjustForViewBoxHeight(pPath.StrokeWidth)); + pRet.Transform(transMatrix); + break; + case SvgMarkerUnits.userSpaceOnUse: + break; + } + return (pRet); + } + + /// + /// Adjust the given value to account for the width of the viewbox in the viewport + /// + /// + /// + private float AdjustForViewBoxWidth(float fWidth) + { + // TODO: We know this isn't correct + return (fWidth / ViewBox.Width); + } + + /// + /// Adjust the given value to account for the height of the viewbox in the viewport + /// + /// + /// + private float AdjustForViewBoxHeight(float fHeight) + { + // TODO: We know this isn't correct + return (fHeight / ViewBox.Height); + } + } } \ No newline at end of file diff --git a/Source/Paths/SvgPath.cs b/Source/Paths/SvgPath.cs index a78ba08c2a1e9919cf84021ef5147c88f276e329..e6e9b13cf54567f58f980fb87eab567325e2ff41 100644 --- a/Source/Paths/SvgPath.cs +++ b/Source/Paths/SvgPath.cs @@ -27,12 +27,12 @@ namespace Svg public SvgPathSegmentList PathData { get { return this.Attributes.GetAttribute("d"); } - set - { - this.Attributes["d"] = value; - value._owner = this; - this.IsPathDirty = true; - } + set + { + this.Attributes["d"] = value; + value._owner = this; + this.IsPathDirty = true; + } } /// @@ -41,7 +41,7 @@ namespace Svg [SvgAttribute("pathLength")] public int PathLength { - get { return this.Attributes.GetAttribute("pathLength"); } + get { return this.Attributes.GetAttribute("pathLength"); } set { this.Attributes["pathLength"] = value; } } @@ -49,23 +49,34 @@ namespace Svg /// /// Gets or sets the marker (end cap) of the path. /// - [SvgAttribute("marker-end")] - public Uri MarkerEnd + [SvgAttribute("marker-end")] + public Uri MarkerEnd { - get { return this.Attributes.GetAttribute("marker-end"); } - set { this.Attributes["marker-end"] = value; } - } + get { return this.Attributes.GetAttribute("marker-end"); } + set { this.Attributes["marker-end"] = value; } + } - /// - /// Gets or sets the marker (start cap) of the path. - /// - [SvgAttribute("marker-start")] - public Uri MarkerStart - { - get { return this.Attributes.GetAttribute("marker-start"); } - set { this.Attributes["marker-start"] = value; } - } + /// + /// Gets or sets the marker (start cap) of the path. + /// + [SvgAttribute("marker-mid")] + public Uri MarkerMid + { + get { return this.Attributes.GetAttribute("marker-mid"); } + set { this.Attributes["marker-mid"] = value; } + } + + + /// + /// Gets or sets the marker (start cap) of the path. + /// + [SvgAttribute("marker-start")] + public Uri MarkerStart + { + get { return this.Attributes.GetAttribute("marker-start"); } + set { this.Attributes["marker-start"] = value; } + } /// @@ -127,80 +138,61 @@ namespace Svg pathData._owner = this; } - /// - /// Renders the stroke of the to the specified - /// - /// The object to render to. - protected internal override void RenderStroke(SvgRenderer renderer) - { - if (this.Stroke != null) - { - float strokeWidth = this.StrokeWidth.ToDeviceValue(this); - using (var pen = new Pen(this.Stroke.GetBrush(this, this.StrokeOpacity), strokeWidth)) - { - if (this.StrokeDashArray != null && this.StrokeDashArray.Count > 0) - { - /* divide by stroke width - GDI behaviour that I don't quite understand yet.*/ - pen.DashPattern = this.StrokeDashArray.ConvertAll(u => u.Value / ((strokeWidth <= 0) ? 1 : strokeWidth)).ToArray(); - } - - if (this.MarkerStart != null) - { - var marker = this.OwnerDocument.GetElementById(this.MarkerStart.ToString()); - pen.CustomStartCap = CapFromMarker(marker, strokeWidth); - } - - if (this.MarkerEnd != null) - { - var marker = this.OwnerDocument.GetElementById(this.MarkerEnd.ToString()); - pen.CustomEndCap = CapFromMarker(marker, strokeWidth); - } - - renderer.DrawPath(pen, this.Path); - } - } - } - - private CustomLineCap CapFromMarker(SvgMarker marker, float strokeWidth) + /// + /// Renders the stroke of the to the specified + /// + /// The object to render to. + protected internal override void RenderStroke(SvgRenderer renderer) { - var markerPath = marker.Path.Clone() as GraphicsPath; - - var transMatrix = new Matrix(); - transMatrix.Translate(-1 * marker.RefX.ToDeviceValue(), -1 * marker.RefY.ToDeviceValue(), MatrixOrder.Append); - transMatrix.Rotate(90f, MatrixOrder.Append); - // With the current aliasing structure, 1px lines still render as 2px lines - if (strokeWidth < 2) - { - transMatrix.Scale(.5f, .5f, MatrixOrder.Append); - } - else if (marker.MarkerUnits == SvgMarkerUnits.userSpaceOnUse) + if (this.Stroke != null) { - transMatrix.Scale(1f / strokeWidth, 1f / strokeWidth, MatrixOrder.Append); - } - - markerPath.Transform(transMatrix); - return new CustomLineCap(markerPath, null); - } - - public override SvgElement DeepCopy() - { - return DeepCopy(); - } + float strokeWidth = this.StrokeWidth.ToDeviceValue(this); + using (Pen pen = new Pen(this.Stroke.GetBrush(this, this.StrokeOpacity), strokeWidth)) + { + if (this.StrokeDashArray != null && this.StrokeDashArray.Count > 0) + { + /* divide by stroke width - GDI behaviour that I don't quite understand yet.*/ + pen.DashPattern = this.StrokeDashArray.ConvertAll(u => u.Value / ((strokeWidth <= 0) ? 1 : strokeWidth)).ToArray(); + } - public override SvgElement DeepCopy() - { - var newObj = base.DeepCopy() as SvgPath; - foreach (var pathData in this.PathData) - newObj.PathData.Add(pathData.Clone()); - newObj.PathLength = this.PathLength; - newObj.MarkerStart = this.MarkerStart; - newObj.MarkerEnd = this.MarkerEnd; - return newObj; + renderer.DrawPath(pen, this.Path); - } + if (this.MarkerStart != null) + { + SvgMarker marker = this.OwnerDocument.GetElementById(this.MarkerStart.ToString()); + marker.RenderMarker(renderer, this, Path.PathPoints[0], Path.PathPoints[0], Path.PathPoints[1]); + } + if (this.MarkerMid != null) + { + SvgMarker marker = this.OwnerDocument.GetElementById(this.MarkerMid.ToString()); + for (int i = 1; i <= Path.PathPoints.Length - 2; i++) + marker.RenderMarker(renderer, this, Path.PathPoints[i], Path.PathPoints[i - 1], Path.PathPoints[i], Path.PathPoints[i + 1]); + } + if (this.MarkerEnd != null) + { + SvgMarker marker = this.OwnerDocument.GetElementById(this.MarkerEnd.ToString()); + marker.RenderMarker(renderer, this, Path.PathPoints[Path.PathPoints.Length - 1], Path.PathPoints[Path.PathPoints.Length - 2], Path.PathPoints[Path.PathPoints.Length - 1]); + } + } + } + } + public override SvgElement DeepCopy() + { + return DeepCopy(); + } + public override SvgElement DeepCopy() + { + var newObj = base.DeepCopy() as SvgPath; + foreach (var pathData in this.PathData) + newObj.PathData.Add(pathData.Clone()); + newObj.PathLength = this.PathLength; + newObj.MarkerStart = this.MarkerStart; + newObj.MarkerEnd = this.MarkerEnd; + return newObj; + } } } \ No newline at end of file diff --git a/Source/Properties/AssemblyInfo.cs b/Source/Properties/AssemblyInfo.cs index 12585a25d99e1138820fa68a5f5c3f22b40d435b..b4d5deda9e9d72324b62754d34011af8823a99b5 100644 --- a/Source/Properties/AssemblyInfo.cs +++ b/Source/Properties/AssemblyInfo.cs @@ -32,7 +32,7 @@ using System.Runtime.InteropServices; // // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("1.6.1.*")] +[assembly: AssemblyVersion("1.7.0.*")] //[assembly: AssemblyFileVersion("1.0.1.*")] [assembly: CLSCompliant(true)] diff --git a/Source/Svg.csproj b/Source/Svg.csproj index 612c4dedc0b1cf1a2c4ef422db2eda7334443452..d330f4ec6aaef790f63f8e8dd8760a56bf4a10aa 100644 --- a/Source/Svg.csproj +++ b/Source/Svg.csproj @@ -52,7 +52,7 @@ Full false - ..\..\vvvv\public\common\src\thirdparty\ + ..\..\vvvv\public\common\src\thirdparty\ TRACE;DEBUG;REFLECTION prompt 4 @@ -99,6 +99,7 @@ + diff --git a/Source/SvgDocument.cs b/Source/SvgDocument.cs index 9e40a681a9ebb52d93e532bbe14308ce7de12139..ce7fe22542dea5ba4ccacfb803651193383ee2e7 100644 --- a/Source/SvgDocument.cs +++ b/Source/SvgDocument.cs @@ -26,7 +26,7 @@ namespace Svg /// public SvgDocument() { - Ppi = 96; + Ppi = PointsPerInch; } /// @@ -250,6 +250,10 @@ namespace Svg case XmlNodeType.Text: value.Append(reader.Value); break; + case XmlNodeType.EntityReference: + reader.ResolveEntity(); + value.Append(reader.Value); + break; } } catch (Exception exc) @@ -413,4 +417,4 @@ namespace Svg } } -} \ No newline at end of file +} diff --git a/Source/SvgRenderer.cs b/Source/SvgRenderer.cs index 63568034ee1ee2248fccfb7c46d3873b23f5bf7c..83cf6958ef6046d62c4756589cf6bd91704564e6 100644 --- a/Source/SvgRenderer.cs +++ b/Source/SvgRenderer.cs @@ -72,6 +72,16 @@ namespace Svg this._innerGraphics.DrawPath(pen, path); } + public void RotateTransform(float fAngle, MatrixOrder order) + { + this._innerGraphics.RotateTransform(fAngle, order); + } + + public void RotateTransform(float fAngle) + { + this.RotateTransform(fAngle, MatrixOrder.Append); + } + public void TranslateTransform(float dx, float dy, MatrixOrder order) { this._innerGraphics.TranslateTransform(dx, dy, order);