diff --git a/SvgNet/SVGGraphics.cs b/SvgNet/SVGGraphics.cs index 22eb1b7..e4dad09 100644 --- a/SvgNet/SVGGraphics.cs +++ b/SvgNet/SVGGraphics.cs @@ -18,6 +18,7 @@ using System.IO; using System.Collections.Generic; using System.Linq; +using System.Text; namespace SvgNet.SvgGdi { @@ -1979,6 +1980,8 @@ public void DrawLines(Pen pen, Point[] points) DrawLines(pen, pts); } + + /// /// Implemented /// @@ -1989,86 +1992,15 @@ public void DrawLines(Pen pen, Point[] points) /// public void DrawPath(Pen pen, GraphicsPath path) { - //Save the original pen dash style in case we need to change it - DashStyle originalPenDashStyle = pen.DashStyle; - - GraphicsPathIterator subpaths = new GraphicsPathIterator(path); - GraphicsPath subpath = new GraphicsPath(path.FillMode); - subpaths.Rewind(); - - //Iterate through all the subpaths in the path. Each subpath will contain either - //lines or Bezier curves - for (int s = 0; s < subpaths.SubpathCount; s++) + foreach (SvgPath data in HandleGraphicsPath(path)) { - bool isClosed; - if (subpaths.NextSubpath(subpath, out isClosed) == 0) - { - continue; //go to next subpath if this one has zero points. - } - PointF start = new PointF(0, 0); - PointF origin = subpath.PathPoints[0]; - PointF last = subpath.PathPoints[subpath.PathPoints.Length - 1]; - int bezierCurvePointsIndex = 0; - PointF[] bezierCurvePoints = new PointF[4]; - for (int i = 0; i < subpath.PathPoints.Length; i++) - { - /* Each subpath point has a corresponding path point type which can be: - *The point starts the subpath - *The point is a line point - *The point is Bezier curve point - * Another point type like dash-mode - */ - switch ((PathPointType)subpath.PathTypes[i] & PathPointType.PathTypeMask) //Mask off non path-type types - { - case PathPointType.Start: - start = subpath.PathPoints[i]; - bezierCurvePoints[0] = subpath.PathPoints[i]; - bezierCurvePointsIndex = 1; - pen.DashStyle = originalPenDashStyle; //Reset pen dash mode to original when starting subpath - continue; - case PathPointType.Line: - DrawLine(pen, start, subpath.PathPoints[i]); //Draw a line segment ftom start point - start = subpath.PathPoints[i]; //Move start point to line end - bezierCurvePoints[0] = subpath.PathPoints[i]; //A line point can also be the start of a Bezier curve - bezierCurvePointsIndex = 1; - continue; - case PathPointType.Bezier3: - bezierCurvePoints[bezierCurvePointsIndex++] = subpath.PathPoints[i]; - if (bezierCurvePointsIndex == 4) //If 4 points including start have been found then draw the Bezier curve - { - DrawBezier(pen, bezierCurvePoints[0], bezierCurvePoints[1], bezierCurvePoints[2], bezierCurvePoints[3]); - bezierCurvePoints = new PointF[4]; - bezierCurvePoints[0] = subpath.PathPoints[i]; - bezierCurvePointsIndex = 1; - start = subpath.PathPoints[i]; //Move start point to curve end - } - continue; - default: - switch ((PathPointType)subpath.PathTypes[i]) - { - case PathPointType.DashMode: - pen.DashStyle = DashStyle.Dash; - continue; - default: - throw new SvgException("Unknown path type value: " + subpath.PathTypes[i]); - } - } - } - if (isClosed) //If the subpath is closed and it is a linear figure then draw the last connecting line segment - { - PathPointType originType = (PathPointType)subpath.PathTypes[0]; - PathPointType lastType = (PathPointType) subpath.PathTypes[subpath.PathPoints.Length - 1]; - - if (((lastType & PathPointType.PathTypeMask) == PathPointType.Line) && ((originType & PathPointType.PathTypeMask) == PathPointType.Line)) - { - DrawLine(pen, last, origin); - } - } - + SvgPathElement pathElement = new SvgPathElement(); + pathElement.Style = new SvgStyle(pen); + pathElement.D = data; + if (!_transforms.Result.IsIdentity) + pathElement.Transform = new SvgTransformList(_transforms.Result.Clone()); + _cur.AddChild(pathElement); } - subpath.Dispose(); - subpaths.Dispose(); - pen.DashStyle = originalPenDashStyle; } /// @@ -2355,33 +2287,15 @@ public void FillEllipse(Brush brush, Int32 x, Int32 y, Int32 width, Int32 height /// public void FillPath(Brush brush, GraphicsPath path) { - GraphicsPathIterator subpaths = new GraphicsPathIterator(path); - GraphicsPath subpath = new GraphicsPath(path.FillMode); - subpaths.Rewind(); - for (int s = 0; s < subpaths.SubpathCount; s++) + foreach (var svgPath in HandleGraphicsPath(path)) { - bool isClosed; - if (subpaths.NextSubpath(subpath, out isClosed) < 2) - { - continue; - } - if (!isClosed) - { - //subpath.CloseAllFigures(); - } - PathPointType lastType = (PathPointType)subpath.PathTypes[subpath.PathPoints.Length - 1]; - if (subpath.PathTypes.Any(pt => ((PathPointType) pt & PathPointType.PathTypeMask) == PathPointType.Line)) - { - FillPolygon(brush, subpath.PathPoints, path.FillMode); - } - else - { - FillBeziers(brush, subpath.PathPoints, path.FillMode); - } - + var pathElement = new SvgPathElement(); + pathElement.Style = HandleBrush(brush); + pathElement.D = svgPath; + if (!_transforms.Result.IsIdentity) + pathElement.Transform = new SvgTransformList(_transforms.Result.Clone()); + _cur.AddChild(pathElement); } - subpath.Dispose(); - subpaths.Dispose(); } /// @@ -3635,6 +3549,69 @@ private void FillBeziers(Brush brush, PointF[] points, FillMode fillmode) _cur.AddChild(bez); } + private IEnumerable HandleGraphicsPath(GraphicsPath path) + { + StringBuilder pathBuilder = new StringBuilder(); + using (GraphicsPathIterator subpaths = new GraphicsPathIterator(path)) + using (GraphicsPath subpath = new GraphicsPath(path.FillMode)) + { + subpaths.Rewind(); + + //Iterate through all the subpaths in the path. Each subpath will contain either + //lines or Bezier curves + for (int s = 0; s < subpaths.SubpathCount; s++) + { + bool isClosed; + if (subpaths.NextSubpath(subpath, out isClosed) == 0) + { + continue; //go to next subpath if this one has zero points. + } + + PathPointType lastType = PathPointType.Start; + for (int i = 0; i < subpath.PathPoints.Length; i++) + { + /* Each subpath point has a corresponding path point type which can be: + *The point starts the subpath + *The point is a line point + *The point is Bezier curve point + */ + PointF point = subpath.PathPoints[i]; + PathPointType pathType = (PathPointType)subpath.PathTypes[i] & PathPointType.PathTypeMask; + switch (pathType) //Mask off non path-type types + { + case PathPointType.Start: + //Move to start point + pathBuilder.AppendFormat(CultureInfo.InvariantCulture, "M {0},{1}", point.X, point.Y); + break; + case PathPointType.Line: + // Draw line to current point + if (lastType != PathPointType.Line) pathBuilder.Append(" L"); + pathBuilder.AppendFormat(CultureInfo.InvariantCulture, " {0},{1}", point.X, point.Y); + break; + case PathPointType.Bezier3: + // Draw curve to current point + if (lastType != PathPointType.Bezier3) pathBuilder.Append(" C"); + pathBuilder.AppendFormat(CultureInfo.InvariantCulture, " {0},{1}", point.X, point.Y); + break; + default: + continue; + } + + lastType = pathType; + } + + if (isClosed) + { + // Close path + pathBuilder.Append(" Z"); + } + + yield return new SvgPath(pathBuilder.ToString()); + pathBuilder.Clear(); + } + } + } + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// /// When a GDI instruction with a brush parameter is called, there can be a lot we have to do to emulate the brush. The aim is to return a