Skip to content

Commit

Permalink
Updated FillPath and DrawPath to use the more general SvgPathElement
Browse files Browse the repository at this point in the history
  • Loading branch information
glopesdev authored and monoman committed May 8, 2018
1 parent 3be32ca commit 94ae9e5
Showing 1 changed file with 80 additions and 103 deletions.
183 changes: 80 additions & 103 deletions SvgNet/SVGGraphics.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SvgNet.SvgGdi
{
Expand Down Expand Up @@ -1979,6 +1980,8 @@ public void DrawLines(Pen pen, Point[] points)
DrawLines(pen, pts);
}



/// <summary>
/// Implemented
/// </summary>
Expand All @@ -1989,86 +1992,15 @@ public void DrawLines(Pen pen, Point[] points)
/// </remarks>
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;
}

/// <summary>
Expand Down Expand Up @@ -2355,33 +2287,15 @@ public void FillEllipse(Brush brush, Int32 x, Int32 y, Int32 width, Int32 height
/// </summary>
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();
}

/// <summary>
Expand Down Expand Up @@ -3635,6 +3549,69 @@ private void FillBeziers(Brush brush, PointF[] points, FillMode fillmode)
_cur.AddChild(bez);
}

private IEnumerable<SvgPath> 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();
}
}
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
/// 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
Expand Down

0 comments on commit 94ae9e5

Please sign in to comment.