Commit c88ad05d authored by davescriven's avatar davescriven
Browse files

All current source code

parent 01b73c95
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>9.0.21022</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{886A98C5-37C0-4E8B-885E-30C1D2F98B47}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Svg</RootNamespace>
<AssemblyName>Svg</AssemblyName>
<RunPostBuildEvent>OnOutputUpdated</RunPostBuildEvent>
<FileUpgradeFlags>
</FileUpgradeFlags>
<OldToolsVersion>2.0</OldToolsVersion>
<UpgradeBackupLocation>
</UpgradeBackupLocation>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<PublishUrl>publish\</PublishUrl>
<Install>true</Install>
<InstallFrom>Disk</InstallFrom>
<UpdateEnabled>false</UpdateEnabled>
<UpdateMode>Foreground</UpdateMode>
<UpdateInterval>7</UpdateInterval>
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
<UpdatePeriodically>false</UpdatePeriodically>
<UpdateRequired>false</UpdateRequired>
<MapFileExtensions>true</MapFileExtensions>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<IsWebBootstrapper>false</IsWebBootstrapper>
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<CodeAnalysisRules>
</CodeAnalysisRules>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.JScript" />
<Reference Include="Microsoft.Vsa" />
<Reference Include="System" />
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Data" />
<Reference Include="System.Drawing" />
<Reference Include="System.Web" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Basic Shapes\SvgGraphicsElement.cs" />
<Compile Include="Basic Shapes\SvgGraphicsElementEvents.cs" />
<Compile Include="Basic Shapes\SvgCircle.cs" />
<Compile Include="Basic Shapes\SvgEllipse.cs" />
<Compile Include="Basic Shapes\SvgLine.cs" />
<Compile Include="Basic Shapes\SvgPolygon.cs" />
<Compile Include="Basic Shapes\SvgPolyline.cs" />
<Compile Include="DataTypes\ISvgViewPort.cs" />
<Compile Include="DataTypes\SvgElementStyle.cs" />
<Compile Include="DataTypes\SvgUnitCollection.cs" />
<Compile Include="DataTypes\SvgViewBox.cs" />
<Compile Include="Document Structure\SvgDefinitionList.cs" />
<Compile Include="Document Structure\SvgDescription.cs" />
<Compile Include="Document Structure\SvgGroup.cs" />
<Compile Include="Document Structure\SvgFragment.cs" />
<Compile Include="Document Structure\SvgUse.cs" />
<Compile Include="Filter Effects\ISvgFilter.cs" />
<Compile Include="Filter Effects\ISvgFilterable.cs" />
<Compile Include="Filter Effects\SvgFilter.cs" />
<Compile Include="Filter Effects\SvgFilterPrimitive.cs" />
<Compile Include="Filter Effects\SvgGaussianBlur.cs" />
<Compile Include="Filter Effects\SvgMerge.cs" />
<Compile Include="ISvgRenderer.cs" />
<Compile Include="Painting\SvgColourConverter.cs" />
<Compile Include="Painting\SvgGradientSpreadMethod.cs" />
<Compile Include="Painting\SvgGradientUnit.cs" />
<Compile Include="SvgDtdResolver.cs" />
<Compile Include="Exceptions\SvgException.cs" />
<Compile Include="Painting\SvgFillRule.cs" />
<Compile Include="Painting\SvgGradientServer.cs" />
<Compile Include="Painting\SvgGradientStop.cs" />
<Compile Include="Painting\ISvgStylable.cs" />
<Compile Include="Painting\SvgColourServer.cs" />
<Compile Include="Painting\SvgLinearGradientServer.cs" />
<Compile Include="Painting\SvgPaintServer.cs" />
<Compile Include="Painting\SvgPaintServerFactory.cs" />
<Compile Include="Painting\SvgPatternServer.cs" />
<Compile Include="Painting\SvgRadialGradientServer.cs" />
<Compile Include="Painting\SvgStrokeLineCap.cs" />
<Compile Include="Painting\SvgStrokeLineJoin.cs" />
<Compile Include="Basic Shapes\SvgGraphicsElementStyle.cs" />
<Compile Include="Paths\SvgArcSegment.cs" />
<Compile Include="Paths\SvgClosePathSegment.cs" />
<Compile Include="Paths\SvgCubicCurveSegment.cs" />
<Compile Include="Paths\SvgLineSegment.cs" />
<Compile Include="Paths\SvgMoveToSegment.cs" />
<Compile Include="Paths\SvgPath.cs" />
<Compile Include="Basic Shapes\SvgRectangle.cs" />
<Compile Include="Paths\SvgPathSegment.cs" />
<Compile Include="Paths\SvgPathSegmentList.cs" />
<Compile Include="Paths\SvgQuadraticCurveSegment.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Document Structure\SvgDocument.cs" />
<Compile Include="SvgAttributeAttribute.cs" />
<Compile Include="SvgAttributeCollection.cs" />
<Compile Include="SvgElement.cs" />
<Compile Include="SvgElementCollection.cs" />
<Compile Include="SvgElementFactory.cs" />
<Compile Include="Paths\SvgPathBuilder.cs" />
<Compile Include="DataTypes\SvgPoint.cs" />
<Compile Include="SvgElementIdManager.cs" />
<Compile Include="DataTypes\SvgUnit.cs" />
<Compile Include="DataTypes\SvgUnitConverter.cs" />
<Compile Include="Text\SvgText.cs" />
<Compile Include="Text\SvgTextAnchor.cs" />
<Compile Include="Text\SvgTextSpan.cs" />
<Compile Include="Transforms\ISvgTransformable.cs" />
<Compile Include="Transforms\SvgRotate.cs" />
<Compile Include="Transforms\SvgScale.cs" />
<Compile Include="Transforms\SvgTransform.cs" />
<Compile Include="Transforms\SvgTransformCollection.cs" />
<Compile Include="Transforms\SvgTransformConverter.cs" />
<Compile Include="Transforms\SvgTranslate.cs" />
<Compile Include="Web\SvgHandler.cs" />
</ItemGroup>
<ItemGroup>
<BootstrapperPackage Include="Microsoft.Net.Framework.2.0">
<Visible>False</Visible>
<ProductName>.NET Framework 2.0 %28x86%29</ProductName>
<Install>true</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Framework.3.0">
<Visible>False</Visible>
<ProductName>.NET Framework 3.0 %28x86%29</ProductName>
<Install>false</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5</ProductName>
<Install>false</Install>
</BootstrapperPackage>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Resources\svg11.dtd" />
</ItemGroup>
<ItemGroup>
<Folder Include="Clipping and Masking\" />
<Folder Include="Web\Resources\" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
<PropertyGroup>
<PostBuildEvent>
</PostBuildEvent>
</PropertyGroup>
</Project>
\ No newline at end of file
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<PublishUrlHistory>
</PublishUrlHistory>
<InstallUrlHistory>
</InstallUrlHistory>
<SupportUrlHistory>
</SupportUrlHistory>
<UpdateUrlHistory>
</UpdateUrlHistory>
<BootstrapperUrlHistory>
</BootstrapperUrlHistory>
<FallbackCulture>en-US</FallbackCulture>
<VerifyUploadedFiles>false</VerifyUploadedFiles>
<ProjectView>ProjectFiles</ProjectView>
</PropertyGroup>
</Project>
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
namespace Svg
{
public class SvgAttributeAttribute : System.Attribute
{
private const string SVG_NAMESPACE = "http://www.w3.org/2000/svg";
private string _name;
private string _namespace;
public override object TypeId
{
get
{
return base.TypeId;
}
}
public override bool Match(object obj)
{
SvgAttributeAttribute indicator = obj as SvgAttributeAttribute;
if (indicator == null)
return false;
// Always match if either value is String.Empty (wildcard)
if (indicator.Name == String.Empty)
return false;
return String.Compare(indicator.Name, this.Name) == 0;
}
public string Name
{
get { return this._name; }
}
public string NameSpace
{
get { return this._namespace; }
}
internal SvgAttributeAttribute()
{
this._name = String.Empty;
}
internal SvgAttributeAttribute(string name)
{
this._name = name;
this._namespace = SVG_NAMESPACE;
}
public SvgAttributeAttribute(string name, string nameSpace)
{
this._name = name;
this._namespace = nameSpace;
}
}
}
\ No newline at end of file
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Svg
{
/// <summary>
/// A collection of Scalable Vector Attributes that can be inherited from the owner elements ancestors.
/// </summary>
public sealed class SvgAttributeCollection : Dictionary<string, object>
{
private SvgElement _owner;
/// <summary>
/// Initialises a new instance of a <see cref="SvgAttributeCollection"/> with the given <see cref="SvgElement"/> as the owner.
/// </summary>
/// <param name="owner">The <see cref="SvgElement"/> owner of the collection.</param>
public SvgAttributeCollection(SvgElement owner)
{
this._owner = owner;
}
/// <summary>
/// Gets the attribute with the specified name.
/// </summary>
/// <typeparam name="TAttributeType">The type of the attribute value.</typeparam>
/// <param name="attributeName">A <see cref="string"/> containing the name of the attribute.</param>
/// <returns>The attribute value if available; otherwise the default value of <typeparamref name="TAttributeType"/>.</returns>
public TAttributeType GetAttribute<TAttributeType>(string attributeName)
{
if (this.ContainsKey(attributeName) && base[attributeName] != null)
{
return (TAttributeType)base[attributeName];
}
return default(TAttributeType);
}
/// <summary>
/// Gets the attribute with the specified name and inherits from ancestors if there is no attribute set.
/// </summary>
/// <typeparam name="TAttributeType">The type of the attribute value.</typeparam>
/// <param name="attributeName">A <see cref="string"/> containing the name of the attribute.</param>
/// <returns>The attribute value if available; otherwise the ancestors value for the same attribute; otherwise the default value of <typeparamref name="TAttributeType"/>.</returns>
public TAttributeType GetInheritedAttribute<TAttributeType>(string attributeName)
{
if (this.ContainsKey(attributeName) && base[attributeName] != null)
{
return (TAttributeType)base[attributeName];
}
if (this._owner.Parent != null)
{
if (this._owner.Parent.Attributes[attributeName] != null)
{
return (TAttributeType)this._owner.Parent.Attributes[attributeName];
}
}
return default(TAttributeType);
}
/// <summary>
/// Gets the attribute with the specified name.
/// </summary>
/// <param name="attributeName">A <see cref="string"/> containing the attribute name.</param>
/// <returns>The attribute value associated with the specified name; If there is no attribute the parent's value will be inherited.</returns>
public new object this[string attributeName]
{
get { return this.GetInheritedAttribute<object>(attributeName); }
set { base[attributeName] = value; }
}
}
}
\ No newline at end of file
using System;
using System.Resources;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Xml;
namespace Svg
{
internal class SvgDtdResolver : XmlUrlResolver
{
/// <summary>
/// Maps a URI to an object containing the actual resource.
/// </summary>
/// <param name="absoluteUri">The URI returned from <see cref="M:System.Xml.XmlResolver.ResolveUri(System.Uri,System.String)"/></param>
/// <param name="role">The current implementation does not use this parameter when resolving URIs. This is provided for future extensibility purposes. For example, this can be mapped to the xlink:role and used as an implementation specific argument in other scenarios.</param>
/// <param name="ofObjectToReturn">The type of object to return. The current implementation only returns System.IO.Stream objects.</param>
/// <returns>
/// A System.IO.Stream object or null if a type other than stream is specified.
/// </returns>
/// <exception cref="T:System.Xml.XmlException">
/// <paramref name="ofObjectToReturn"/> is neither null nor a Stream type. </exception>
/// <exception cref="T:System.UriFormatException">The specified URI is not an absolute URI. </exception>
/// <exception cref="T:System.NullReferenceException">
/// <paramref name="absoluteUri"/> is null. </exception>
/// <exception cref="T:System.Exception">There is a runtime error (for example, an interrupted server connection). </exception>
public override object GetEntity(Uri absoluteUri, string role, Type ofObjectToReturn)
{
return Assembly.GetExecutingAssembly().GetManifestResourceStream("Svg.Resources.svg11.dtd");
}
}
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Xml;
using Svg.Transforms;
namespace Svg
{
/// <summary>
/// The base class of which all SVG elements are derived from.
/// </summary>
public abstract class SvgElement : ISvgElement, ISvgTransformable, ICloneable
{
internal SvgElement _parent;
private string _content;
private string _elementName;
private SvgAttributeCollection _attributes;
private EventHandlerList _eventHandlers;
private SvgElementCollection _children;
private static readonly object _loadEventKey = new object();
private Matrix _graphicsMatrix;
/// <summary>
/// Gets the name of the element.
/// </summary>
protected virtual string ElementName
{
get { return this._elementName; }
}
/// <summary>
/// Gets or sets the content of the element.
/// </summary>
public virtual string Content
{
get { return this._content; }
set { this._content = value; }
}
/// <summary>
/// Gets an <see cref="EventHandlerList"/> of all events belonging to the element.
/// </summary>
protected virtual EventHandlerList Events
{
get { return this._eventHandlers; }
}
/// <summary>
/// Occurs when the element is loaded.
/// </summary>
public event EventHandler Load
{
add { this.Events.AddHandler(_loadEventKey, value); }
remove { this.Events.RemoveHandler(_loadEventKey, value); }
}
/// <summary>
/// Gets a collection of all child <see cref="SvgElements"/>.
/// </summary>
public virtual SvgElementCollection Children
{
get { return this._children; }
}
/// <summary>
/// Gets a value to determine whether the element has children.
/// </summary>
/// <returns></returns>
public virtual bool HasChildren()
{
return (this.Children.Count > 0);
}
/// <summary>
/// Gets the parent <see cref="SvgElement"/>.
/// </summary>
/// <value>An <see cref="SvgElement"/> if one exists; otherwise null.</value>
public virtual SvgElement Parent
{
get { return this._parent; }
}
/// <summary>
/// Gets the owner <see cref="SvgDocument"/>.
/// </summary>
public virtual SvgDocument OwnerDocument
{
get
{
if (Parent == null)
{
if (this is SvgDocument)
return (SvgDocument)this;
else
return null;
}
else
return Parent.OwnerDocument;
}
}
/// <summary>
/// Gets a collection of element attributes.
/// </summary>
protected internal virtual SvgAttributeCollection Attributes
{
get
{
if (this._attributes == null)
{
this._attributes = new SvgAttributeCollection(this);
}
return this._attributes;
}
}
protected internal virtual void PushTransforms(Graphics graphics)
{
// Return if there are no transforms
if (this.Transforms == null || this.Transforms.Count == 0)
{
return;
}
_graphicsMatrix = graphics.Transform;
Matrix transformMatrix = new Matrix();
foreach (SvgTransform transformation in this.Transforms)
{
transformMatrix.Multiply(transformation.Matrix);
}
graphics.Transform = transformMatrix;
}
protected internal virtual void PopTransforms(Graphics graphics)
{
if (this.Transforms == null || this.Transforms.Count == 0 || _graphicsMatrix == null)
{
return;
}
graphics.Transform = _graphicsMatrix;
_graphicsMatrix = null;
}
void ISvgTransformable.PushTransforms(Graphics graphics)
{
this.PushTransforms(graphics);
}
void ISvgTransformable.PopTransforms(Graphics graphics)
{
this.PopTransforms(graphics);
}
/// <summary>
/// Gets or sets the element transforms.
/// </summary>
/// <value>The transforms.</value>
[SvgAttribute("transform")]
public SvgTransformCollection Transforms
{
get { return this.Attributes.GetAttribute<SvgTransformCollection>("Transforms"); }
set { this.Attributes["Transforms"] = value; }
}
/// <summary>
/// Gets or sets the ID of the element.
/// </summary>
/// <exception cref="SvgException">The ID is already used within the <see cref="SvgDocument"/>.</exception>
[SvgAttribute("id")]
public string ID
{
get { return this.Attributes.GetAttribute<string>("ID"); }
set
{
// Don't do anything if it hasn't changed
if (string.Compare(this.ID, value) == 0)
return;
if (this.OwnerDocument != null)
{
this.OwnerDocument.IdManager.Remove(this);
}
this.Attributes["ID"] = value;
if (this.OwnerDocument != null)
{
this.OwnerDocument.IdManager.Add(this);
}
}
}
protected virtual void ElementAdded(SvgElement child, int index)
{
}
internal void OnElementAdded(SvgElement child, int index)
{
this.ElementAdded(child, index);
}
protected virtual void ElementRemoved(SvgElement child)
{
}
internal void OnElementRemoved(SvgElement child)
{
this.ElementRemoved(child);
}
/// <summary>
/// Initializes a new instance of the <see cref="SvgElement"/> class.
/// </summary>
internal SvgElement()
{
this._children = new SvgElementCollection(this);
this._eventHandlers = new EventHandlerList();
this._elementName = string.Empty;
}
public void RenderElement(Graphics graphics)
{
this.Render(graphics);
}
public void WriteElement(XmlTextWriter writer)
{
this.Write(writer);
}
protected virtual void WriteStartElement(XmlTextWriter writer)
{
if (this.ElementName != String.Empty)
{
writer.WriteStartElement(this.ElementName);
}
this.WriteAttributes(writer);
}
protected virtual void WriteEndElement(XmlTextWriter writer)
{
if (this.ElementName != String.Empty)
{
writer.WriteEndElement();
}
}
protected virtual void WriteAttributes(XmlTextWriter writer)
{
}
protected virtual void Write(XmlTextWriter writer)
{
if (this.ElementName != String.Empty)
{
this.WriteStartElement(writer);
this.WriteChildren(writer);
this.WriteEndElement(writer);
}
}
protected virtual void WriteChildren(XmlTextWriter writer)
{
foreach (SvgElement child in this.Children)
{
child.Write(writer);
}
}
/// <summary>
/// Renders the <see cref="SvgElement"/> and contents to the specified <see cref="Graphics"/> object.
/// </summary>
/// <param name="graphics">The <see cref="Graphics"/> object to render to.</param>
protected virtual void Render(Graphics graphics)
{
this.PushTransforms(graphics);
this.RenderContents(graphics);
this.PopTransforms(graphics);
}
protected virtual void RenderContents(Graphics graphics)
{
foreach (SvgElement element in this.Children)
{
element.Render(graphics);
}
}
void ISvgElement.Render(Graphics graphics)
{
this.Render(graphics);
}
public virtual object Clone()
{
return this.MemberwiseClone();
}
}
internal interface ISvgElement
{
void Render(Graphics graphics);
}
}
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.Text;
namespace Svg
{
/// <summary>
/// Represents a collection of <see cref="SvgElement"/>s.
/// </summary>
public sealed class SvgElementCollection : IList<SvgElement>
{
private List<SvgElement> _elements;
private SvgElement _owner;
/// <summary>
/// Initialises a new instance of an <see cref="SvgElementCollection"/> class.
/// </summary>
/// <param name="owner">The owner <see cref="SvgElement"/> of the collection.</param>
internal SvgElementCollection(SvgElement owner)
{
if (owner == null)
{
throw new ArgumentNullException("owner");
}
this._elements = new List<SvgElement>();
this._owner = owner;
}
/// <summary>
/// Returns the index of the specified <see cref="SvgElement"/> in the collection.
/// </summary>
/// <param name="item">The <see cref="SvgElement"/> to search for.</param>
/// <returns>The index of the element if it is present; otherwise -1.</returns>
public int IndexOf(SvgElement item)
{
return this._elements.IndexOf(item);
}
/// <summary>
/// Inserts the given <see cref="SvgElement"/> to the collection at the specified index.
/// </summary>
/// <param name="index">The index that the <paramref name="item"/> should be added at.</param>
/// <param name="item">The <see cref="SvgElement"/> to be added.</param>
public void Insert(int index, SvgElement item)
{
this._elements.Insert(index, item);
}
public void RemoveAt(int index)
{
SvgElement element = this[index];
if (element != null)
this.Remove(element);
}
public SvgElement this[int index]
{
get { return this._elements[index]; }
set { this._elements[index] = value; }
}
public void Add(SvgElement item)
{
if (this._owner.OwnerDocument != null)
{
this._owner.OwnerDocument.IdManager.Add(item);
}
this._elements.Add(item);
item._parent = this._owner;
item._parent.OnElementAdded(item, this.Count - 1);
}
public void Clear()
{
while (this.Count > 0)
{
SvgElement element = this[0];
this.Remove(element);
}
}
public bool Contains(SvgElement item)
{
return this._elements.Contains(item);
}
public void CopyTo(SvgElement[] array, int arrayIndex)
{
this._elements.CopyTo(array, arrayIndex);
}
public int Count
{
get { return this._elements.Count; }
}
public bool IsReadOnly
{
get { return false; }
}
public bool Remove(SvgElement item)
{
bool removed = this._elements.Remove(item);
if (removed)
{
this._owner.OnElementRemoved(item);
item._parent = null;
if (this._owner.OwnerDocument != null)
{
this._owner.OwnerDocument.IdManager.Remove(item);
}
}
return removed;
}
public IEnumerator<SvgElement> GetEnumerator()
{
return this._elements.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return this._elements.GetEnumerator();
}
}
}
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Collections;
using System.Text;
using System.Globalization;
using System.Text.RegularExpressions;
using System.Xml;
using System.ComponentModel;
using System.Reflection;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Diagnostics;
using System.Threading;
using Svg.Transforms;
namespace Svg
{
internal class SvgElementFactory
{
public static SvgDocument CreateDocument(XmlTextReader reader)
{
return (SvgDocument)CreateElement(reader, true, null);
}
public static SvgElement CreateElement(XmlTextReader reader, SvgDocument document)
{
return CreateElement(reader, false, document);
}
private static SvgElement CreateElement(XmlTextReader reader, bool fragmentIsDocument, SvgDocument document)
{
SvgElement createdElement = null;
SvgFragment fragment;
string elementName = reader.LocalName;
// Parse element
switch (elementName)
{
case "path":
createdElement = new SvgPath();
break;
case "linearGradient":
createdElement = new SvgLinearGradientServer();
break;
case "radialGradient":
createdElement = new SvgRadialGradientServer();
break;
case "pattern":
createdElement = new SvgPatternServer();
break;
case "defs":
createdElement = new SvgDefinitionList();
break;
case "stop":
createdElement = new SvgGradientStop();
break;
case "desc":
createdElement = new SvgDescription();
break;
case "svg":
if (!fragmentIsDocument)
fragment = new SvgFragment();
else
fragment = new SvgDocument();
createdElement = (fragmentIsDocument) ? (SvgDocument)fragment : fragment;
break;
case "circle":
createdElement = new SvgCircle();
break;
case "ellipse":
createdElement = new SvgEllipse();
break;
case "rect":
createdElement = new SvgRectangle();
break;
case "line":
createdElement = new SvgLine();
break;
case "polyline":
createdElement = new SvgPolyline();
break;
case "polygon":
createdElement = new SvgPolygon();
break;
case "g":
createdElement = new SvgGroup();
break;
case "use":
createdElement = new SvgUse();
break;
case "text":
createdElement = new SvgText();
break;
default:
// Do nothing - unsupported
return null;
}
SetAttributes(createdElement, reader, document);
return createdElement;
}
private static void SetAttributes(SvgElement element, XmlTextReader reader, SvgDocument document)
{
string[] styles = null;
string[] style = null;
int i = 0;
while (reader.MoveToNextAttribute())
{
// Special treatment for "style"
if (reader.LocalName.Equals("style"))
{
styles = reader.Value.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
for (i = 0; i < styles.Length; i++)
{
if (!styles[i].Contains(":"))
{
continue;
}
style = styles[i].Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries);
SetPropertyValue(element, style[0].Trim(), style[1].Trim(), document);
}
continue;
}
SetPropertyValue(element, reader.LocalName, reader.Value, document);
}
}
private static void SetPropertyValue(SvgElement element, string attributeName, string attributeValue, SvgDocument document)
{
PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(element.GetType(), new SvgAttributeAttribute[] { new SvgAttributeAttribute(attributeName) });
PropertyDescriptor descriptor = null;
TypeConverter converter = null;
if (properties.Count > 0)
{
descriptor = properties[0];
converter = (properties[0].Converter != null) ? properties[0].Converter : TypeDescriptor.GetConverter(descriptor.PropertyType);
try
{
descriptor.SetValue(element, converter.ConvertFrom(document, CultureInfo.InvariantCulture, attributeValue));
}
catch
{
Trace.TraceWarning(string.Format("Attribute '{0}' cannot be set - type '{1}' cannot convert from string '{2}'.", attributeName, descriptor.PropertyType.FullName, attributeValue));
}
}
}
//private static void SetAttributes(SvgElement element, Dictionary<string, string> attributes, SvgDocument document)
//{
// // Parse attributes
// foreach(KeyValuePair<string, string> keyValuePair in attributes)
// {
// string name = keyValuePair.Key;
// string value = keyValuePair.Value;
// switch (name)
// {
// case "id":
// if (!String.IsNullOrEmpty(value))
// SetProperty(element, name, value);
// break;
// case "style":
// string[] styles = value.Split(';');
// Dictionary<string, string> styleAttributes = new Dictionary<string, string>();
// foreach (string style in styles)
// {
// if (String.IsNullOrEmpty(style) || style.IndexOf(":") == -1)
// continue;
// string[] pair = style.Split(':');
// styleAttributes.Add(pair[0].Trim(), pair[1].Trim());
// }
// SetAttributes(element, styleAttributes, document);
// break;
// case "href":
// if (element is SvgUse)
// SetProperty(element, name, document.GetElementById(value));
// break;
// case "transform":
// SetProperty(element, name, _transformConverter.ConvertFrom(value));
// break;
// case "stroke":
// case "fill":
// SetProperty(element, name, SvgPaintServerFactory.Create(value, document));
// break;
// case "font":
// break;
// case "font-family":
// // TODO: create font family converter, loop through families list. return generic if it's not in the list
// try
// {
// SetProperty(element, name, new FontFamily(value));
// }
// catch
// {
// Trace.TraceWarning("\"{0}\" is not a recognised font.", value);
// SetProperty(element, name, FontFamily.GenericSansSerif);
// }
// break;
// case "font-weight":
// //SetProperty(createdElement, reader.LocalName, reader.Value);
// break;
// case "fill-opacity":
// case "stroke-opacity":
// case "stop-opacity":
// case "opacity":
// SetProperty(element, name, float.Parse(value));
// break;
// case "points":
// // TODO: TypeConverter for this?
// string points = value.Replace(",", " ").Trim();
// Regex spaceReplace = new Regex(@"\s+");
// points = spaceReplace.Replace(points, " ");
// string[] pts = points.Split(' ');
// List<SvgUnit> units = new List<SvgUnit>();
// foreach (string point in pts)
// units.Add((SvgUnit)_unitConverter.ConvertFrom(point));
// SetProperty(element, name, units);
// break;
// case "font-size":
// case "letter-spacing":
// case "word-spacing":
// case "r":
// case "width":
// case "height":
// case "ry":
// case "rx":
// case "x":
// case "y":
// case "x1":
// case "y1":
// case "x2":
// case "y2":
// case "cy":
// case "cx":
// case "offset":
// case "stroke-width":
// SetProperty(element, name, (SvgUnit)_unitConverter.ConvertFrom(value));
// break;
// case "stop-color":
// SetProperty(element, name, (Color)_colourConverter.ConvertFrom(value));
// break;
// case "d":
// SvgPathBuilder.Parse(value, ((SvgPath)element).PathData);
// break;
// case "pathLength":
// SetProperty(element, name, int.Parse(value));
// break;
// default:
// break;
// }
// }
//}
//private static void SetProperty(object element, string attributeName, object attributeValue)
//{
// string key = String.Format("{0}{1}", element.GetType().Name, attributeName);
// if (!_propertyDescriptorLookup.ContainsKey(key))
// {
// PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(element.GetType(), new Attribute[] { new SvgAttributeAttribute(attributeName) });
// if (properties.Count == 0)
// return;
// _propertyDescriptorLookup.Add(key, properties[0]);
// }
// PropertyDescriptor property = _propertyDescriptorLookup[key];
// property.SetValue(element, attributeValue);
//}
}
}
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Svg
{
/// <summary>
/// Provides methods to ensure element ID's are valid and unique.
/// </summary>
public class SvgElementIdManager
{
private SvgDocument _document;
private Dictionary<string, SvgElement> _idValueMap;
/// <summary>
/// Retrieves the <see cref="SvgElement"/> with the specified ID.
/// </summary>
/// <param name="id">A <see cref="string"/> containing the ID of the element to find.</param>
/// <returns>An <see cref="SvgElement"/> of one exists with the specified ID; otherwise false.</returns>
public virtual SvgElement GetElementById(string id)
{
if (id.StartsWith("#"))
id = id.Substring(1);
return this._idValueMap[id];
}
public virtual SvgElement GetElementById(Uri uri)
{
return this.GetElementById(uri.ToString());
}
/// <summary>
/// Adds the specified <see cref="SvgElement"/> for ID management.
/// </summary>
/// <param name="element">The <see cref="SvgElement"/> to be managed.</param>
public virtual void Add(SvgElement element)
{
if (!string.IsNullOrEmpty(element.ID))
{
this.EnsureValidId(element.ID);
this._idValueMap.Add(element.ID, element);
}
}
/// <summary>
/// Removed the specified <see cref="SvgElement"/> from ID management.
/// </summary>
/// <param name="element">The <see cref="SvgElement"/> to be removed from ID management.</param>
public virtual void Remove(SvgElement element)
{
if (!string.IsNullOrEmpty(element.ID))
{
this._idValueMap.Remove(element.ID);
}
}
/// <summary>
/// Ensures that the specified ID is valid within the containing <see cref="SvgDocument"/>.
/// </summary>
/// <param name="id">A <see cref="string"/> containing the ID to validate.</param>
/// <exception cref="SvgException">
/// <para>The ID cannot start with a digit.</para>
/// <para>An element with the same ID already exists within the containing <see cref="SvgDocument"/>.</para>
/// </exception>
public void EnsureValidId(string id)
{
if (string.IsNullOrEmpty(id))
{
return;
}
if (char.IsDigit(id[0]))
{
throw new SvgException("ID cannot start with a digit: '" + id + "'.");
}
if (this._idValueMap.ContainsKey(id))
{
throw new SvgException("An element with the same ID already exists: '" + id + "'.");
}
}
/// <summary>
/// Initialises a new instance of an <see cref="SvgElementIdManager"/>.
/// </summary>
/// <param name="document">The <see cref="SvgDocument"/> containing the <see cref="SvgElement"/>s to manage.</param>
public SvgElementIdManager(SvgDocument document)
{
this._document = document;
this._idValueMap = new Dictionary<string, SvgElement>();
}
}
}
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Text;
namespace Svg
{
/// <summary>
/// The <see cref="SvgText"/> element defines a graphics element consisting of text.
/// </summary>
public class SvgText : SvgGraphicsElement
{
private SvgUnit _x;
private SvgUnit _y;
private SvgUnit _letterSpacing;
private SvgUnit _wordSpacing;
private SvgUnit _fontSize;
private Font _font;
private GraphicsPath _path;
private SvgTextAnchor _textAnchor = SvgTextAnchor.Start;
private static readonly Graphics _stringMeasure;
/// <summary>
/// Initializes the <see cref="SvgText"/> class.
/// </summary>
static SvgText()
{
Bitmap bitmap = new Bitmap(1, 1);
_stringMeasure = Graphics.FromImage(bitmap);
}
/// <summary>
/// Initializes a new instance of the <see cref="SvgText"/> class.
/// </summary>
public SvgText()
{
this._font = new Font(new FontFamily("Times New Roman"), 1.0f);
this._fontSize = new SvgUnit(0.0f);
}
/// <summary>
/// Initializes a new instance of the <see cref="SvgText"/> class.
/// </summary>
/// <param name="text">The text.</param>
public SvgText(string text) : this()
{
this.Text = text;
}
/// <summary>
/// Gets or sets the text to be rendered.
/// </summary>
public virtual string Text
{
get { return base.Content; }
set { base.Content = value; this.IsPathDirty = true; }
}
/// <summary>
/// Gets or sets the text anchor.
/// </summary>
/// <value>The text anchor.</value>
[SvgAttribute("text-anchor")]
public virtual SvgTextAnchor TextAnchor
{
get { return this._textAnchor; }
set { this._textAnchor = value; this.IsPathDirty = true; }
}
/// <summary>
/// Gets or sets the X.
/// </summary>
/// <value>The X.</value>
[SvgAttribute("x")]
public virtual SvgUnit X
{
get { return this._x; }
set { this._x = value; this.IsPathDirty = true; }
}
/// <summary>
/// Gets or sets the Y.
/// </summary>
/// <value>The Y.</value>
[SvgAttribute("y")]
public virtual SvgUnit Y
{
get { return this._y; }
set { this._y = value; this.IsPathDirty = true; }
}
/// <summary>
/// Specifies spacing behavior between text characters.
/// </summary>
[SvgAttribute("letter-spacing")]
public virtual SvgUnit LetterSpacing
{
get { return this._letterSpacing; }
set { this._letterSpacing = value; this.IsPathDirty = true; }
}
/// <summary>
/// Specifies spacing behavior between words.
/// </summary>
[SvgAttribute("word-spacing")]
public virtual SvgUnit WordSpacing
{
get { return this._wordSpacing; }
set { this._wordSpacing = value; this.IsPathDirty = true; }
}
/// <summary>
/// Indicates which font family is to be used to render the text.
/// </summary>
[SvgAttribute("font-family")]
public virtual Font FontFamily
{
get { return this._font; }
set { this._font = value; this.IsPathDirty = true; }
}
/// <summary>
/// Refers to the size of the font from baseline to baseline when multiple lines of text are set solid in a multiline layout environment.
/// </summary>
[SvgAttribute("font-size")]
public virtual SvgUnit FontSize
{
get { return this._fontSize; }
set { this._fontSize = value; this.IsPathDirty = true; }
}
/// <summary>
/// Set all font information.
/// </summary>
[SvgAttribute("font")]
public virtual Font Font
{
get { return this._font; }
set { this._font = value; this.IsPathDirty = true; }
}
/// <summary>
/// Gets or sets the fill.
/// </summary>
/// <remarks>
/// <para>Unlike other <see cref="SvgGraphicsElement"/>s, <see cref="SvgText"/> has a default fill of black rather than transparent.</para>
/// </remarks>
/// <value>The fill.</value>
public override SvgPaintServer Fill
{
get { return (this.Attributes["Fill"] == null) ? new SvgColourServer(Color.Black) : (SvgPaintServer)this.Attributes["Fill"]; }
set { this.Attributes["Fill"] = value; }
}
/// <summary>
/// Returns a <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
/// </summary>
/// <returns>
/// A <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
/// </returns>
public override string ToString()
{
return this.Text;
}
/// <summary>
/// Gets or sets a value to determine if anti-aliasing should occur when the element is being rendered.
/// </summary>
/// <value></value>
protected override bool RequiresSmoothRendering
{
get { return true; }
}
/// <summary>
/// Gets the bounds of the element.
/// </summary>
/// <value>The bounds.</value>
public override System.Drawing.RectangleF Bounds
{
get { return this.Path.GetBounds(); }
}
/// <summary>
/// Renders the <see cref="SvgElement"/> and contents to the specified <see cref="Graphics"/> object.
/// </summary>
/// <param name="graphics">The <see cref="Graphics"/> object to render to.</param>
protected override void Render(Graphics graphics)
{
base.Render(graphics);
}
/// <summary>
/// Gets the <see cref="GraphicsPath"/> for this element.
/// </summary>
/// <value></value>
public override System.Drawing.Drawing2D.GraphicsPath Path
{
get
{
// Make sure the path is always null if there is no text
if (_path == null || this.IsPathDirty && !string.IsNullOrEmpty(this.Text))
{
float fontSize = this.FontSize.ToDeviceValue(this);
SizeF stringSize = SizeF.Empty;
PointF location = PointF.Empty;
// Minus FontSize because the x/y coords mark the bottom left, not bottom top.
switch (this.TextAnchor)
{
case SvgTextAnchor.Start:
location = new PointF(this.X.ToDeviceValue(this), this.Y.ToDeviceValue(this, true) - fontSize);
break;
case SvgTextAnchor.Middle:
stringSize = _stringMeasure.MeasureString(this.Text, new Font(this._font.FontFamily, fontSize));
location = new PointF(this.X.ToDeviceValue(this) - (stringSize.Width / 2), this.Y.ToDeviceValue(this, true) - fontSize);
break;
case SvgTextAnchor.End:
stringSize = _stringMeasure.MeasureString(this.Text, new Font(this._font.FontFamily, fontSize));
location = new PointF(this.X.ToDeviceValue(this) - stringSize.Width, this.Y.ToDeviceValue(this, true) - fontSize);
break;
}
_path = new GraphicsPath();
_path.StartFigure();
// No way to do letter-spacing or word-spacing, so do manually
if (this.LetterSpacing.Value > 0.0f || this.WordSpacing.Value > 0.0f)
{
// Cut up into words, or just leave as required
string[] words = (this.WordSpacing.Value > 0.0f) ? this.Text.Split(' ') : new string[] { this.Text };
float wordSpacing = this.WordSpacing.ToDeviceValue(this);
float letterSpacing = this.LetterSpacing.ToDeviceValue(this);
float start = this.X.ToDeviceValue(this);
foreach (string word in words)
{
// Only do if there is line spacing, just write the word otherwise
if (this.LetterSpacing.Value > 0.0f)
{
char[] characters = word.ToCharArray();
foreach (char currentCharacter in characters)
{
_path.AddString(currentCharacter.ToString(), this._font.FontFamily, 0, fontSize, location, StringFormat.GenericDefault);
location = new PointF(_path.GetBounds().Width + start + letterSpacing, location.Y);
}
}
else
_path.AddString(word, this._font.FontFamily, 0, fontSize, location, StringFormat.GenericDefault);
// Move the location of the word to be written along
location = new PointF(_path.GetBounds().Width + start + wordSpacing, location.Y);
}
}
else
{
_path.AddString(this.Text, this._font.FontFamily, 0, fontSize, location, StringFormat.GenericDefault);
}
_path.CloseFigure();
this.IsPathDirty = false;
}
return _path;
}
}
}
}
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Svg
{
/// <summary>
/// Text anchor is used to align (start-, middle- or end-alignment) a string of text relative to a given point.
/// </summary>
public enum SvgTextAnchor
{
/// <summary>
/// The rendered characters are aligned such that the start of the text string is at the initial current text position.
/// </summary>
Start,
/// <summary>
/// The rendered characters are aligned such that the middle of the text string is at the current text position.
/// </summary>
Middle,
/// <summary>
/// The rendered characters are aligned such that the end of the text string is at the initial current text position.
/// </summary>
End
}
}
\ No newline at end of file
using System;
using System.ComponentModel;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Svg
{
public class SvgTextSpan : SvgText
{
/// <summary>
/// Gets or sets the X.
/// </summary>
/// <value>The X.</value>
[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public override SvgUnit X
{
get { return base.X; }
set { base.X = value; }
}
/// <summary>
/// Gets or sets the Y.
/// </summary>
/// <value>The Y.</value>
[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public override SvgUnit Y
{
get { return base.Y; }
set { base.Y = value; }
}
}
}
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Drawing.Drawing2D;
using Svg.Transforms;
namespace Svg
{
public interface ISvgTransformable
{
SvgTransformCollection Transforms { get; set; }
void PushTransforms(Graphics graphics);
void PopTransforms(Graphics graphics);
}
}
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.Text;
namespace Svg.Transforms
{
public class SvgRotate : SvgTransform
{
private float angle;
public float Angle
{
get { return this.angle; }
set { this.angle = value; }
}
public override System.Drawing.Drawing2D.Matrix Matrix
{
get
{
System.Drawing.Drawing2D.Matrix matrix = new System.Drawing.Drawing2D.Matrix();
matrix.Rotate(this.Angle);
return matrix;
}
}
public SvgRotate(float angle)
{
this.angle = angle;
}
}
}
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing.Drawing2D;
namespace Svg.Transforms
{
public class SvgScale : SvgTransform
{
private float scaleFactorX;
private float scaleFactorY;
public float X
{
get { return this.scaleFactorX; }
set { this.scaleFactorX = value; }
}
public float Y
{
get { return this.scaleFactorY; }
set { this.scaleFactorY = value; }
}
public override System.Drawing.Drawing2D.Matrix Matrix
{
get
{
System.Drawing.Drawing2D.Matrix matrix = new System.Drawing.Drawing2D.Matrix();
matrix.Scale(this.X, this.Y);
return matrix;
}
}
public SvgScale(float x) : this(x, x) { }
public SvgScale(float x, float y)
{
this.scaleFactorX = x;
this.scaleFactorY = y;
}
}
}
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Drawing.Drawing2D;
namespace Svg.Transforms
{
public abstract class SvgTransform
{
public abstract Matrix Matrix { get; }
}
}
\ No newline at end of file
using System;
using System.ComponentModel;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Svg.Transforms
{
[TypeConverter(typeof(SvgTransformConverter))]
public class SvgTransformCollection : List<SvgTransform>
{
}
}
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.ComponentModel;
using System.Text.RegularExpressions;
namespace Svg.Transforms
{
public class SvgTransformConverter : TypeConverter
{
private static IEnumerable<string> SplitTransforms(string transforms)
{
int transformEnd = 0;
for (int i = 0; i < transforms.Length; i++)
{
if (transforms[i] == ')')
{
yield return transforms.Substring(transformEnd, i - transformEnd + 1).Trim();
transformEnd = i+1;
}
}
}
/// <summary>
/// Converts the given object to the type of this converter, using the specified context and culture information.
/// </summary>
/// <param name="context">An <see cref="T:System.ComponentModel.ITypeDescriptorContext"/> that provides a format context.</param>
/// <param name="culture">The <see cref="T:System.Globalization.CultureInfo"/> to use as the current culture.</param>
/// <param name="value">The <see cref="T:System.Object"/> to convert.</param>
/// <returns>
/// An <see cref="T:System.Object"/> that represents the converted value.
/// </returns>
/// <exception cref="T:System.NotSupportedException">The conversion cannot be performed. </exception>
public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
{
if (value is string)
{
SvgTransformCollection transformList = new SvgTransformCollection();
string[] parts;
string contents;
string transformName;
foreach (string transform in SvgTransformConverter.SplitTransforms((string)value))
{
if (string.IsNullOrEmpty(transform))
continue;
parts = transform.Split('(', ')');
transformName = parts[0].Trim();
contents = parts[1].Trim();
switch (transformName)
{
case "translate":
string[] coords = contents.Split(new char[]{',', ' '}, StringSplitOptions.RemoveEmptyEntries);
float x = float.Parse(coords[0].Trim());
float y = float.Parse(coords[1].Trim());
transformList.Add(new SvgTranslate(x, y));
break;
case "rotate":
float angle = float.Parse(contents);
transformList.Add(new SvgRotate(angle));
break;
case "scale":
float scaleFactor = float.Parse(contents);
transformList.Add(new SvgScale(scaleFactor));
break;
}
}
return transformList;
}
return base.ConvertFrom(context, culture, value);
}
}
}
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.Text;
namespace Svg.Transforms
{
public class SvgTranslate : SvgTransform
{
private float x;
private float y;
public float X
{
get { return x; }
set { this.x = value; }
}
public float Y
{
get { return y; }
set { this.y = value; }
}
public override System.Drawing.Drawing2D.Matrix Matrix
{
get
{
System.Drawing.Drawing2D.Matrix matrix = new System.Drawing.Drawing2D.Matrix();
matrix.Translate(this.X, this.Y);
return matrix;
}
}
public SvgTranslate(float x, float y)
{
this.x = x;
this.y = y;
}
public SvgTranslate(float x)
: this(x, 0.0f)
{
}
}
}
\ No newline at end of file
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Threading;
using System.Collections.Generic;
using System.Text;
using System.Web;
namespace Svg.Web
{
/// <summary>
/// A handler to asynchronously render Scalable Vector Graphics files (usually *.svg or *.xml file extensions).
/// </summary>
/// <remarks>
/// <para>If a crawler requests the SVG file the raw XML will be returned rather than the image to allow crawlers to better read the image.</para>
/// <para>Adding "?raw=true" to the querystring will alos force the handler to render the raw SVG.</para>
/// </remarks>
public class SvgHandler : IHttpAsyncHandler
{
Thread t;
/// <summary>
/// Gets a value indicating whether another request can use the <see cref="T:System.Web.IHttpHandler"/> instance.
/// </summary>
/// <value></value>
/// <returns>true if the <see cref="T:System.Web.IHttpHandler"/> instance is reusable; otherwise, false.</returns>
public bool IsReusable
{
get { return false; }
}
/// <summary>
/// Enables processing of HTTP Web requests by a custom HttpHandler that implements the <see cref="T:System.Web.IHttpHandler"/> interface.
/// </summary>
/// <param name="context">An <see cref="T:System.Web.HttpContext"/> object that provides references to the intrinsic server objects (for example, Request, Response, Session, and Server) used to service HTTP requests.</param>
public void ProcessRequest(HttpContext context)
{
// Not used
}
/// <summary>
/// Initiates an asynchronous call to the HTTP handler.
/// </summary>
/// <param name="context">An <see cref="T:System.Web.HttpContext"/> object that provides references to intrinsic server objects (for example, Request, Response, Session, and Server) used to service HTTP requests.</param>
/// <param name="cb">The <see cref="T:System.AsyncCallback"/> to call when the asynchronous method call is complete. If <paramref name="cb"/> is null, the delegate is not called.</param>
/// <param name="extraData">Any extra data needed to process the request.</param>
/// <returns>
/// An <see cref="T:System.IAsyncResult"/> that contains information about the status of the process.
/// </returns>
public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)
{
string path = context.Request.PhysicalPath;
if (!File.Exists(path))
{
throw new HttpException(404, "The requested file cannot be found.");
}
SvgAsyncRenderState reqState = new SvgAsyncRenderState(context, cb, extraData);
SvgAsyncRender asyncRender = new SvgAsyncRender(reqState);
ThreadStart ts = new ThreadStart(asyncRender.RenderSvg);
t = new Thread(ts);
t.Start();
return reqState;
}
/// <summary>
/// Provides an asynchronous process End method when the process ends.
/// </summary>
/// <param name="result">An <see cref="T:System.IAsyncResult"/> that contains information about the status of the process.</param>
public void EndProcessRequest(IAsyncResult result)
{
}
/// <summary>
/// The class to be used when
/// </summary>
protected sealed class SvgAsyncRender
{
private SvgAsyncRenderState _state;
public SvgAsyncRender(SvgAsyncRenderState state)
{
this._state = state;
}
private void RenderRawSvg()
{
this._state._context.Response.ContentType = "image/svg+xml";
this._state._context.Response.WriteFile(this._state._context.Request.PhysicalPath);
this._state._context.Response.End();
this._state.CompleteRequest();
return;
}
public void RenderSvg()
{
this._state._context.Response.AddFileDependency(this._state._context.Request.PhysicalPath);
this._state._context.Response.Cache.SetLastModifiedFromFileDependencies();
this._state._context.Response.Cache.SetETagFromFileDependencies();
// Allow crawlers to see the raw XML - they can get more information from it that way
if (this._state._context.Request.Browser.Crawler || !string.IsNullOrEmpty(this._state._context.Request.QueryString["raw"]))
{
this.RenderRawSvg();
}
try
{
SvgDocument document = SvgDocument.Open(this._state._context.Request.PhysicalPath);
using (Bitmap bitmap = document.Draw())
{
using (MemoryStream ms = new MemoryStream())
{
bitmap.Save(ms, ImageFormat.Png);
this._state._context.Response.ContentType = "image/png";
ms.WriteTo(this._state._context.Response.OutputStream);
}
}
}
catch (Exception exc)
{
System.Diagnostics.Trace.TraceError("An error occured while attempting to render the SVG image '" + this._state._context.Request.PhysicalPath + "': " + exc.Message);
}
finally
{
this._state._context.Response.End();
this._state.CompleteRequest();
}
}
}
/// <summary>
/// Represents the state of a request for SVG rendering.
/// </summary>
protected sealed class SvgAsyncRenderState : IAsyncResult
{
internal HttpContext _context;
internal AsyncCallback _callback;
internal object _extraData;
private bool _isCompleted = false;
private ManualResetEvent _callCompleteEvent = null;
/// <summary>
/// Initializes a new instance of the <see cref="SvgAsyncRenderState"/> class.
/// </summary>
/// <param name="context">The <see cref="HttpContext"/> of the request.</param>
/// <param name="callback">The delegate to be called when the rendering is complete.</param>
/// <param name="extraData">The extra data.</param>
public SvgAsyncRenderState(HttpContext context, AsyncCallback callback,
object extraData)
{
_context = context;
_callback = callback;
_extraData = extraData;
}
/// <summary>
/// Indicates that the rendering is complete and the waiting thread may proceed.
/// </summary>
internal void CompleteRequest()
{
_isCompleted = true;
lock (this)
{
if (_callCompleteEvent != null)
{
_callCompleteEvent.Set();
}
}
// if a callback was registered, invoke it now
if (_callback != null)
{
_callback(this);
}
}
// IAsyncResult
//
/// <summary>
/// Gets a user-defined object that qualifies or contains information about an asynchronous operation.
/// </summary>
/// <value></value>
/// <returns>A user-defined object that qualifies or contains information about an asynchronous operation.</returns>
public object AsyncState { get { return (_extraData); } }
/// <summary>
/// Gets an indication of whether the asynchronous operation completed synchronously.
/// </summary>
/// <value></value>
/// <returns>true if the asynchronous operation completed synchronously; otherwise, false.</returns>
public bool CompletedSynchronously { get { return (false); } }
/// <summary>
/// Gets an indication whether the asynchronous operation has completed.
/// </summary>
/// <value></value>
/// <returns>true if the operation is complete; otherwise, false.</returns>
public bool IsCompleted { get { return (_isCompleted); } }
/// <summary>
/// Gets a <see cref="T:System.Threading.WaitHandle"/> that is used to wait for an asynchronous operation to complete.
/// </summary>
/// <value></value>
/// <returns>A <see cref="T:System.Threading.WaitHandle"/> that is used to wait for an asynchronous operation to complete.</returns>
public WaitHandle AsyncWaitHandle
{
get
{
lock (this)
{
if (_callCompleteEvent == null)
{
_callCompleteEvent = new ManualResetEvent(false);
}
return _callCompleteEvent;
}
}
}
}
}
}
\ No newline at end of file
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