diff --git a/Source/Basic Shapes/SvgCircle.cs b/Source/Basic Shapes/SvgCircle.cs index 87637a959eff620c05e0d1127f1f634f62f392f9..bdeba7a19b87fb8ec3a11bb73b78e10653a12570 100644 --- a/Source/Basic Shapes/SvgCircle.cs +++ b/Source/Basic Shapes/SvgCircle.cs @@ -139,5 +139,20 @@ namespace Svg { } + + + public override SvgElement DeepCopy() + { + return DeepCopy(); + } + + public override SvgElement DeepCopy() + { + var newObj = base.DeepCopy() as SvgCircle; + newObj.CenterX = this.CenterX; + newObj.CenterY = this.CenterY; + newObj.Radius = this.Radius; + return newObj; + } } } \ No newline at end of file diff --git a/Source/Basic Shapes/SvgEllipse.cs b/Source/Basic Shapes/SvgEllipse.cs index 3ec051319133f5969dca827ad7b16fff46f91609..4cce3f323e9a359a09a36a4b44e96f287160de42 100644 --- a/Source/Basic Shapes/SvgEllipse.cs +++ b/Source/Basic Shapes/SvgEllipse.cs @@ -115,5 +115,22 @@ namespace Svg public SvgEllipse() { } + + + + public override SvgElement DeepCopy() + { + return DeepCopy(); + } + + public override SvgElement DeepCopy() + { + var newObj = base.DeepCopy() as SvgEllipse; + newObj.CenterX = this.CenterX; + newObj.CenterY = this.CenterY; + newObj.RadiusX = this.RadiusX; + newObj.RadiusY = this.RadiusY; + return newObj; + } } } \ No newline at end of file diff --git a/Source/Basic Shapes/SvgImage.cs b/Source/Basic Shapes/SvgImage.cs new file mode 100644 index 0000000000000000000000000000000000000000..8262128859af67847fdeac6718e2d3bd9cd51488 --- /dev/null +++ b/Source/Basic Shapes/SvgImage.cs @@ -0,0 +1,118 @@ +using System; +using System.Drawing; +using System.Drawing.Drawing2D; +using Svg.Transforms; + +namespace Svg +{ + /// + /// Represents and SVG image + /// + [SvgElement("image")] + public class SvgImage : SvgVisualElement + { + /// + /// Initializes a new instance of the class. + /// + public SvgImage() + { + Width = new SvgUnit(0.0f); + Height = new SvgUnit(0.0f); + } + + /// + /// Gets an representing the top left point of the rectangle. + /// + public SvgPoint Location + { + get { return new SvgPoint(X, Y); } + } + + [SvgAttribute("x")] + public virtual SvgUnit X + { + get { return this.Attributes.GetAttribute("x"); } + set { this.Attributes["x"] = value; } + } + + [SvgAttribute("y")] + public virtual SvgUnit Y + { + get { return this.Attributes.GetAttribute("y"); } + set { this.Attributes["y"] = value; } + } + + + [SvgAttribute("width")] + public virtual SvgUnit Width + { + get { return this.Attributes.GetAttribute("width"); } + set { this.Attributes["width"] = value; } + } + + [SvgAttribute("height")] + public virtual SvgUnit Height + { + get { return this.Attributes.GetAttribute("height"); } + set { this.Attributes["height"] = value; } + } + + [SvgAttribute("href", SvgAttributeAttribute.XLinkNamespace)] + public virtual Uri Href + { + get { return this.Attributes.GetAttribute("href"); } + set { this.Attributes["href"] = value; } + } + + + + /// + /// Gets the bounds of the element. + /// + /// The bounds. + public override RectangleF Bounds + { + get { return new RectangleF(this.Location.ToDeviceValue(), new SizeF(this.Width, this.Height)); } + } + + /// + /// Gets the for this element. + /// + public override GraphicsPath Path + { + get + { + return null; + } + } + + /// + /// Renders the and contents to the specified object. + /// + protected override void Render(SvgRenderer renderer) + { + if (Width.Value > 0.0f && Height.Value > 0.0f) + { + //TODO: + //base.Render(renderer); + } + } + + + public override SvgElement DeepCopy() + { + return DeepCopy(); + } + + public override SvgElement DeepCopy() + { + var newObj = base.DeepCopy() as SvgImage; + newObj.Height = this.Height; + newObj.Width = this.Width; + newObj.X = this.X; + newObj.Y = this.Y; + newObj.Href = this.Href; + return newObj; + } + } +} \ No newline at end of file diff --git a/Source/Basic Shapes/SvgLine.cs b/Source/Basic Shapes/SvgLine.cs index 4712869a4021900484350f9d167e702a0eff41cf..baa2c9f9f23be6eeb08623574312a658dba0050e 100644 --- a/Source/Basic Shapes/SvgLine.cs +++ b/Source/Basic Shapes/SvgLine.cs @@ -81,5 +81,24 @@ namespace Svg { get { return this.Path.GetBounds(); } } + + public override SvgElement DeepCopy() + { + return DeepCopy(); + } + + public override SvgElement DeepCopy() + { + var newObj = base.DeepCopy() as SvgLine; + newObj.StartX = this.StartX; + newObj.EndX = this.EndX; + newObj.StartY = this.StartY; + newObj.EndY = this.EndY; + if (this.Fill != null) + newObj.Fill = this.Fill.DeepCopy() as SvgPaintServer; + + return newObj; + } + } } diff --git a/Source/Basic Shapes/SvgPolygon.cs b/Source/Basic Shapes/SvgPolygon.cs index 9f73f2bec63827b730d46de40e80f1eacebc508e..235f019e467e1a36b22f6d019eaaba144eb3e892 100644 --- a/Source/Basic Shapes/SvgPolygon.cs +++ b/Source/Basic Shapes/SvgPolygon.cs @@ -74,5 +74,20 @@ namespace Svg { get { return this.Path.GetBounds(); } } + + + public override SvgElement DeepCopy() + { + return DeepCopy(); + } + + public override SvgElement DeepCopy() + { + var newObj = base.DeepCopy() as SvgPolygon; + newObj.Points = new SvgUnitCollection(); + foreach (var pt in this.Points) + newObj.Points.Add(pt); + return newObj; + } } } \ No newline at end of file diff --git a/Source/Basic Shapes/SvgRectangle.cs b/Source/Basic Shapes/SvgRectangle.cs index a3797813a3301e4966fbce0c8c941a2474c4bc3f..317788f3a20ef2bbb14b83ddcc03b6bef9f2e3c7 100644 --- a/Source/Basic Shapes/SvgRectangle.cs +++ b/Source/Basic Shapes/SvgRectangle.cs @@ -1,6 +1,7 @@ using System; using System.Drawing; using System.Drawing.Drawing2D; +using Svg.Transforms; namespace Svg { @@ -250,5 +251,23 @@ namespace Svg base.Render(renderer); } } + + + public override SvgElement DeepCopy() + { + return DeepCopy(); + } + + public override SvgElement DeepCopy() + { + var newObj = base.DeepCopy() as SvgRectangle; + newObj.CornerRadiusX = this.CornerRadiusX; + newObj.CornerRadiusY = this.CornerRadiusY; + newObj.Height = this.Height; + newObj.Width = this.Width; + newObj.X = this.X; + newObj.Y = this.Y; + return newObj; + } } } \ No newline at end of file diff --git a/Source/Basic Shapes/SvgVisualElement.cs b/Source/Basic Shapes/SvgVisualElement.cs index 7ac47758d95c642856cdb0fb2ba6ed4c1746632f..e8408ced88a3098c5820a41a88c5fbce4b3eceb9 100644 --- a/Source/Basic Shapes/SvgVisualElement.cs +++ b/Source/Basic Shapes/SvgVisualElement.cs @@ -61,6 +61,18 @@ namespace Svg set { this.Attributes["clip-rule"] = value; } } + + /// + /// Gets the associated if one has been specified. + /// + [SvgAttribute("filter")] + public virtual Uri Filter + { + get { return this.Attributes.GetAttribute("filter"); } + set { this.Attributes["filter"] = value; } + } + + /// /// Gets or sets a value to determine if anti-aliasing should occur when the element is being rendered. /// @@ -199,5 +211,32 @@ namespace Svg { this.ResetClip(renderer); } + + public override SvgElement DeepCopy() + { + var newObj = base.DeepCopy() as SvgVisualElement; + newObj.ClipPath = this.ClipPath; + newObj.ClipRule = this.ClipRule; + newObj.Filter = this.Filter; + + newObj.Visible = this.Visible; + if (this.Fill != null) + newObj.Fill = this.Fill; + if (this.Stroke != null) + newObj.Stroke = this.Stroke; + newObj.FillRule = this.FillRule; + newObj.FillOpacity = this.FillOpacity; + newObj.StrokeWidth = this.StrokeWidth; + newObj.StrokeLineCap = this.StrokeLineCap; + newObj.StrokeLineJoin = this.StrokeLineJoin; + newObj.StrokeMiterLimit = this.StrokeMiterLimit; + newObj.StrokeDashArray = this.StrokeDashArray; + newObj.StrokeDashOffset = this.StrokeDashOffset; + newObj.StrokeOpacity = this.StrokeOpacity; + newObj.Opacity = this.Opacity; + + return newObj; + } + } } \ No newline at end of file diff --git a/Source/Clipping and Masking/SvgClipPath.cs b/Source/Clipping and Masking/SvgClipPath.cs index ddffc3a176fed27ec93c4f8399f7c3e6332e1230..7f9645db462ad4e04c9db990ec0e2726930f8051 100644 --- a/Source/Clipping and Masking/SvgClipPath.cs +++ b/Source/Clipping and Masking/SvgClipPath.cs @@ -115,5 +115,18 @@ namespace Svg { // Do nothing } + + + public override SvgElement DeepCopy() + { + return DeepCopy(); + } + + public override SvgElement DeepCopy() + { + var newObj = base.DeepCopy() as SvgClipPath; + newObj.ClipPathUnits = this.ClipPathUnits; + return newObj; + } } } diff --git a/Source/Clipping and Masking/SvgMask.cs b/Source/Clipping and Masking/SvgMask.cs index 971d5f032bcb7901fbf2c9a677ee1dacabad6e32..7728301f59ddad4a9c8b2f1d3223effed3eba1a5 100644 --- a/Source/Clipping and Masking/SvgMask.cs +++ b/Source/Clipping and Masking/SvgMask.cs @@ -6,5 +6,12 @@ namespace Svg { public class SvgMask : SvgElement { + + + public override SvgElement DeepCopy() + { + return DeepCopy(); + } + } } \ No newline at end of file diff --git a/Source/DataTypes/ISvgViewPort.cs b/Source/DataTypes/ISvgViewPort.cs index 8b7273444fc814c5ab9db0f26571bd76f5ff137b..e0d83908884e9e065abeafc7f5dfa86da6dd53ad 100644 --- a/Source/DataTypes/ISvgViewPort.cs +++ b/Source/DataTypes/ISvgViewPort.cs @@ -15,5 +15,6 @@ namespace Svg /// SvgViewBox ViewBox { get; set; } SvgAspectRatio AspectRatio { get; set; } + SvgOverflow Overflow { get; set; } } } diff --git a/Source/DataTypes/SvgColourInterpolation.cs b/Source/DataTypes/SvgColourInterpolation.cs new file mode 100644 index 0000000000000000000000000000000000000000..4d666539b6d8dbaa202c62954a54a5bd3fdc3d08 --- /dev/null +++ b/Source/DataTypes/SvgColourInterpolation.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Svg.DataTypes +{ + public enum SvgColourInterpolation + { + auto, + sRGB, + linearRGB, + inherit + } +} diff --git a/Source/DataTypes/SvgFontWeight.cs b/Source/DataTypes/SvgFontWeight.cs new file mode 100644 index 0000000000000000000000000000000000000000..227b3bfd8da266c57b8ebc4b3d67c0b1a24a219b --- /dev/null +++ b/Source/DataTypes/SvgFontWeight.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text; + +namespace Svg.DataTypes +{ + public enum SvgFontWeight + { + normal, + bold + } + + +} diff --git a/Source/DataTypes/SvgOrient.cs b/Source/DataTypes/SvgOrient.cs new file mode 100644 index 0000000000000000000000000000000000000000..9563fb74a53d0a43b28caaecda3c60ac5607c4cd --- /dev/null +++ b/Source/DataTypes/SvgOrient.cs @@ -0,0 +1,108 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.ComponentModel; +using System.Web.UI.WebControls; +using System.Globalization; + +namespace Svg +{ + /// + /// Represents an orientation in an Scalable Vector Graphics document. + /// + public class SvgOrient + { + private bool _isAuto = true; + private float _angle; + + public SvgOrient() + { + IsAuto = true; + } + + public SvgOrient(float angle) + { + Angle = angle; + } + + /// + /// Gets the value of the unit. + /// + public float Angle + { + get { return this._angle; } + set + { + this._angle = value; + this._isAuto = false; + } + } + + + /// + /// Gets the value of the unit. + /// + public bool IsAuto + { + get { return this._isAuto; } + set { + this._isAuto = value; + this._angle = 0f; + } + } + + + /// + /// Indicates whether this instance and a specified object are equal. + /// + /// Another object to compare to. + /// + /// true if and this instance are the same type and represent the same value; otherwise, false. + /// + public override bool Equals(object obj) + { + if (obj == null) return false; + if (!(obj.GetType() == typeof (SvgOrient))) return false; + + var unit = (SvgOrient)obj; + return (unit.IsAuto == this.IsAuto && unit.Angle == this.Angle); + } + + public override int GetHashCode() + { + return base.GetHashCode(); + } + + public override string ToString() + { + string type = string.Empty; + + if (this.IsAuto) + return "auto"; + else + return this.Angle.ToString(); + } + + ///// + ///// Performs an implicit conversion from to . + ///// + ///// The value. + ///// The result of the conversion. + //public static implicit operator float(SvgOrient value) + //{ + // return this.Angle; + //} + + /// + /// Performs an implicit conversion from to . + /// + /// The value. + /// The result of the conversion. + public static implicit operator SvgOrient(float value) + { + return new SvgOrient(value); + } + + } + +} diff --git a/Source/DataTypes/SvgOverflow.cs b/Source/DataTypes/SvgOverflow.cs new file mode 100644 index 0000000000000000000000000000000000000000..97bddcc17bae0f6b41c5f849773ddc2e46aed102 --- /dev/null +++ b/Source/DataTypes/SvgOverflow.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Svg +{ + public enum SvgOverflow + { + auto, + visible, + hidden, + scroll, + inherit + } +} diff --git a/Source/Document Structure/SvgDefinitionList.cs b/Source/Document Structure/SvgDefinitionList.cs index a3e099d98fc519031ba4eae40a4336a7d20a3f00..bd39d971b51de5823d58872100e8c7319d8bd6b5 100644 --- a/Source/Document Structure/SvgDefinitionList.cs +++ b/Source/Document Structure/SvgDefinitionList.cs @@ -25,5 +25,12 @@ namespace Svg { // Do nothing. Children should NOT be rendered. } + + + public override SvgElement DeepCopy() + { + return DeepCopy(); + } + } } \ No newline at end of file diff --git a/Source/Document Structure/SvgDescription.cs b/Source/Document Structure/SvgDescription.cs index d9a8b6cefb088b22b45e18242e8bc68c65f4b0d3..34006e9e92370b118694f3a8fd81f726a05ea915 100644 --- a/Source/Document Structure/SvgDescription.cs +++ b/Source/Document Structure/SvgDescription.cs @@ -21,5 +21,19 @@ namespace Svg { return this.Text; } + + + public override SvgElement DeepCopy() + { + return DeepCopy(); + } + + public override SvgElement DeepCopy() + { + var newObj = base.DeepCopy() as SvgDescription; + newObj.Text = this.Text; + return newObj; + } + } } \ No newline at end of file diff --git a/Source/Document Structure/SvgDocumentMetadata.cs b/Source/Document Structure/SvgDocumentMetadata.cs new file mode 100644 index 0000000000000000000000000000000000000000..a52cb8800c4bc452856354053d12d9dfa224ac0c --- /dev/null +++ b/Source/Document Structure/SvgDocumentMetadata.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Xml; + +namespace Svg +{ + /// + /// Represents a list of re-usable SVG components. + /// + [SvgElement("metadata")] + public class SvgDocumentMetadata : SvgElement + { + // private string _metadata; + + + /// + /// Initializes a new instance of the class. + /// + public SvgDocumentMetadata() + { + Content = ""; + } + + + //public string Metadata + //{ + // get { return _metadata; } + // set { _metadata = value; } + //} + + + /// + /// Renders the and contents to the specified object. + /// + /// The object to render to. + protected override void Render(SvgRenderer renderer) + { + // Do nothing. Children should NOT be rendered. + } + + protected override void WriteChildren(XmlTextWriter writer) + { + writer.WriteRaw(this.Content); //write out metadata as is + } + + + public override SvgElement DeepCopy() + { + return DeepCopy(); + } + + public override void InitialiseFromXML(XmlTextReader reader, SvgDocument document) + { + base.InitialiseFromXML(reader, document); + + //read in the metadata just as a string ready to be written straight back out again + Content = reader.ReadInnerXml(); + } + + } +} \ No newline at end of file diff --git a/Source/Document Structure/SvgFragment.cs b/Source/Document Structure/SvgFragment.cs index cf13d6d93736b8318aefa3a431f9e516090fa0c2..c7062beeef0c64f03b3e40c72dd6bbe3cc7e904b 100644 --- a/Source/Document Structure/SvgFragment.cs +++ b/Source/Document Structure/SvgFragment.cs @@ -46,6 +46,13 @@ namespace Svg set { this._height = value; } } + [SvgAttribute("overflow")] + public virtual SvgOverflow Overflow + { + get { return this.Attributes.GetAttribute("overflow"); } + set { this.Attributes["overflow"] = value; } + } + /// /// Gets or sets the viewport of the element. /// @@ -123,5 +130,22 @@ namespace Svg this.ViewBox = SvgViewBox.Empty; this.AspectRatio = new SvgAspectRatio(SvgPreserveAspectRatio.None); } + + + public override SvgElement DeepCopy() + { + return DeepCopy(); + } + + public override SvgElement DeepCopy() + { + var newObj = base.DeepCopy() as SvgFragment; + newObj.Height = this.Height; + newObj.Width = this.Width; + newObj.Overflow = this.Overflow; + newObj.ViewBox = this.ViewBox; + newObj.AspectRatio = this.AspectRatio; + return newObj; + } } } \ No newline at end of file diff --git a/Source/Document Structure/SvgGroup.cs b/Source/Document Structure/SvgGroup.cs index 38c69ac29c3ba4f82d84d0ede000cc3bc53c1eac..52ff11a5a14776962f07b630f77b02c488efc06c 100644 --- a/Source/Document Structure/SvgGroup.cs +++ b/Source/Document Structure/SvgGroup.cs @@ -4,6 +4,8 @@ using System.Xml; using System.Text; using System.Drawing; using System.Drawing.Drawing2D; +using System.Linq; +using Svg.Transforms; namespace Svg { @@ -74,5 +76,19 @@ namespace Svg this.ResetClip(renderer); this.PopTransforms(renderer); } + + + public override SvgElement DeepCopy() + { + return DeepCopy(); + } + + public override SvgElement DeepCopy() + { + var newObj = base.DeepCopy() as SvgGroup; + if (this.Fill != null) + newObj.Fill = this.Fill.DeepCopy() as SvgPaintServer; + return newObj; + } } } \ No newline at end of file diff --git a/Source/Document Structure/SvgUse.cs b/Source/Document Structure/SvgUse.cs index 4efaf3fae90ec1d8eadb404a68e90a0e20600cc0..cc5d4f820263cd0a5081d74c3d0add034556518c 100644 --- a/Source/Document Structure/SvgUse.cs +++ b/Source/Document Structure/SvgUse.cs @@ -90,5 +90,22 @@ namespace Svg this.PopTransforms(renderer); } + + + public override SvgElement DeepCopy() + { + return DeepCopy(); + } + + public override SvgElement DeepCopy() + { + var newObj = base.DeepCopy() as SvgUse; + newObj.ReferencedElement = this.ReferencedElement; + newObj.X = this.X; + newObj.Y = this.Y; + + return newObj; + } + } } \ No newline at end of file diff --git a/Source/Filter Effects/SvgFilter.cs b/Source/Filter Effects/SvgFilter.cs index 1a6edb07126526f1b7a780bd6e18ba136d8f76d9..a1946b2694a7e1e7d4184d2f23de4f8434dbeccf 100644 --- a/Source/Filter Effects/SvgFilter.cs +++ b/Source/Filter Effects/SvgFilter.cs @@ -5,6 +5,7 @@ using System.Text; using System.Drawing; using System.Drawing.Imaging; using System.Drawing.Drawing2D; +using Svg.DataTypes; namespace Svg.FilterEffects { @@ -17,6 +18,28 @@ namespace Svg.FilterEffects private Bitmap sourceGraphic; private Bitmap sourceAlpha; + + /// + /// Gets or sets the position where the left point of the filter. + /// + [SvgAttribute("x")] + public SvgUnit X + { + get { return this.Attributes.GetAttribute("x"); } + set { this.Attributes["x"] = value; } + } + + /// + /// Gets or sets the position where the top point of the filter. + /// + [SvgAttribute("y")] + public SvgUnit Y + { + get { return this.Attributes.GetAttribute("y"); } + set { this.Attributes["y"] = value; } + } + + /// /// Gets or sets the width of the resulting filter graphic. /// @@ -37,6 +60,19 @@ namespace Svg.FilterEffects set { this.Attributes["height"] = value; } } + + /// + /// Gets or sets the color-interpolation-filters of the resulting filter graphic. + /// NOT currently mapped through to bitmap + /// + [SvgAttribute("color-interpolation-filters")] + public SvgColourInterpolation ColorInterpolationFilters + { + get { return this.Attributes.GetAttribute("color-interpolation-filters"); } + set { this.Attributes["color-interpolation-filters"] = value; } + } + + internal Dictionary> Buffer { get; private set; } /// @@ -53,7 +89,7 @@ namespace Svg.FilterEffects /// The object to render to. protected override void Render(SvgRenderer renderer) { - // Do nothing + base.RenderChildren(renderer); } /// @@ -164,5 +200,23 @@ namespace Svg.FilterEffects return this.sourceAlpha; } #endregion + + + + public override SvgElement DeepCopy() + { + return DeepCopy(); + } + + public override SvgElement DeepCopy() + { + var newObj = base.DeepCopy() as SvgFilter; + newObj.Height = this.Height; + newObj.Width = this.Width; + newObj.X = this.X; + newObj.Y = this.Y; + newObj.ColorInterpolationFilters = this.ColorInterpolationFilters; + return newObj; + } } } \ No newline at end of file diff --git a/Source/Filter Effects/feColourMatrix/SvgColourMatrix.cs b/Source/Filter Effects/feColourMatrix/SvgColourMatrix.cs new file mode 100644 index 0000000000000000000000000000000000000000..9ae6f1b4e73e6bc52ddf0cf3282d42c0097e442b --- /dev/null +++ b/Source/Filter Effects/feColourMatrix/SvgColourMatrix.cs @@ -0,0 +1,58 @@ +using System; +using System.Drawing; +using System.Collections.Generic; +using Svg.Filter_Effects.feColourMatrix; + +namespace Svg.FilterEffects +{ + /// + /// Note: this is not used in calculations to bitmap - used only to allow for svg xml output + /// + [SvgElement("feColorMatrix")] + public class SvgColourMatrix : SvgFilterPrimitive + { + + /// + /// matrix | saturate | hueRotate | luminanceToAlpha + /// Indicates the type of matrix operation. The keyword 'matrix' indicates that a full 5x4 matrix of values will be provided. The other keywords represent convenience shortcuts to allow commonly used color operations to be performed without specifying a complete matrix. If attribute ‘type’ is not specified, then the effect is as if a value of matrix were specified. + /// Note: this is not used in calculations to bitmap - used only to allow for svg xml output + /// + [SvgAttribute("type")] + public SvgColourMatrixType Type { get; set; } + + + + /// + /// list of s + /// The contents of ‘values’ depends on the value of attribute ‘type’: + /// Note: this is not used in calculations to bitmap - used only to allow for svg xml output + /// + [SvgAttribute("values")] + public string Values { get; set; } + + + + + public override Bitmap Process() + { + return null; + } + + + public override SvgElement DeepCopy() + { + return DeepCopy(); + } + + public override SvgElement DeepCopy() + { + var newObj = base.DeepCopy() as SvgColourMatrix; + newObj.Type = this.Type; + newObj.Values = this.Values; + + return newObj; + } + + + } +} \ No newline at end of file diff --git a/Source/Filter Effects/feColourMatrix/SvgColourMatrixType.cs b/Source/Filter Effects/feColourMatrix/SvgColourMatrixType.cs new file mode 100644 index 0000000000000000000000000000000000000000..417c0ebbb0930d2e7bc526b821c6477b92d13476 --- /dev/null +++ b/Source/Filter Effects/feColourMatrix/SvgColourMatrixType.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Svg.Filter_Effects.feColourMatrix +{ + public enum SvgColourMatrixType + { + matrix, + saturate, + hueRotate, + luminanceToAlpha + } +} diff --git a/Source/Filter Effects/feGaussianBlur/SvgGaussianBlur.cs b/Source/Filter Effects/feGaussianBlur/SvgGaussianBlur.cs index 6a553d44ae8a357bfc0804708b1ab6e505fea303..c5183b6281b5e3ee3db05aa6c394a5632b1a9fd6 100644 --- a/Source/Filter Effects/feGaussianBlur/SvgGaussianBlur.cs +++ b/Source/Filter Effects/feGaussianBlur/SvgGaussianBlur.cs @@ -12,40 +12,43 @@ namespace Svg.FilterEffects } [SvgElement("feGaussianBlur")] - public class SvgGaussianBlur + public class SvgGaussianBlur : SvgFilterPrimitive { - private int _radius; - private int[] _kernel; + private int _stdDeviation; + private BlurType _blurType; + + private int[] _kernel; private int _kernelSum; private int[,] _multable; - private BlurType _blurType; public SvgGaussianBlur() : this(1, BlurType.Both) { } - public SvgGaussianBlur(int radius) - : this(radius, BlurType.Both) + public SvgGaussianBlur(int stdDeviation) + : this(stdDeviation, BlurType.Both) { } - public SvgGaussianBlur(int radius, BlurType blurType) + public SvgGaussianBlur(int stdDeviation, BlurType blurType) : base() { - _radius = radius; + _stdDeviation = stdDeviation; _blurType = blurType; PreCalculate(); } + + private void PreCalculate() { - int sz = _radius * 2 + 1; + int sz = _stdDeviation * 2 + 1; _kernel = new int[sz]; _multable = new int[sz, 256]; - for (int i = 1; i <= _radius; i++) + for (int i = 1; i <= _stdDeviation; i++) { - int szi = _radius - i; - int szj = _radius + i; + int szi = _stdDeviation - i; + int szj = _stdDeviation + i; _kernel[szj] = _kernel[szi] = (szi + 1) * (szi + 1); _kernelSum += (_kernel[szj] + _kernel[szi]); for (int j = 0; j < 256; j++) @@ -53,11 +56,11 @@ namespace Svg.FilterEffects _multable[szj, j] = _multable[szi, j] = _kernel[szj] * j; } } - _kernel[_radius] = (_radius + 1) * (_radius + 1); - _kernelSum += _kernel[_radius]; + _kernel[_stdDeviation] = (_stdDeviation + 1) * (_stdDeviation + 1); + _kernelSum += _kernel[_stdDeviation]; for (int j = 0; j < 256; j++) { - _multable[_radius, j] = _kernel[_radius] * j; + _multable[_stdDeviation, j] = _kernel[_stdDeviation] * j; } } @@ -101,7 +104,7 @@ namespace Svg.FilterEffects for (int i = 0; i < pixelCount; i++) { bsum = gsum = rsum = asum = 0; - read = i - _radius; + read = i - _stdDeviation; for (int z = 0; z < _kernel.Length; z++) { if (read < start) @@ -153,7 +156,7 @@ namespace Svg.FilterEffects index = 0; for (int i = 0; i < src.Height; i++) { - int y = i - _radius; + int y = i - _stdDeviation; start = y * src.Width; for (int j = 0; j < src.Width; j++) { @@ -216,20 +219,25 @@ namespace Svg.FilterEffects } } - public int Radius + /// + /// Gets or sets the radius of the blur (only allows for one value - not the two specified in the SVG Spec) + /// + [SvgAttribute("stdDeviation")] + public int StdDeviation { - get { return _radius; } + get { return _stdDeviation; } set { if (value < 1) { throw new InvalidOperationException("Radius must be greater then 0"); } - _radius = value; + _stdDeviation = value; PreCalculate(); } } + public BlurType BlurType { get { return _blurType; } @@ -238,5 +246,29 @@ namespace Svg.FilterEffects _blurType = value; } } + + + + public override Bitmap Process() + { + //Todo + + return null; + } + + + + public override SvgElement DeepCopy() + { + return DeepCopy(); + } + + public override SvgElement DeepCopy() + { + var newObj = base.DeepCopy() as SvgGaussianBlur; + newObj.StdDeviation = this.StdDeviation; + newObj.BlurType = this.BlurType; + return newObj; + } } } \ No newline at end of file diff --git a/Source/Filter Effects/feMerge/SvgMerge.cs b/Source/Filter Effects/feMerge/SvgMerge.cs index 3e9fc68bd361b4b7a45c68ce89818bfe00cd9b70..a18ffdc574531bd5b9605f749b4efe1bb9296a96 100644 --- a/Source/Filter Effects/feMerge/SvgMerge.cs +++ b/Source/Filter Effects/feMerge/SvgMerge.cs @@ -8,6 +8,8 @@ using System.Drawing.Imaging; namespace Svg.FilterEffects { + + [SvgElement("feMerge")] public class SvgMerge : SvgFilterPrimitive { public StringCollection MergeResults { get; private set; } @@ -19,6 +21,8 @@ namespace Svg.FilterEffects public override Bitmap Process() { + //Todo + //Bitmap merged = new Bitmap((int)this.Owner.Width.Value, (int)this.Owner.Height.Value); //Graphics mergedGraphics = Graphics.FromImage(merged); @@ -34,5 +38,12 @@ namespace Svg.FilterEffects return null; } + + + public override SvgElement DeepCopy() + { + throw new NotImplementedException(); + } + } } \ No newline at end of file diff --git a/Source/Filter Effects/feMerge/SvgMergeNode.cs b/Source/Filter Effects/feMerge/SvgMergeNode.cs new file mode 100644 index 0000000000000000000000000000000000000000..a302a7a814818de9d6cf8689d5cf297d7dbb6bf4 --- /dev/null +++ b/Source/Filter Effects/feMerge/SvgMergeNode.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Text; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Drawing.Imaging; + +namespace Svg.FilterEffects +{ + + [SvgElement("feMergeNode")] + public class SvgMergeNode : SvgFilterPrimitive + { + public override Bitmap Process() + { + //Todo + + return null; + } + + public override SvgElement DeepCopy() + { + throw new NotImplementedException(); + } + + } +} \ No newline at end of file diff --git a/Source/Filter Effects/feOffset/SvgOffset.cs b/Source/Filter Effects/feOffset/SvgOffset.cs new file mode 100644 index 0000000000000000000000000000000000000000..37680e72b2857a770e976066fb6186e143b95564 --- /dev/null +++ b/Source/Filter Effects/feOffset/SvgOffset.cs @@ -0,0 +1,58 @@ +using System; +using System.Drawing; +using System.Collections.Generic; +using Svg.Filter_Effects.feColourMatrix; + +namespace Svg.FilterEffects +{ + /// + /// Note: this is not used in calculations to bitmap - used only to allow for svg xml output + /// + [SvgElement("feOffset")] + public class SvgOffset : SvgFilterPrimitive + { + + + /// + /// The amount to offset the input graphic along the x-axis. The offset amount is expressed in the coordinate system established by attribute ‘primitiveUnits’ on the ‘filter’ element. + /// If the attribute is not specified, then the effect is as if a value of 0 were specified. + /// Note: this is not used in calculations to bitmap - used only to allow for svg xml output + /// + [SvgAttribute("dx")] + public SvgUnit Dx { get; set; } + + + /// + /// The amount to offset the input graphic along the y-axis. The offset amount is expressed in the coordinate system established by attribute ‘primitiveUnits’ on the ‘filter’ element. + /// If the attribute is not specified, then the effect is as if a value of 0 were specified. + /// Note: this is not used in calculations to bitmap - used only to allow for svg xml output + /// + [SvgAttribute("dy")] + public string Dy { get; set; } + + + + public override Bitmap Process() + { + return null; + } + + + + + public override SvgElement DeepCopy() + { + return DeepCopy(); + } + + public override SvgElement DeepCopy() + { + var newObj = base.DeepCopy() as SvgOffset; + newObj.Dx = this.Dx; + newObj.Dy = this.Dy; + + return newObj; + } + + } +} \ No newline at end of file diff --git a/Source/Painting/SvgColourServer.cs b/Source/Painting/SvgColourServer.cs index 718e53e4fc0b476f27c4addd2e83dcf962a187b4..a95bb37427b8228524edc01a3f5d8d3f54b493f9 100644 --- a/Source/Painting/SvgColourServer.cs +++ b/Source/Painting/SvgColourServer.cs @@ -45,5 +45,21 @@ namespace Svg // Return the hex value return String.Format("#{0}", c.ToArgb().ToString("x").Substring(2)); } + + + public override SvgElement DeepCopy() + { + return DeepCopy(); + } + + + public override SvgElement DeepCopy() + { + var newObj = base.DeepCopy() as SvgColourServer; + newObj.Colour = this.Colour; + return newObj; + + } + } } diff --git a/Source/Painting/SvgGradientServer.cs b/Source/Painting/SvgGradientServer.cs index 4731b4f05caf72da5faf19d0ddbcb4e28d93ea03..83070db57b4bcb51dc2148583fac318278d65fad 100644 --- a/Source/Painting/SvgGradientServer.cs +++ b/Source/Painting/SvgGradientServer.cs @@ -179,5 +179,17 @@ namespace Svg _stops.AddRange(this.InheritGradient.Stops); } } + + + public override SvgElement DeepCopy() + { + var newObj = base.DeepCopy() as SvgGradientServer; + newObj.SpreadMethod = this.SpreadMethod; + newObj.GradientUnits = this.GradientUnits; + newObj.InheritGradient = this.InheritGradient; + return newObj; + + } + } } \ No newline at end of file diff --git a/Source/Painting/SvgGradientStop.cs b/Source/Painting/SvgGradientStop.cs index 7fcbf8e1635820e6310a5b65061a182fa3b792e2..480f2423a6c2997eb051a5b0c098e19aaafdae84 100644 --- a/Source/Painting/SvgGradientStop.cs +++ b/Source/Painting/SvgGradientStop.cs @@ -71,5 +71,21 @@ namespace Svg this._colour = colour; this._opacity = 1.0f; } + + + public override SvgElement DeepCopy() + { + return DeepCopy(); + } + + public override SvgElement DeepCopy() + { + var newObj = base.DeepCopy() as SvgGradientStop; + newObj.Offset = this.Offset; + newObj.Colour = this.Colour; + newObj.Opacity = this.Opacity; + + return newObj; + } } } \ No newline at end of file diff --git a/Source/Painting/SvgLinearGradientServer.cs b/Source/Painting/SvgLinearGradientServer.cs index 8aeece0bc1746b1f43b8164aea6facf51292d1b3..7a85815e25efc4fd457070b69a9be24c3f310ec9 100644 --- a/Source/Painting/SvgLinearGradientServer.cs +++ b/Source/Painting/SvgLinearGradientServer.cs @@ -115,5 +115,24 @@ namespace Svg gradient.WrapMode = WrapMode.TileFlipX; return gradient; } + + + + public override SvgElement DeepCopy() + { + return DeepCopy(); + } + + + public override SvgElement DeepCopy() + { + var newObj = base.DeepCopy() as SvgLinearGradientServer; + newObj.X1 = this.X1; + newObj.Y1 = this.Y1; + newObj.X2 = this.X2; + newObj.Y2 = this.Y2; + return newObj; + + } } } \ No newline at end of file diff --git a/Source/Painting/SvgMarker.cs b/Source/Painting/SvgMarker.cs new file mode 100644 index 0000000000000000000000000000000000000000..cbe354aa35748dfeb4e1d597d3f1f9e1cd20af4d --- /dev/null +++ b/Source/Painting/SvgMarker.cs @@ -0,0 +1,117 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Web; +using System.Xml; +using System.Xml.Serialization; +using System.Drawing.Drawing2D; + +namespace Svg +{ + [SvgElement("marker")] + public class SvgMarker : SvgVisualElement, ISvgViewPort + { + private SvgOrient _svgOrient = new SvgOrient(); + + [SvgAttribute("refX")] + public virtual SvgUnit RefX + { + get { return this.Attributes.GetAttribute("refX"); } + set { this.Attributes["refX"] = value; } + } + + [SvgAttribute("refY")] + public virtual SvgUnit RefY + { + get { return this.Attributes.GetAttribute("refY"); } + set { this.Attributes["refY"] = value; } + } + + + [SvgAttribute("orient")] + public virtual SvgOrient Orient + { + get { return _svgOrient; } + set { _svgOrient = value; } + } + + + [SvgAttribute("overflow")] + public virtual SvgOverflow Overflow + { + get { return this.Attributes.GetAttribute("overflow"); } + set { this.Attributes["overflow"] = value; } + } + + + [SvgAttribute("viewBox")] + public virtual SvgViewBox ViewBox + { + get { return this.Attributes.GetAttribute("viewBox"); } + set { this.Attributes["viewBox"] = value; } + } + + + [SvgAttribute("preserveAspectRatio")] + public virtual SvgAspectRatio AspectRatio + { + get { return this.Attributes.GetAttribute("preserveAspectRatio"); } + set { this.Attributes["preserveAspectRatio"] = value; } + } + + + public override System.Drawing.Drawing2D.GraphicsPath Path + { + get + { + var path = this.Children.FirstOrDefault(x => x is SvgPath); + if (path != null) + return (path as SvgPath).Path; + return null; + } + } + + public override System.Drawing.RectangleF Bounds + { + get + { + var path = this.Path; + if (path != null) + return path.GetBounds(); + return new System.Drawing.RectangleF(); + } + } + + //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(); + } + + public override SvgElement DeepCopy() + { + var newObj = base.DeepCopy() as SvgMarker; + newObj.RefX = this.RefX; + newObj.RefY = this.RefY; + newObj.Orient = this.Orient; + newObj.ViewBox = this.ViewBox; + newObj.Overflow = this.Overflow; + newObj.AspectRatio = this.AspectRatio; + + return newObj; + } + } +} \ No newline at end of file diff --git a/Source/Painting/SvgPaintServer.cs b/Source/Painting/SvgPaintServer.cs index 115e7f1c5885c81a761fda2ae9620c32be142abe..2c2f7022cea1b684d5897d956cdaf2340943ec82 100644 --- a/Source/Painting/SvgPaintServer.cs +++ b/Source/Painting/SvgPaintServer.cs @@ -51,5 +51,8 @@ namespace Svg { return String.Format("url(#{0})", this.ID); } + + + } } \ No newline at end of file diff --git a/Source/Painting/SvgPatternServer.cs b/Source/Painting/SvgPatternServer.cs index 1bd345400d0e922bab14cac53482486a4d78b90d..983727b862cb65a4e0a36260a67c0361f10a9a70 100644 --- a/Source/Painting/SvgPatternServer.cs +++ b/Source/Painting/SvgPatternServer.cs @@ -21,6 +21,14 @@ namespace Svg private SvgUnit _y; private SvgViewBox _viewBox; + [SvgAttribute("overflow")] + public SvgOverflow Overflow + { + get { return this.Attributes.GetAttribute("overflow"); } + set { this.Attributes["overflow"] = value; } + } + + /// /// Specifies a supplemental transformation which is applied on top of any /// transformations necessary to create a new pattern coordinate system. @@ -149,5 +157,28 @@ namespace Svg return textureBrush; } + + + + + public override SvgElement DeepCopy() + { + return DeepCopy(); + } + + + public override SvgElement DeepCopy() + { + var newObj = base.DeepCopy() as SvgPatternServer; + newObj.Overflow = this.Overflow; + newObj.ViewBox = this.ViewBox; + newObj.AspectRatio = this.AspectRatio; + newObj.X = this.X; + newObj.Y = this.Y; + newObj.Width = this.Width; + newObj.Height = this.Height; + return newObj; + + } } } \ No newline at end of file diff --git a/Source/Painting/SvgRadialGradientServer.cs b/Source/Painting/SvgRadialGradientServer.cs index b806b1a20b9cf35b8846e71e35c295d40275920c..a305750159f241c70207f1c1ee1609eb49c14e48 100644 --- a/Source/Painting/SvgRadialGradientServer.cs +++ b/Source/Painting/SvgRadialGradientServer.cs @@ -78,5 +78,24 @@ namespace Svg return null; } + + + public override SvgElement DeepCopy() + { + return DeepCopy(); + } + + + public override SvgElement DeepCopy() + { + var newObj = base.DeepCopy() as SvgRadialGradientServer; + newObj.CenterX = this.CenterX; + newObj.CenterY = this.CenterY; + newObj.Radius = this.Radius; + newObj.FocalX = this.FocalX; + newObj.FocalY = this.FocalY; + return newObj; + + } } } \ No newline at end of file diff --git a/Source/Paths/SvgPath.cs b/Source/Paths/SvgPath.cs index e2b7762084d7ece343724b0da4ee1e6e96098336..f1135ff1ec181df966bbd4c3ec5210c161d511cb 100644 --- a/Source/Paths/SvgPath.cs +++ b/Source/Paths/SvgPath.cs @@ -46,6 +46,29 @@ namespace Svg set { this._pathLength = value; } } + + /// + /// Gets or sets the marker (end cap) of the path. + /// + [SvgAttribute("marker-end")] + public Uri MarkerEnd + { + get { return this.Attributes.GetAttribute("marker-end"); } + set { this.Attributes["marker-end"] = value; } + } + + + /// + /// Gets or sets the marker (start cap) of the path. + /// + [SvgAttribute("marker-start")] + public Uri MarkerStart + { + get { return this.Attributes.GetAttribute("marker-start"); } + set { this.Attributes["marker-start"] = value; } + } + + /// /// Gets the for this element. /// @@ -98,5 +121,70 @@ namespace Svg this._pathData = new SvgPathSegmentList(); this._pathData._owner = this; } + + /// + /// Renders the stroke of the to the specified + /// + /// The object to render to. + protected internal override void RenderStroke(SvgRenderer renderer) + { + if (this.Stroke != null) + { + float strokeWidth = this.StrokeWidth.ToDeviceValue(this); + using (var pen = new Pen(this.Stroke.GetBrush(this, this.StrokeOpacity), strokeWidth)) + { + if (this.StrokeDashArray != null && this.StrokeDashArray.Count > 0) + { + /* divide by stroke width - GDI behaviour that I don't quite understand yet.*/ + pen.DashPattern = this.StrokeDashArray.ConvertAll(u => u.Value / ((strokeWidth <= 0) ? 1 : strokeWidth)).ToArray(); + } + + //hardcoded transformation matrix. I am not sure why this is not in proportion or rotated correctly (something to do with how the endcaps are determined in GDI) + var transMatrix = new Matrix(); + transMatrix.Rotate(-90f); + transMatrix.Scale(.6f, .6f); + + if (this.MarkerStart != null) + { + var marker = this.OwnerDocument.GetElementById(this.MarkerStart.ToString()); + var markerPath = marker.Path.Clone() as GraphicsPath; + markerPath.Transform(transMatrix); + pen.CustomStartCap = new CustomLineCap(markerPath, null); + } + + if (this.MarkerEnd != null) + { + var marker = this.OwnerDocument.GetElementById(this.MarkerEnd.ToString()); + var markerPath = marker.Path.Clone() as GraphicsPath; + markerPath.Transform(transMatrix); + pen.CustomEndCap = new CustomLineCap(markerPath, null); + } + + renderer.DrawPath(pen, this.Path); + } + } + } + + + public override SvgElement DeepCopy() + { + return DeepCopy(); + } + + public override SvgElement DeepCopy() + { + var newObj = base.DeepCopy() as SvgPath; + foreach (var pathData in this.PathData) + newObj.PathData.Add(pathData.Clone()); + newObj.PathLength = this.PathLength; + newObj.MarkerStart = this.MarkerStart; + newObj.MarkerEnd = this.MarkerEnd; + return newObj; + + } + + + + } } \ No newline at end of file diff --git a/Source/Paths/SvgPathBuilder.cs b/Source/Paths/SvgPathBuilder.cs index 5e86d03f0607cc50406eb791ca5e76b9c15df093..b1c793bf4bc7dad591673703b75f9b54a96f56ac 100644 --- a/Source/Paths/SvgPathBuilder.cs +++ b/Source/Paths/SvgPathBuilder.cs @@ -217,7 +217,7 @@ namespace Svg for (var i = 0; i < path.Length; i++) { string command; - if (char.IsLetter(path[i])) + if (char.IsLetter(path[i]) && path[i] != 'e') //e is used in scientific notiation. but not svg path { command = path.Substring(commandStart, i - commandStart).Trim(); commandStart = i; @@ -247,8 +247,9 @@ namespace Svg private static IEnumerable ParseCoordinates(string coords) { // TODO: Handle "1-1" (new PointF(1, -1); - var parts = coords.Remove(0, 1).Replace("-", " -").Split(new[] { ',', ' ', '\r', '\n' }, - StringSplitOptions.RemoveEmptyEntries); + // var parts = coords.Remove(0, 1).Replace("-", " -").Split(new[] { ',', ' ', '\r', '\n' },StringSplitOptions.RemoveEmptyEntries); + //gareth: removed replacing '-' with ' -' - was screwing up scientific notiation + var parts = coords.Remove(0, 1).Split(new[] { ',', ' ', '\r', '\n' },StringSplitOptions.RemoveEmptyEntries); for (var i = 0; i < parts.Length; i++) { diff --git a/Source/Paths/SvgPathSegment.cs b/Source/Paths/SvgPathSegment.cs index 4323b2e6ffca39e560fefd862b475d23bf8ebe96..9cef8e75f263bd2070db33177ab9cbe812c0fde4 100644 --- a/Source/Paths/SvgPathSegment.cs +++ b/Source/Paths/SvgPathSegment.cs @@ -34,5 +34,10 @@ namespace Svg.Pathing } public abstract void AddToPath(GraphicsPath graphicsPath); + + public SvgPathSegment Clone() + { + return this.MemberwiseClone() as SvgPathSegment; + } } } diff --git a/Source/Svg.csproj b/Source/Svg.csproj index 3a939e64db12deb54a36cd3a083422ea202acb81..7aeece30c31782c765f9f496bc1e1599c1f18ca5 100644 --- a/Source/Svg.csproj +++ b/Source/Svg.csproj @@ -48,7 +48,7 @@ Full false - ..\..\vvvv\public\common\src\thirdparty\ + bin\Debug\ TRACE;DEBUG;REFLECTION prompt 4 @@ -58,7 +58,7 @@ PdbOnly true - ..\..\vvvv\public\common\src\thirdparty\ + bin\Release\ TRACE prompt 4 @@ -80,6 +80,7 @@ + @@ -90,18 +91,28 @@ + + + + + + - + + + + + diff --git a/Source/SvgAttributeAttribute.cs b/Source/SvgAttributeAttribute.cs index ace4a4d59063c1541119b0fdc07590bff632aa88..bb86f58876ceecb4b1b2e9eef7cf268b00f1f5af 100644 --- a/Source/SvgAttributeAttribute.cs +++ b/Source/SvgAttributeAttribute.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Text; using System.ComponentModel; @@ -11,7 +12,18 @@ namespace Svg [AttributeUsage(AttributeTargets.Property)] public class SvgAttributeAttribute : System.Attribute { - private const string SVG_NAMESPACE = "http://www.w3.org/2000/svg"; + /// + /// Gets a containing the XLink namespace (http://www.w3.org/1999/xlink). + /// + public const string SVG_NAMESPACE = "http://www.w3.org/2000/svg"; + public const string XLinkPrefix = "xlink"; + public const string XLinkNamespace = "http://www.w3.org/1999/xlink"; + + public static readonly List> Namespaces = new List>() + { + new KeyValuePair("", SVG_NAMESPACE), + new KeyValuePair(XLinkPrefix, XLinkNamespace) + }; private string _name; private string _namespace; @@ -36,6 +48,20 @@ namespace Svg return String.Compare(indicator.Name, this.Name) == 0; } + /// + /// Gets the name of the SVG attribute. + /// + public string NamespaceAndName + { + get + { + if (_namespace == SVG_NAMESPACE) + return _name; + return Namespaces.First(x => x.Value == _namespace).Key + ":" + _name; + } + } + + /// /// Gets the name of the SVG attribute. /// diff --git a/Source/SvgDocument.cs b/Source/SvgDocument.cs index e3c9c3c885224936425e03fa67ba76876db2c202..1237934a3186ae22a307f65009afbf2202f24ae9 100644 --- a/Source/SvgDocument.cs +++ b/Source/SvgDocument.cs @@ -19,13 +19,9 @@ namespace Svg public class SvgDocument : SvgFragment, ITypeDescriptorContext { public static readonly int PPI = 96; + private SvgElementIdManager _idManager; - /// - /// Gets a containing the XLink namespace (http://www.w3.org/1999/xlink). - /// - public static readonly string XLinkNamespace = "http://www.w3.org/1999/xlink"; - private SvgElementIdManager _idManager; /// /// Initializes a new instance of the class. @@ -340,7 +336,7 @@ namespace Svg var size = GetDimensions(); var bitmap = new Bitmap((int)Math.Ceiling(size.Width), (int)Math.Ceiling(size.Height)); - + // bitmap.SetResolution(300, 300); try { Draw(bitmap); @@ -406,5 +402,6 @@ namespace Svg this.Write(fs); } } + } } \ No newline at end of file diff --git a/Source/SvgElement.cs b/Source/SvgElement.cs index 09f131a560536a7bdb8ac36b51501349bdb9edbf..6bb904315bb0de3c7bb0177289330322015fff78 100644 --- a/Source/SvgElement.cs +++ b/Source/SvgElement.cs @@ -196,7 +196,7 @@ namespace Svg [SvgAttribute("transform")] public SvgTransformCollection Transforms { - get { return this.Attributes.GetAttribute("Transforms"); } + get { return (this.Attributes.GetAttribute("Transforms") ?? new SvgTransformCollection()); } set { this.Attributes["Transforms"] = value; } } @@ -271,13 +271,20 @@ namespace Svg /// /// Initializes a new instance of the class. /// - internal SvgElement() + public SvgElement() { this._children = new SvgElementCollection(this); this._eventHandlers = new EventHandlerList(); this._elementName = string.Empty; } + + public virtual void InitialiseFromXML(XmlTextReader reader, SvgDocument document) + { + + } + + /// /// Renders this element to the . /// @@ -299,9 +306,15 @@ namespace Svg writer.WriteStartElement(this.ElementName); if (this.ElementName == "svg") { - writer.WriteAttributeString("xmlns", "http://www.w3.org/2000/svg"); - writer.WriteAttributeString("version", "1.1"); - } + foreach (var ns in SvgAttributeAttribute.Namespaces) + { + if (string.IsNullOrEmpty(ns.Key)) + writer.WriteAttributeString("xmlns", ns.Value); + else + writer.WriteAttributeString("xmlns:" + ns.Key, ns.Value); + } + writer.WriteAttributeString("version", "1.1"); + } } this.WriteAttributes(writer); } @@ -339,13 +352,13 @@ namespace Svg { string value = (string)attr.Property.Converter.ConvertTo(propertyValue, typeof(string)); - writer.WriteAttributeString(attr.Attribute.Name, value); + writer.WriteAttributeString(attr.Attribute.NamespaceAndName, 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); + writer.WriteAttributeString(attr.Attribute.NamespaceAndName, value); } } } @@ -485,10 +498,39 @@ namespace Svg { return this.MemberwiseClone(); } + + public abstract SvgElement DeepCopy(); + + public virtual SvgElement DeepCopy() where T : SvgElement, new() + { + var newObj = new T(); + newObj.Content = this.Content; + newObj.ElementName = this.ElementName; +// if (this.Parent != null) + // this.Parent.Children.Add(newObj); + + if (this.Transforms != null) + { + newObj.Transforms = new SvgTransformCollection(); + foreach (var transform in this.Transforms) + newObj.Transforms.Add(transform.Clone() as SvgTransform); + } + + foreach (var child in this.Children) + { + newObj.Children.Add(child.DeepCopy()); + } + + + return newObj; + } } internal interface ISvgElement { + SvgElement Parent {get;} + SvgElementCollection Children { get; } + void Render(SvgRenderer renderer); } } \ No newline at end of file diff --git a/Source/SvgElementCollection.cs b/Source/SvgElementCollection.cs index dcf61ae7de088529f4657eea23d59f3b467fa4f7..206984855ae4d5813d6228e4b7bee0f7a3fad691 100644 --- a/Source/SvgElementCollection.cs +++ b/Source/SvgElementCollection.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Text; namespace Svg @@ -139,6 +140,32 @@ namespace Svg return removed; } + /// + /// expensive recursive search for nodes of type T + /// + /// + /// + public IEnumerable FindSvgElementsOf() where T : SvgElement + { + return _elements.Where(x => x is T).Select(x => x as T).Concat(_elements.SelectMany(x => x.Children.FindSvgElementsOf())); + } + + /// + /// expensive recursive search for first node of type T + /// + /// + /// + public T FindSvgElementOf() where T : SvgElement + { + return _elements.OfType().FirstOrDefault() ?? _elements.Select(x => x.Children.FindSvgElementOf()).FirstOrDefault(x => x != null); + } + + public T GetSvgElementOf() where T : SvgElement + { + return _elements.FirstOrDefault(x => x is T) as T; + } + + public IEnumerator GetEnumerator() { return this._elements.GetEnumerator(); diff --git a/Source/SvgElementFactory.cs b/Source/SvgElementFactory.cs index d00873c2078185326fc42596c9939b8ac165249f..5caf44a0814d06656712fca7727fb17f3759d568 100644 --- a/Source/SvgElementFactory.cs +++ b/Source/SvgElementFactory.cs @@ -100,8 +100,7 @@ namespace Svg if (createdElement != null) { - createdElement.ElementName = elementName; - SetAttributes(createdElement, reader, document); + SetAttributes(createdElement, reader, document); } //Trace.TraceInformation("End CreateElement"); @@ -135,7 +134,7 @@ namespace Svg SetPropertyValue(element, style[0].Trim(), style[1].Trim(), document); } - continue; + continue; } SetPropertyValue(element, reader.LocalName, reader.Value, document); diff --git a/Source/Text/SvgText.cs b/Source/Text/SvgText.cs index c860cf797dc4adc125adbca2b42cc90778ec4146..42e4b2dc1b8aba2b1d796ae6f9e124767c4c7493 100644 --- a/Source/Text/SvgText.cs +++ b/Source/Text/SvgText.cs @@ -5,6 +5,8 @@ using System.ComponentModel; using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Text; +using Svg.DataTypes; +using System.Linq; namespace Svg { @@ -19,12 +21,12 @@ namespace Svg private SvgUnit _letterSpacing; private SvgUnit _wordSpacing; private SvgUnit _fontSize; + private SvgFontWeight _fontWeight; private string _font; private string _fontFamily; private GraphicsPath _path; private SvgTextAnchor _textAnchor = SvgTextAnchor.Start; private static readonly SvgRenderer _stringMeasure; - /// /// Initializes the class. /// @@ -135,6 +137,18 @@ namespace Svg set { this._fontSize = value; this.IsPathDirty = true; } } + + /// + /// Refers to the boldness of the font. + /// + [SvgAttribute("font-weight")] + public virtual SvgFontWeight FontWeight + { + get { return this._fontWeight; } + set { this._fontWeight = value; this.IsPathDirty = true; } + } + + /// /// Set all font information. /// @@ -205,7 +219,11 @@ namespace Svg get { // Make sure the path is always null if there is no text - if (_path == null || this.IsPathDirty && !string.IsNullOrEmpty(this.Text)) + //if (string.IsNullOrEmpty(this.Text)) + // _path = null; + //NOT SURE WHAT THIS IS ABOUT - Path gets created again anyway - WTF? + + if (_path == null || this.IsPathDirty) { float fontSize = this.FontSize.ToDeviceValue(this); if (fontSize == 0.0f) @@ -213,70 +231,118 @@ namespace Svg fontSize = 1.0f; } - PointF location = PointF.Empty; - Font font = new Font(this._fontFamily, fontSize, FontStyle.Regular, GraphicsUnit.Pixel); - SizeF stringBounds = _stringMeasure.MeasureString(this.Text, font); - - // 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) - stringBounds.Height); - break; - case SvgTextAnchor.Middle: - location = new PointF(this.X.ToDeviceValue(this) - (stringBounds.Width / 2), this.Y.ToDeviceValue(this, true) - stringBounds.Height); - break; - case SvgTextAnchor.End: - location = new PointF(this.X.ToDeviceValue(this) - stringBounds.Width, this.Y.ToDeviceValue(this, true) - stringBounds.Height); - break; - } + FontStyle fontWeight = (this.FontWeight == SvgFontWeight.bold ? FontStyle.Bold : FontStyle.Regular); + Font font = new Font(this._fontFamily, fontSize, fontWeight, GraphicsUnit.Pixel); _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(), new FontFamily(this._fontFamily), 0, fontSize, location, StringFormat.GenericTypographic); - location = new PointF(_path.GetBounds().Width + start + letterSpacing, location.Y); - } - } - else - { - _path.AddString(word, new FontFamily(this._fontFamily), 0, fontSize, location, StringFormat.GenericTypographic); - } - - // Move the location of the word to be written along - location = new PointF(_path.GetBounds().Width + start + wordSpacing, location.Y); - } - } - else - { - if (!string.IsNullOrEmpty(this.Text)) - { - _path.AddString(this.Text, new FontFamily(this._fontFamily), 0, fontSize, location, StringFormat.GenericTypographic); - } - } + if (!string.IsNullOrEmpty(this.Text)) + DrawString(_path, this.X, this.Y, SvgUnit.Empty, SvgUnit.Empty, font, fontSize, this.Text); - _path.CloseFigure(); + foreach (var tspan in this.Children.Where(x => x is SvgTextSpan).Select(x => x as SvgTextSpan)) + { + if (!string.IsNullOrEmpty(tspan.Text)) + DrawString( + _path, + tspan.X == SvgUnit.Empty ? this.X: tspan.X, + tspan.Y == SvgUnit.Empty ? this.Y : tspan.Y, + tspan.DX, + tspan.DY, + font, + fontSize, + tspan.Text); + } + + _path.CloseFigure(); this.IsPathDirty = false; } return _path; } } + + + private void DrawString(GraphicsPath path, SvgUnit x, SvgUnit y, SvgUnit dx, SvgUnit dy, Font font, float fontSize, string text) + { + PointF location = PointF.Empty; + SizeF stringBounds = _stringMeasure.MeasureString(text, font); + + float xToDevice = x.ToDeviceValue(this) + dx.ToDeviceValue(this); + float yToDevice = y.ToDeviceValue(this, true) + dy.ToDeviceValue(this, true); + + // Minus FontSize because the x/y coords mark the bottom left, not bottom top. + switch (this.TextAnchor) + { + case SvgTextAnchor.Start: + location = new PointF(xToDevice, yToDevice - stringBounds.Height); + break; + case SvgTextAnchor.Middle: + location = new PointF(xToDevice - (stringBounds.Width / 2), yToDevice - stringBounds.Height); + break; + case SvgTextAnchor.End: + location = new PointF(xToDevice - stringBounds.Width, yToDevice - stringBounds.Height); + break; + } + + // 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) ? text.Split(' ') : new string[] { 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(), new FontFamily(this._fontFamily), (int)font.Style, fontSize, location, StringFormat.GenericTypographic); + location = new PointF(path.GetBounds().Width + start + letterSpacing, location.Y); + } + } + else + { + path.AddString(word, new FontFamily(this._fontFamily), (int)font.Style, fontSize, location, StringFormat.GenericTypographic); + } + + // Move the location of the word to be written along + location = new PointF(path.GetBounds().Width + start + wordSpacing, location.Y); + } + } + else + { + if (!string.IsNullOrEmpty(text)) + { + path.AddString(text, new FontFamily(this._fontFamily), (int)font.Style, fontSize, location, StringFormat.GenericTypographic); + } + } + + } + + + public override SvgElement DeepCopy() + { + return DeepCopy(); + } + + public override SvgElement DeepCopy() + { + var newObj = base.DeepCopy() as SvgText; + newObj.TextAnchor = this.TextAnchor; + newObj.WordSpacing = this.WordSpacing; + newObj.LetterSpacing = this.LetterSpacing; + newObj.Font = this.Font; + newObj.FontFamily = this.FontFamily; + newObj.FontSize = this.FontSize; + newObj.FontWeight = this.FontWeight; + newObj.X = this.X; + newObj.Y = this.Y; + return newObj; + } } } \ No newline at end of file diff --git a/Source/Text/SvgTextSpan.cs b/Source/Text/SvgTextSpan.cs index f7c6b01df660eea6844a8f8037a651bfb8a872e8..629e12fc3cac0ecbfd011be9d27d2d7c2db227f1 100644 --- a/Source/Text/SvgTextSpan.cs +++ b/Source/Text/SvgTextSpan.cs @@ -1,34 +1,94 @@ using System; using System.ComponentModel; using System.Collections.Generic; +using System.Drawing.Drawing2D; using System.Linq; using System.Text; namespace Svg { [SvgElement("tspan")] - public class SvgTextSpan : SvgText + public class SvgTextSpan : SvgElement { - /// - /// Gets or sets the X. - /// - /// The X. - [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public override SvgUnit X + private SvgUnit _x; + private SvgUnit _y; + private SvgUnit _dx; + private SvgUnit _dy; + + /// + /// Gets or sets the X. + /// + /// The X. + [SvgAttribute("x")] + public SvgUnit X { - get { return base.X; } - set { base.X = value; } - } - - /// - /// Gets or sets the Y. - /// - /// The Y. - [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public override SvgUnit Y + get { return this._x; } + set { this._x = value; } + } + + /// + /// Gets or sets the X. + /// + /// The X. + [SvgAttribute("y")] + public SvgUnit Y { - get { return base.Y; } - set { base.Y = value; } - } + get { return this._y; } + set { this._y = value; } + } + + + /// + /// Gets or sets the deltaX from the containing text. + /// + /// The dX. + [SvgAttribute("dx")] + public SvgUnit DX + { + get { return this._dx; } + set { this._dx = value; } + } + + /// + /// Gets or sets the deltaY from the containing text. + /// + /// The dY. + [SvgAttribute("dy")] + public SvgUnit DY + { + get { return this._dy; } + set { this._dy = value; } + } + + + /// + /// Gets or sets the text to be rendered. + /// + public virtual string Text + { + get { return base.Content; } + set { base.Content = value; this.Content = value; } + } + + + + public override SvgElement DeepCopy() + { + return DeepCopy(); + } + + public override SvgElement DeepCopy() + { + var newObj = base.DeepCopy() as SvgTextSpan; + newObj.X = this.X; + newObj.Y = this.Y; + newObj.DX = this.DX; + newObj.DY = this.DY; + newObj.Text = this.Text; + + return newObj; + } + + } } \ No newline at end of file diff --git a/Source/Transforms/SvgMatrix.cs b/Source/Transforms/SvgMatrix.cs index 9e1f4c7cdf379f4327a74505873c3ce3a00693fd..15f8adf782bb7084212835d9469ebca95ae235f2 100644 --- a/Source/Transforms/SvgMatrix.cs +++ b/Source/Transforms/SvgMatrix.cs @@ -45,5 +45,12 @@ namespace Svg.Transforms { this.points = m; } + + + public override object Clone() + { + return new SvgMatrix(this.Points); + } + } } \ No newline at end of file diff --git a/Source/Transforms/SvgRotate.cs b/Source/Transforms/SvgRotate.cs index 9ebf8f5a10ade6669f2da1fde35430cc48013461..dd4241dc1626779c5787ce679c5698055315d568 100644 --- a/Source/Transforms/SvgRotate.cs +++ b/Source/Transforms/SvgRotate.cs @@ -54,5 +54,11 @@ namespace Svg.Transforms this.CenterX = centerX; this.CenterY = centerY; } + + + public override object Clone() + { + return new SvgRotate(this.Angle, this.CenterX, this.CenterY); + } } } \ No newline at end of file diff --git a/Source/Transforms/SvgScale.cs b/Source/Transforms/SvgScale.cs index 03c1e2a53e047f9bf8f58ed069e46a91122d774a..1033579906c0c6386ae5c88df5f2929c837ed937 100644 --- a/Source/Transforms/SvgScale.cs +++ b/Source/Transforms/SvgScale.cs @@ -45,5 +45,11 @@ namespace Svg.Transforms this.scaleFactorX = x; this.scaleFactorY = y; } + + + public override object Clone() + { + return new SvgScale(this.X, this.Y); + } } } diff --git a/Source/Transforms/SvgShear.cs b/Source/Transforms/SvgShear.cs index b02b055f2ef2b133f74f35595fefac4f063f126b..3457f838e5728b29e26d3466f9eac44e17332a52 100644 --- a/Source/Transforms/SvgShear.cs +++ b/Source/Transforms/SvgShear.cs @@ -48,5 +48,11 @@ namespace Svg.Transforms this.shearFactorX = x; this.shearFactorY = y; } + + + public override object Clone() + { + return new SvgShear(this.X, this.Y); + } } } \ No newline at end of file diff --git a/Source/Transforms/SvgSkew.cs b/Source/Transforms/SvgSkew.cs index 38beb07fee2421a7d81fa739c4b1cc5a2065a1ce..3e5fb7630cef5bc79ad33d63377bd067931b05a8 100644 --- a/Source/Transforms/SvgSkew.cs +++ b/Source/Transforms/SvgSkew.cs @@ -35,5 +35,11 @@ namespace Svg.Transforms AngleX = x; AngleY = y; } + + + public override object Clone() + { + return new SvgSkew(this.AngleX, this.AngleY); + } } } \ No newline at end of file diff --git a/Source/Transforms/SvgTransform.cs b/Source/Transforms/SvgTransform.cs index 605823557ab5190236c92f3c7dc475b95b1b2282..3fee736d7841297b6334334b54166b44b6b22045 100644 --- a/Source/Transforms/SvgTransform.cs +++ b/Source/Transforms/SvgTransform.cs @@ -6,9 +6,11 @@ using System.Drawing.Drawing2D; namespace Svg.Transforms { - public abstract class SvgTransform + public abstract class SvgTransform : ICloneable { public abstract Matrix Matrix { get; } public abstract string WriteToString(); + + public abstract object Clone(); } } \ No newline at end of file diff --git a/Source/Transforms/SvgTransformCollection.cs b/Source/Transforms/SvgTransformCollection.cs index 775108e1f61a556e05f4affd43684a044c1478d3..9b7ce37d24d9ad6c37a5db65eba1609217ed402a 100644 --- a/Source/Transforms/SvgTransformCollection.cs +++ b/Source/Transforms/SvgTransformCollection.cs @@ -31,6 +31,14 @@ namespace Svg.Transforms return transformMatrix; } + + + public override bool Equals(object obj) + { + if (this.Count == 0 && this.Count == this.Count) //default will be an empty list + return true; + return base.Equals(obj); + } } } diff --git a/Source/Transforms/SvgTranslate.cs b/Source/Transforms/SvgTranslate.cs index 13eee570885e8216cb541d76cf065ae614c10d7f..77fb8378c2180920283b6693126236e8cb12e0e7 100644 --- a/Source/Transforms/SvgTranslate.cs +++ b/Source/Transforms/SvgTranslate.cs @@ -47,5 +47,12 @@ namespace Svg.Transforms : this(x, 0.0f) { } + + + public override object Clone() + { + return new SvgTranslate(this.x, this.y); + } + } } \ No newline at end of file