Commit b4e8b183 authored by Eric Domke's avatar Eric Domke
Browse files

Merging with Official Project

parents 1f36e015 a94f228d
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
<metadata>
<id>Svg</id>
<version>$version$</version>
<title>SVG Rendering Library</title>
<authors>davescriven,jvenema,owaits,ddpruitt,Ralf1108,Tebjan Halm,and others</authors>
<owners>vvvv.org</owners>
<licenseUrl>http://opensource.org/licenses/MS-PL.html</licenseUrl>
<projectUrl>https://github.com/vvvv/SVG</projectUrl>
<requireLicenseAcceptance>true</requireLicenseAcceptance>
<description>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</description>
<summary>Open source library to load/save and render SVG vector graphics.</summary>
<releaseNotes>merged github pull requests</releaseNotes>
<tags>svg, vector graphics, rendering</tags>
<frameworkAssemblies>
<frameworkAssembly assemblyName="System" targetFramework="" />
<frameworkAssembly assemblyName="System.Web" targetFramework="" />
<frameworkAssembly assemblyName="System.Xml" targetFramework="" />
<frameworkAssembly assemblyName="System.Drawing" targetFramework="" />
</frameworkAssemblies>
</metadata>
<files>
<file src="..\Source\bin\Release\Svg.dll" target="lib\Svg.dll" />
<file src="..\Source\bin\Release\Svg.pdb" target="lib\Svg.pdb" />
<file src="..\Source\bin\Release\Svg.XML" target="lib\Svg.XML" />
</files>
</package>
\ No newline at end of file
using System;
using Svg.DataTypes;
using System.ComponentModel;
namespace Svg
......@@ -6,9 +6,10 @@ namespace Svg
/// <summary>
/// Description of SvgAspectRatio.
/// </summary>
[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
......@@ -35,6 +37,12 @@ namespace Svg
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
}
}
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<SvgPreserveAspectRatio>(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);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
namespace Svg
namespace Svg.DataTypes
{
[TypeConverter(typeof(SvgMarkerUnitsConverter))]
public enum SvgMarkerUnits
{
strokeWidth,
......
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
{
......
......@@ -103,7 +103,7 @@ namespace Svg
[SvgAttribute("preserveAspectRatio")]
public SvgAspectRatio AspectRatio
{
get {return this.Attributes.GetAttribute<SvgAspectRatio>("preserveAspectRatio"); }
get { return this.Attributes.GetAttribute<SvgAspectRatio>("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;
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.ScaleTransform(this.Width.ToDeviceValue() / this.ViewBox.Width, this.Height.ToDeviceValue() / this.ViewBox.Height, MatrixOrder.Append);
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);
}
......
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<SvgPreserveAspectRatio>
{
}
public sealed class SvgStrokeLineCapConverter : EnumBaseConverter<SvgStrokeLineCap>
{
}
......@@ -121,4 +117,7 @@ namespace Svg
{
}
public sealed class SvgMarkerUnitsConverter : EnumBaseConverter<SvgMarkerUnits>
{
}
}
......@@ -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<SvgUnit>("markerWidth"); }
set { this.Attributes["markerWidth"] = value; }
}
[SvgAttribute("markerHeight")]
public virtual SvgUnit MarkerHeight
{
get { return this.Attributes.GetAttribute<SvgUnit>("markerHeight"); }
set { this.Attributes["markerHeight"] = value; }
}
[SvgAttribute("markerUnits")]
public virtual SvgMarkerUnits MarkerUnits
{
get { return this.Attributes.GetAttribute<SvgMarkerUnits>("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<SvgMarker>();
......@@ -125,5 +143,148 @@ namespace Svg
return newObj;
}
/// <summary>
/// Render this marker using the slope of the given line segment
/// </summary>
/// <param name="pRenderer"></param>
/// <param name="pOwner"></param>
/// <param name="pMarkerPoint1"></param>
/// <param name="pMarkerPoint2"></param>
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);
}
/// <summary>
/// Render this marker using the average of the slopes of the two given line segments
/// </summary>
/// <param name="pRenderer"></param>
/// <param name="pOwner"></param>
/// <param name="pMarkerPoint1"></param>
/// <param name="pMarkerPoint2"></param>
/// <param name="pMarkerPoint3"></param>
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);
}
/// <summary>
/// Common code for rendering a marker once the orientation angle has been calculated
/// </summary>
/// <param name="fAngle"></param>
/// <param name="pRenderer"></param>
/// <param name="pOwner"></param>
/// <param name="pMarkerPoint"></param>
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();
}
/// <summary>
/// Create a pen that can be used to render this marker
/// </summary>
/// <param name="pStroke"></param>
/// <returns></returns>
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));
}
/// <summary>
/// Get a clone of the current path, scaled for the stroke with
/// </summary>
/// <returns></returns>
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);
}
/// <summary>
/// Adjust the given value to account for the width of the viewbox in the viewport
/// </summary>
/// <param name="fWidth"></param>
/// <returns></returns>
private float AdjustForViewBoxWidth(float fWidth)
{
// TODO: We know this isn't correct
return (fWidth / ViewBox.Width);
}
/// <summary>
/// Adjust the given value to account for the height of the viewbox in the viewport
/// </summary>
/// <param name="fWidth"></param>
/// <returns></returns>
private float AdjustForViewBoxHeight(float fHeight)
{
// TODO: We know this isn't correct
return (fHeight / ViewBox.Height);
}
}
}
\ No newline at end of file
......@@ -57,6 +57,17 @@ namespace Svg
}
/// <summary>
/// Gets or sets the marker (start cap) of the path.
/// </summary>
[SvgAttribute("marker-mid")]
public Uri MarkerMid
{
get { return this.Attributes.GetAttribute<Uri>("marker-mid"); }
set { this.Attributes["marker-mid"] = value; }
}
/// <summary>
/// Gets or sets the marker (start cap) of the path.
/// </summary>
......@@ -136,7 +147,7 @@ namespace Svg
if (this.Stroke != null)
{
float strokeWidth = this.StrokeWidth.ToDeviceValue(this);
using (var pen = new Pen(this.Stroke.GetBrush(this, this.StrokeOpacity), strokeWidth))
using (Pen pen = new Pen(this.Stroke.GetBrush(this, this.StrokeOpacity), strokeWidth))
{
if (this.StrokeDashArray != null && this.StrokeDashArray.Count > 0)
{
......@@ -144,42 +155,28 @@ namespace Svg
pen.DashPattern = this.StrokeDashArray.ConvertAll(u => u.Value / ((strokeWidth <= 0) ? 1 : strokeWidth)).ToArray();
}
renderer.DrawPath(pen, this.Path);
if (this.MarkerStart != null)
{
var marker = this.OwnerDocument.GetElementById<SvgMarker>(this.MarkerStart.ToString());
pen.CustomStartCap = CapFromMarker(marker, strokeWidth);
SvgMarker marker = this.OwnerDocument.GetElementById<SvgMarker>(this.MarkerStart.ToString());
marker.RenderMarker(renderer, this, Path.PathPoints[0], Path.PathPoints[0], Path.PathPoints[1]);
}
if (this.MarkerEnd != null)
if (this.MarkerMid != null)
{
var marker = this.OwnerDocument.GetElementById<SvgMarker>(this.MarkerEnd.ToString());
pen.CustomEndCap = CapFromMarker(marker, strokeWidth);
}
renderer.DrawPath(pen, this.Path);
SvgMarker marker = this.OwnerDocument.GetElementById<SvgMarker>(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]);
}
}
}
private CustomLineCap CapFromMarker(SvgMarker marker, float strokeWidth)
{
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)
if (this.MarkerEnd != null)
{
transMatrix.Scale(.5f, .5f, MatrixOrder.Append);
SvgMarker marker = this.OwnerDocument.GetElementById<SvgMarker>(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]);
}
}
else if (marker.MarkerUnits == SvgMarkerUnits.userSpaceOnUse)
{
transMatrix.Scale(1f / strokeWidth, 1f / strokeWidth, MatrixOrder.Append);
}
markerPath.Transform(transMatrix);
return new CustomLineCap(markerPath, null);
}
public override SvgElement DeepCopy()
......@@ -196,11 +193,6 @@ namespace Svg
newObj.MarkerStart = this.MarkerStart;
newObj.MarkerEnd = this.MarkerEnd;
return newObj;
}
}
}
\ No newline at end of file
......@@ -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)]
......@@ -99,6 +99,7 @@
<Compile Include="Clipping and Masking\SvgClipRule.cs" />
<Compile Include="Clipping and Masking\SvgClipPath.cs" />
<Compile Include="Clipping and Masking\SvgMask.cs" />
<Compile Include="DataTypes\SvgAspectRatioConverter.cs" />
<Compile Include="DataTypes\SvgMarkerUnits.cs" />
<Compile Include="DataTypes\SvgOrient.cs" />
<Compile Include="DataTypes\ISvgViewPort.cs" />
......
......@@ -26,7 +26,7 @@ namespace Svg
/// </summary>
public SvgDocument()
{
Ppi = 96;
Ppi = PointsPerInch;
}
/// <summary>
......@@ -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)
......
......@@ -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);
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment