Commit 6998823a authored by Tebjan Halm's avatar Tebjan Halm
Browse files

* implemented fill modes

* fill can be null -> none in XML
* added type converters for enums
* added type converter for unitcollection
* fixes several viewbox bugs
* document can now draw into a given bitmap
* content of SVG tag is written (used by the text tag)
* changed font handling in text element, still need proper alignment
* changed intersparse character of SvgTransformConverter.cs to space, because inkscape couldn't parse comma
* added class diagram for basic shapes
parent 28333a39
<?xml version="1.0" encoding="utf-8"?>
<ClassDiagram MajorVersion="1" MinorVersion="1">
<Class Name="Svg.SvgCircle" Collapsed="true">
<Position X="0.5" Y="4.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAIAAAAAAACAAIAGAAAAAAAAAAAAAQAABAAAAAIAgA=</HashCode>
<FileName>Basic Shapes\SvgCircle.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="Svg.SvgEllipse" Collapsed="true">
<Position X="5" Y="4.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAABAAgAAAACAAIAGAAgGQAAAAAAAAQAABAAAAAAAgA=</HashCode>
<FileName>Basic Shapes\SvgEllipse.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="Svg.SvgLine" Collapsed="true">
<Position X="7.25" Y="4.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAyAiAAIAAAAAAAAAAAAADAAAAADAAAAAAgA=</HashCode>
<FileName>Basic Shapes\SvgLine.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="Svg.SvgPolygon" Collapsed="true">
<Position X="2.75" Y="4.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAACgAIAgAAAAAAAAAAAAAQAAAAAAAAAAgA=</HashCode>
<FileName>Basic Shapes\SvgPolygon.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="Svg.SvgPolyline" Collapsed="true">
<Position X="2.75" Y="6" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>Basic Shapes\SvgPolyline.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="Svg.SvgRectangle" Collapsed="true">
<Position X="9.5" Y="4.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAIBASCAAIAAAIAAEDAABAAAAQAABAAEAAAYgA=</HashCode>
<FileName>Basic Shapes\SvgRectangle.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="Svg.SvgVisualElement">
<Position X="11.25" Y="1.25" Width="1.5" />
<TypeIdentifier>
<HashCode>AACCEAAFAYAAgAKAAABAACABEAgBSsUIABAAAACAIgA=</HashCode>
<FileName>Basic Shapes\SvgVisualElement.cs</FileName>
</TypeIdentifier>
<ShowAsAssociation>
<Property Name="FillOpacity" />
<Property Name="FillRule" />
<Property Name="ClipRule" />
<Property Name="Opacity" />
<Property Name="StrokeLineCap" />
<Property Name="StrokeWidth" />
</ShowAsAssociation>
<Lollipop Position="1.003" />
</Class>
<Class Name="Svg.SvgGroup">
<Position X="9" Y="1.75" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAIAAAAAAAAAAAAACAAAABAAAAAAAgA=</HashCode>
<FileName>Document Structure\SvgGroup.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="Svg.SvgElement">
<Position X="6.25" Y="7.25" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAUiAAQAggRkAECBABEQAAREgACAQAAgBIAIAECIBI=</HashCode>
<FileName>SvgElement.cs</FileName>
</TypeIdentifier>
<Lollipop Position="0.2" />
</Class>
<Class Name="Svg.SvgDocument">
<Position X="10.5" Y="10.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAQAgAgACQIwQAAAQAAAAAQEAAAAAQCAAAAAEAAMA=</HashCode>
<FileName>SvgDocument.cs</FileName>
</TypeIdentifier>
<Lollipop Position="0.2" />
</Class>
<Struct Name="System.Single" Collapsed="true">
<Position X="16.25" Y="3" Width="1.5" />
<TypeIdentifier />
<Lollipop Position="0.2" />
</Struct>
<Struct Name="Svg.SvgUnit">
<Position X="18.25" Y="1.75" Width="1.5" />
<TypeIdentifier>
<HashCode>ABBAACAAAAAIAAYcgAIAAAAAAEAAAIAQAQAgAAEAAAA=</HashCode>
<FileName>DataTypes\SvgUnit.cs</FileName>
</TypeIdentifier>
<ShowAsAssociation>
<Property Name="Type" />
<Property Name="Value" />
</ShowAsAssociation>
</Struct>
<Enum Name="Svg.SvgFillRule">
<Position X="14" Y="1.25" Width="1.5" />
<TypeIdentifier>
<HashCode>AABAAAACAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>Painting\SvgFillRule.cs</FileName>
</TypeIdentifier>
</Enum>
<Enum Name="Svg.SvgClipRule">
<Position X="14" Y="3.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AABAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>Clipping and Masking\SvgClipRule.cs</FileName>
</TypeIdentifier>
</Enum>
<Enum Name="Svg.SvgStrokeLineCap">
<Position X="14" Y="4.75" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAACAAAAAAAAAABAAAAAAAAAAAAAAgAAIAAAA=</HashCode>
<FileName>Painting\SvgStrokeLineCap.cs</FileName>
</TypeIdentifier>
</Enum>
<Enum Name="Svg.SvgUnitType">
<Position X="20.25" Y="1.75" Width="1.5" />
<TypeIdentifier>
<HashCode>AAABAAAAAAEAgAAAAAABAAAAAAgAAEAAAAAAACEAAAA=</HashCode>
<FileName>DataTypes\SvgUnit.cs</FileName>
</TypeIdentifier>
</Enum>
<Font Name="Segoe UI" Size="9" />
</ClassDiagram>
\ No newline at end of file
...@@ -76,6 +76,7 @@ namespace Svg ...@@ -76,6 +76,7 @@ namespace Svg
{ {
this._dirty = true; this._dirty = true;
this._requiresSmoothRendering = false; this._requiresSmoothRendering = false;
this.Fill = new SvgColourServer(); //in case fill attribute is not set by xml, default fill is black
} }
/// <summary> /// <summary>
...@@ -121,6 +122,7 @@ namespace Svg ...@@ -121,6 +122,7 @@ namespace Svg
{ {
if (brush != null) if (brush != null)
{ {
this.Path.FillMode = this.FillRule == SvgFillRule.NonZero ? FillMode.Winding : FillMode.Alternate;
renderer.FillPath(brush, this.Path); renderer.FillPath(brush, this.Path);
} }
} }
......
...@@ -18,6 +18,7 @@ namespace Svg ...@@ -18,6 +18,7 @@ namespace Svg
/// <summary> /// <summary>
/// Gets or sets a value to determine whether the element will be rendered. /// Gets or sets a value to determine whether the element will be rendered.
/// </summary> /// </summary>
[TypeConverter(typeof(SvgBoolConverter))]
[SvgAttribute("visibility")] [SvgAttribute("visibility")]
public virtual bool Visible public virtual bool Visible
{ {
...@@ -31,7 +32,7 @@ namespace Svg ...@@ -31,7 +32,7 @@ namespace Svg
[SvgAttribute("fill")] [SvgAttribute("fill")]
public virtual SvgPaintServer Fill public virtual SvgPaintServer Fill
{ {
get { return (this.Attributes["Fill"] == null) ? new SvgColourServer() : (SvgPaintServer)this.Attributes["Fill"]; } get { return (this.Attributes["Fill"] == null) ? null : (SvgPaintServer)this.Attributes["Fill"]; }
set { this.Attributes["Fill"] = value; } set { this.Attributes["Fill"] = value; }
} }
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.ComponentModel;
namespace Svg namespace Svg
{ {
...@@ -13,6 +14,7 @@ namespace Svg ...@@ -13,6 +14,7 @@ namespace Svg
/// that point to infinity in any direction and then examining the places where a segment of the /// that point to infinity in any direction and then examining the places where a segment of the
/// shape crosses the ray.</para> /// shape crosses the ray.</para>
/// </remarks> /// </remarks>
[TypeConverter(typeof(SvgClipRuleConverter))]
public enum SvgClipRule public enum SvgClipRule
{ {
/// <summary> /// <summary>
......
...@@ -3,6 +3,7 @@ using System.ComponentModel; ...@@ -3,6 +3,7 @@ using System.ComponentModel;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Globalization;
namespace Svg namespace Svg
{ {
...@@ -12,6 +13,16 @@ namespace Svg ...@@ -12,6 +13,16 @@ namespace Svg
[TypeConverter(typeof(SvgUnitCollectionConverter))] [TypeConverter(typeof(SvgUnitCollectionConverter))]
public class SvgUnitCollection : List<SvgUnit> public class SvgUnitCollection : List<SvgUnit>
{ {
public override string ToString()
{
string ret = "";
foreach (var unit in this)
{
ret += unit.ToString() + " ";
}
return ret;
}
} }
/// <summary> /// <summary>
...@@ -49,5 +60,24 @@ namespace Svg ...@@ -49,5 +60,24 @@ namespace Svg
return base.ConvertFrom(context, culture, value); return base.ConvertFrom(context, culture, value);
} }
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)
{
if (destinationType == typeof(string))
{
return ((SvgUnitCollection)value).ToString();
}
return base.ConvertTo(context, culture, value, destinationType);
}
} }
} }
\ No newline at end of file
...@@ -137,7 +137,7 @@ namespace Svg ...@@ -137,7 +137,7 @@ namespace Svg
return string.Format("{0}, {1}, {2}, {3}", return string.Format("{0}, {1}, {2}, {3}",
viewBox.MinX.ToString(CultureInfo.InvariantCulture), viewBox.MinY.ToString(CultureInfo.InvariantCulture), viewBox.MinX.ToString(CultureInfo.InvariantCulture), viewBox.MinY.ToString(CultureInfo.InvariantCulture),
viewBox.MinX.ToString(CultureInfo.InvariantCulture), viewBox.MinY.ToString(CultureInfo.InvariantCulture)); viewBox.Width.ToString(CultureInfo.InvariantCulture), viewBox.Height.ToString(CultureInfo.InvariantCulture));
} }
return base.ConvertTo(context, culture, value, destinationType); return base.ConvertTo(context, culture, value, destinationType);
......
...@@ -66,10 +66,7 @@ namespace Svg ...@@ -66,10 +66,7 @@ namespace Svg
if (!this.ViewBox.Equals(SvgViewBox.Empty)) if (!this.ViewBox.Equals(SvgViewBox.Empty))
{ {
if (this.ViewBox.MinX > 0 || this.ViewBox.MinY > 0) renderer.TranslateTransform(-this.ViewBox.MinX, -this.ViewBox.MinY, MatrixOrder.Append);
{
renderer.TranslateTransform(this.ViewBox.MinX, this.ViewBox.MinY, MatrixOrder.Append);
}
renderer.ScaleTransform(this.Width.ToDeviceValue() / this.ViewBox.Width, this.Height.ToDeviceValue() / this.ViewBox.Height, MatrixOrder.Append); renderer.ScaleTransform(this.Width.ToDeviceValue() / this.ViewBox.Width, this.Height.ToDeviceValue() / this.ViewBox.Height, MatrixOrder.Append);
} }
......
using System;
using System.ComponentModel;
using System.Globalization;
namespace Svg
{
//just overrrides canconvert and returns true
public class BaseConverter : TypeConverter
{
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 sealed class SvgBoolConverter : BaseConverter
{
public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
{
if (value == null)
{
return true;
}
if (!(value is string))
{
throw new ArgumentOutOfRangeException("value must be a string.");
}
return (string)value == "visible" ? true : false;
}
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
{
if (destinationType == typeof(string))
{
return ((bool)value) ? "visible" : "hidden";
}
return base.ConvertTo(context, culture, value, destinationType);
}
}
//converts enums to lower case strings
public class EnumBaseConverter<T> : BaseConverter
{
public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
{
if (value == null)
{
return Activator.CreateInstance(typeof(T));
}
if (!(value is string))
{
throw new ArgumentOutOfRangeException("value must be a string.");
}
return (T)Enum.Parse(typeof(T), (string)value, true);
}
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
{
if (destinationType == typeof(string))
{
return ((T)value).ToString().ToLower();
}
return base.ConvertTo(context, culture, value, destinationType);
}
}
//implementation for fill-rule
public sealed class SvgFillRuleConverter : EnumBaseConverter<SvgFillRule>
{
}
//implementaton for clip rule
public sealed class SvgClipRuleConverter : EnumBaseConverter<SvgClipRule>
{
}
}
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
using System.ComponentModel;
namespace Svg namespace Svg
{ {
[TypeConverter(typeof(SvgFillRuleConverter))]
public enum SvgFillRule public enum SvgFillRule
{ {
NonZero, NonZero,
......
...@@ -48,7 +48,11 @@ namespace Svg ...@@ -48,7 +48,11 @@ namespace Svg
{ {
if (value is string) if (value is string)
{ {
return SvgPaintServerFactory.Create((string)value, (SvgDocument)context); var s = (string) value;
if(s == "none")
return null;
else
return SvgPaintServerFactory.Create(s, (SvgDocument)context);
} }
return base.ConvertFrom(context, culture, value); return base.ConvertFrom(context, culture, value);
...@@ -89,6 +93,10 @@ namespace Svg ...@@ -89,6 +93,10 @@ namespace Svg
{ {
return string.Format(CultureInfo.InvariantCulture, "url(#{0})", ((SvgPaintServer)value).ID); return string.Format(CultureInfo.InvariantCulture, "url(#{0})", ((SvgPaintServer)value).ID);
} }
else
{
return "none";
}
} }
return base.ConvertTo(context, culture, value, destinationType); return base.ConvertTo(context, culture, value, destinationType);
......
...@@ -16,12 +16,16 @@ ...@@ -16,12 +16,16 @@
<OldToolsVersion>3.5</OldToolsVersion> <OldToolsVersion>3.5</OldToolsVersion>
<UpgradeBackupLocation> <UpgradeBackupLocation>
</UpgradeBackupLocation> </UpgradeBackupLocation>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion> <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<IsWebBootstrapper>false</IsWebBootstrapper> <IsWebBootstrapper>false</IsWebBootstrapper>
<SccProjectName>SAK</SccProjectName> <SccProjectName>
<SccLocalPath>SAK</SccLocalPath> </SccProjectName>
<SccAuxPath>SAK</SccAuxPath> <SccLocalPath>
<SccProvider>SAK</SccProvider> </SccLocalPath>
<SccAuxPath>
</SccAuxPath>
<SccProvider>
</SccProvider>
<PublishUrl>publish\</PublishUrl> <PublishUrl>publish\</PublishUrl>
<Install>true</Install> <Install>true</Install>
<InstallFrom>Disk</InstallFrom> <InstallFrom>Disk</InstallFrom>
...@@ -36,12 +40,13 @@ ...@@ -36,12 +40,13 @@
<ApplicationVersion>1.0.0.%2a</ApplicationVersion> <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<UseApplicationTrust>false</UseApplicationTrust> <UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled> <BootstrapperEnabled>true</BootstrapperEnabled>
<TargetFrameworkProfile />
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols> <DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType> <DebugType>full</DebugType>
<Optimize>false</Optimize> <Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath> <OutputPath>..\..\..\..\..\..\Dev\vvvv\vvvv\public\common\src\thirdparty\</OutputPath>
<DefineConstants>TRACE;DEBUG;REFLECTION</DefineConstants> <DefineConstants>TRACE;DEBUG;REFLECTION</DefineConstants>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
...@@ -50,7 +55,7 @@ ...@@ -50,7 +55,7 @@
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType> <DebugType>pdbonly</DebugType>
<Optimize>true</Optimize> <Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath> <OutputPath>..\..\..\..\..\..\Dev\vvvv\vvvv\public\common\src\thirdparty\</OutputPath>
<DefineConstants>TRACE</DefineConstants> <DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
...@@ -97,6 +102,7 @@ ...@@ -97,6 +102,7 @@
<Compile Include="Filter Effects\SvgFilterPrimitive.cs" /> <Compile Include="Filter Effects\SvgFilterPrimitive.cs" />
<Compile Include="Filter Effects\feGaussianBlur\SvgGaussianBlur.cs" /> <Compile Include="Filter Effects\feGaussianBlur\SvgGaussianBlur.cs" />
<Compile Include="Filter Effects\feMerge\SvgMerge.cs" /> <Compile Include="Filter Effects\feMerge\SvgMerge.cs" />
<Compile Include="Painting\EnumConverters.cs" />
<Compile Include="SvgElementAttribute.cs" /> <Compile Include="SvgElementAttribute.cs" />
<Compile Include="SvgRenderer.cs" /> <Compile Include="SvgRenderer.cs" />
<Compile Include="Painting\SvgColourConverter.cs" /> <Compile Include="Painting\SvgColourConverter.cs" />
...@@ -187,6 +193,9 @@ ...@@ -187,6 +193,9 @@
<ItemGroup> <ItemGroup>
<Folder Include="Web\Resources\" /> <Folder Include="Web\Resources\" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<None Include="Basic Shapes\DOM.cd" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- 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. Other similar extension points exist, see Microsoft.Common.targets.
......
...@@ -8,6 +8,8 @@ using System.Drawing.Text; ...@@ -8,6 +8,8 @@ using System.Drawing.Text;
using System.IO; using System.IO;
using System.Text; using System.Text;
using System.Xml; using System.Xml;
using System.Threading;
using System.Globalization;
namespace Svg namespace Svg
{ {
...@@ -325,6 +327,27 @@ namespace Svg ...@@ -325,6 +327,27 @@ namespace Svg
var size = GetDimensions(); var size = GetDimensions();
var bitmap = new Bitmap((int)Math.Ceiling(size.Width), (int)Math.Ceiling(size.Height)); var bitmap = new Bitmap((int)Math.Ceiling(size.Width), (int)Math.Ceiling(size.Height));
try
{
Draw(bitmap);
}
catch
{
bitmap.Dispose();
throw;
}
//Trace.TraceInformation("End Render");
return bitmap;
}
/// <summary>
/// Renders the <see cref="SvgDocument"/> into a given Bitmap <see cref="Bitmap"/>.
/// </summary>
public virtual void Draw(Bitmap bitmap)
{
//Trace.TraceInformation("Begin Render");
try try
{ {
using (var renderer = SvgRenderer.FromImage(bitmap)) using (var renderer = SvgRenderer.FromImage(bitmap))
...@@ -338,22 +361,36 @@ namespace Svg ...@@ -338,22 +361,36 @@ namespace Svg
} }
catch catch
{ {
bitmap.Dispose();
throw; throw;
} }
//Trace.TraceInformation("End Render"); //Trace.TraceInformation("End Render");
return bitmap;
} }
public void Write(Stream stream) public void Write(Stream stream)
{ {
//Save previous culture and switch to invariant for writing
var previousCulture = Thread.CurrentThread.CurrentCulture;
Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
var xmlWriter = new XmlTextWriter(stream, Encoding.UTF8);
xmlWriter.Formatting = Formatting.Indented;
xmlWriter.WriteDocType("svg", "-//W3C//DTD SVG 1.1//EN", "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd", null);
this.WriteElement(xmlWriter);
xmlWriter.Close();
Thread.CurrentThread.CurrentCulture = previousCulture;
} }
public void Write(string path) public void Write(string path)
{ {
using(var fs = new FileStream(path, FileMode.Create, FileAccess.Write))
{
this.Write(fs);
}
} }
} }
} }
\ No newline at end of file
...@@ -297,6 +297,11 @@ namespace Svg ...@@ -297,6 +297,11 @@ namespace Svg
if (this.ElementName != String.Empty) if (this.ElementName != String.Empty)
{ {
writer.WriteStartElement(this.ElementName); writer.WriteStartElement(this.ElementName);
if (this.ElementName == "svg")
{
writer.WriteAttributeString("xmlns", "http://www.w3.org/2000/svg");
writer.WriteAttributeString("version", "1.1");
}
} }
this.WriteAttributes(writer); this.WriteAttributes(writer);
} }
...@@ -324,9 +329,23 @@ namespace Svg ...@@ -324,9 +329,23 @@ namespace Svg
if (propertyValue != null) if (propertyValue != null)
{ {
string value = (string)attr.Property.Converter.ConvertTo(propertyValue, typeof(string)); var type = propertyValue.GetType();
object defaultValue = null;
if(type.IsValueType)
defaultValue = Activator.CreateInstance(type);
if (!propertyValue.Equals(defaultValue) || type == typeof(float) || type == typeof(bool) || type == typeof(SvgColourServer))
{
string value = (string)attr.Property.Converter.ConvertTo(propertyValue, typeof(string));
writer.WriteAttributeString(attr.Attribute.Name, attr.Attribute.NameSpace, value); writer.WriteAttributeString(attr.Attribute.Name, value);
}
}
else if(attr.Attribute.Name == "fill") //if fill equals null, write 'none'
{
string value = (string)attr.Property.Converter.ConvertTo(propertyValue, typeof(string));
writer.WriteAttributeString(attr.Attribute.Name, value);
} }
} }
} }
...@@ -344,6 +363,11 @@ namespace Svg ...@@ -344,6 +363,11 @@ namespace Svg
protected virtual void WriteChildren(XmlTextWriter writer) protected virtual void WriteChildren(XmlTextWriter writer)
{ {
//write the content
if(!String.IsNullOrEmpty(this.Content))
writer.WriteString(this.Content);
//write all children
foreach (SvgElement child in this.Children) foreach (SvgElement child in this.Children)
{ {
child.Write(writer); child.Write(writer);
......
...@@ -19,7 +19,8 @@ namespace Svg ...@@ -19,7 +19,8 @@ namespace Svg
private SvgUnit _letterSpacing; private SvgUnit _letterSpacing;
private SvgUnit _wordSpacing; private SvgUnit _wordSpacing;
private SvgUnit _fontSize; private SvgUnit _fontSize;
private Font _font; private string _font;
private string _fontFamily;
private GraphicsPath _path; private GraphicsPath _path;
private SvgTextAnchor _textAnchor = SvgTextAnchor.Start; private SvgTextAnchor _textAnchor = SvgTextAnchor.Start;
private static readonly SvgRenderer _stringMeasure; private static readonly SvgRenderer _stringMeasure;
...@@ -39,7 +40,7 @@ namespace Svg ...@@ -39,7 +40,7 @@ namespace Svg
/// </summary> /// </summary>
public SvgText() public SvgText()
{ {
this._font = new Font(new FontFamily("Times New Roman"), 1.0f); this._fontFamily = "Times New Roman";
this._fontSize = new SvgUnit(0.0f); this._fontSize = new SvgUnit(0.0f);
} }
...@@ -58,7 +59,7 @@ namespace Svg ...@@ -58,7 +59,7 @@ namespace Svg
public virtual string Text public virtual string Text
{ {
get { return base.Content; } get { return base.Content; }
set { base.Content = value; this.IsPathDirty = true; } set { base.Content = value; this.IsPathDirty = true; this.Content = value; }
} }
/// <summary> /// <summary>
...@@ -118,10 +119,10 @@ namespace Svg ...@@ -118,10 +119,10 @@ namespace Svg
/// Indicates which font family is to be used to render the text. /// Indicates which font family is to be used to render the text.
/// </summary> /// </summary>
[SvgAttribute("font-family")] [SvgAttribute("font-family")]
public virtual Font FontFamily public virtual string FontFamily
{ {
get { return this._font; } get { return this._fontFamily; }
set { this._font = value; this.IsPathDirty = true; } set { this._fontFamily = value; this.IsPathDirty = true; }
} }
/// <summary> /// <summary>
...@@ -138,7 +139,7 @@ namespace Svg ...@@ -138,7 +139,7 @@ namespace Svg
/// Set all font information. /// Set all font information.
/// </summary> /// </summary>
[SvgAttribute("font")] [SvgAttribute("font")]
public virtual Font Font public virtual string Font
{ {
get { return this._font; } get { return this._font; }
set { this._font = value; this.IsPathDirty = true; } set { this._font = value; this.IsPathDirty = true; }
...@@ -186,12 +187,12 @@ namespace Svg ...@@ -186,12 +187,12 @@ namespace Svg
get { return this.Path.GetBounds(); } get { return this.Path.GetBounds(); }
} }
static private int MeasureString(SvgRenderer renderer, string text, Font font) static private RectangleF MeasureString(SvgRenderer renderer, string text, Font font)
{ {
GraphicsPath p = new GraphicsPath(); GraphicsPath p = new GraphicsPath();
p.AddString(text, font.FontFamily, 0, font.Size, new PointF(0.0f, 0.0f), StringFormat.GenericTypographic); p.AddString(text, font.FontFamily, 0, font.Size, new PointF(0.0f, 0.0f), StringFormat.GenericTypographic);
p.Transform(renderer.Transform); p.Transform(renderer.Transform);
return (int)(p.GetBounds().Width + 1.0f); return p.GetBounds();
} }
/// <summary> /// <summary>
...@@ -210,22 +211,23 @@ namespace Svg ...@@ -210,22 +211,23 @@ namespace Svg
{ {
fontSize = 1.0f; fontSize = 1.0f;
} }
int stringWidth; RectangleF stringBounds;
PointF location = PointF.Empty; PointF location = PointF.Empty;
Font font = new Font(this._fontFamily, fontSize, FontStyle.Regular, GraphicsUnit.Pixel);
// Minus FontSize because the x/y coords mark the bottom left, not bottom top. // Minus FontSize because the x/y coords mark the bottom left, not bottom top.
switch (this.TextAnchor) switch (this.TextAnchor)
{ {
case SvgTextAnchor.Start: case SvgTextAnchor.Start:
location = new PointF(this.X.ToDeviceValue(this), this.Y.ToDeviceValue(this, true) - fontSize); location = new PointF(this.X.ToDeviceValue(this), this.Y.ToDeviceValue(this, true) - this._fontSize);
break; break;
case SvgTextAnchor.Middle: case SvgTextAnchor.Middle:
stringWidth = SvgText.MeasureString(_stringMeasure, this.Text, new Font(this._font.FontFamily, fontSize)); stringBounds = SvgText.MeasureString(_stringMeasure, this.Text, font);
location = new PointF(this.X.ToDeviceValue(this) - (stringWidth / 2), this.Y.ToDeviceValue(this, true) - fontSize); location = new PointF(this.X.ToDeviceValue(this) - (stringBounds.Width / 2), this.Y.ToDeviceValue(this, true) - this._fontSize);
break; break;
case SvgTextAnchor.End: case SvgTextAnchor.End:
stringWidth = SvgText.MeasureString(_stringMeasure, this.Text, new Font(this._font.FontFamily, fontSize)); stringBounds = SvgText.MeasureString(_stringMeasure, this.Text, font);
location = new PointF(this.X.ToDeviceValue(this) - stringWidth, this.Y.ToDeviceValue(this, true) - fontSize); location = new PointF(this.X.ToDeviceValue(this) - stringBounds.Width, this.Y.ToDeviceValue(this, true) - this._fontSize);
break; break;
} }
...@@ -249,13 +251,13 @@ namespace Svg ...@@ -249,13 +251,13 @@ namespace Svg
char[] characters = word.ToCharArray(); char[] characters = word.ToCharArray();
foreach (char currentCharacter in characters) foreach (char currentCharacter in characters)
{ {
_path.AddString(currentCharacter.ToString(), this._font.FontFamily, 0, fontSize, location, StringFormat.GenericTypographic); _path.AddString(currentCharacter.ToString(), new FontFamily(this._fontFamily), 0, fontSize, location, StringFormat.GenericTypographic);
location = new PointF(_path.GetBounds().Width + start + letterSpacing, location.Y); location = new PointF(_path.GetBounds().Width + start + letterSpacing, location.Y);
} }
} }
else else
{ {
_path.AddString(word, this._font.FontFamily, 0, fontSize, location, StringFormat.GenericTypographic); _path.AddString(word, new FontFamily(this._fontFamily), 0, fontSize, location, StringFormat.GenericTypographic);
} }
// Move the location of the word to be written along // Move the location of the word to be written along
...@@ -266,7 +268,7 @@ namespace Svg ...@@ -266,7 +268,7 @@ namespace Svg
{ {
if (!string.IsNullOrEmpty(this.Text)) if (!string.IsNullOrEmpty(this.Text))
{ {
_path.AddString(this.Text, this._font.FontFamily, 0, fontSize, location, StringFormat.GenericTypographic); _path.AddString(this.Text, new FontFamily(this._fontFamily), 0, fontSize, location, StringFormat.GenericTypographic);
} }
} }
......
...@@ -194,7 +194,7 @@ namespace Svg.Transforms ...@@ -194,7 +194,7 @@ namespace Svg.Transforms
if (transforms != null) if (transforms != null)
{ {
return string.Join(",", transforms.Select(t => t.WriteToString()).ToArray()); return string.Join(" ", transforms.Select(t => t.WriteToString()).ToArray());
} }
} }
......
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