diff --git a/Basic Shapes/SvgVisualElementEvents.cs b/Basic Shapes/SvgVisualElementEvents.cs deleted file mode 100644 index e842aa94bf867d7166b062fa803b992e263c6749..0000000000000000000000000000000000000000 --- a/Basic Shapes/SvgVisualElementEvents.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace Svg -{ - public abstract partial class SvgVisualElement - { - private static readonly object _mouseOverKey = new object(); - private static readonly object _mouseOutKey = new object(); - private static readonly object _focusKey = new object(); - private static readonly object _activeKey = new object(); - private static readonly object _clickKey = new object(); - - public event EventHandler MouseOver - { - add { this.Events.AddHandler(_mouseOverKey, value); } - remove { this.Events.RemoveHandler(_mouseOverKey, value); } - } - - public event EventHandler MouseOut - { - add { this.Events.AddHandler(_mouseOutKey, value); } - remove { this.Events.RemoveHandler(_mouseOutKey, value); } - } - - public event EventHandler Focus - { - add { this.Events.AddHandler(_focusKey, value); } - remove { this.Events.RemoveHandler(_focusKey, value); } - } - - public event EventHandler Active - { - add { this.Events.AddHandler(_activeKey, value); } - remove { this.Events.RemoveHandler(_activeKey, value); } - } - - public event EventHandler Click - { - add { this.Events.AddHandler(_clickKey, value); } - remove { this.Events.RemoveHandler(_clickKey, value); } - } - } -} \ No newline at end of file diff --git a/Filter Effects/ISvgFilter.cs b/Filter Effects/ISvgFilter.cs deleted file mode 100644 index a80efb6e540b08998e830648e550b81f54e1e0ae..0000000000000000000000000000000000000000 --- a/Filter Effects/ISvgFilter.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Drawing; -using System.Drawing.Drawing2D; - -namespace Svg.FilterEffects -{ - public interface ISvgFilter - { - void ApplyFilter(Bitmap sourceGraphic, Graphics renderer); - List Primitives { get; } - Dictionary Results { get; } - SvgUnit Width { get; set; } - SvgUnit Height { get; set; } - } -} \ No newline at end of file diff --git a/Filter Effects/ISvgFilterable.cs b/Filter Effects/ISvgFilterable.cs index 3d20196ea5c521891207299debb7b58cca598be2..fcaeded1f7c4923628801ab10e2b32052f9464d0 100644 --- a/Filter Effects/ISvgFilterable.cs +++ b/Filter Effects/ISvgFilterable.cs @@ -6,6 +6,6 @@ namespace Svg.FilterEffects { public interface ISvgFilterable { - ISvgFilter Filter { get; set; } + SvgFilter Filter { get; set; } } } diff --git a/Filter Effects/SvgFilter.cs b/Filter Effects/SvgFilter.cs index ba0b65ac89312efcd9989ff9886d729546140f5d..1a6edb07126526f1b7a780bd6e18ba136d8f76d9 100644 --- a/Filter Effects/SvgFilter.cs +++ b/Filter Effects/SvgFilter.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using System.Collections.Generic; using System.Text; using System.Drawing; @@ -7,77 +8,161 @@ using System.Drawing.Drawing2D; namespace Svg.FilterEffects { - public class SvgFilter : SvgElement, ISvgFilter + /// + /// A filter effect consists of a series of graphics operations that are applied to a given source graphic to produce a modified graphical result. + /// + [SvgElement("filter")] + public sealed class SvgFilter : SvgElement { - private readonly List _primitives; - private readonly Dictionary _results; - private SvgUnit _width; - private SvgUnit _height; + private Bitmap sourceGraphic; + private Bitmap sourceAlpha; + /// + /// Gets or sets the width of the resulting filter graphic. + /// [SvgAttribute("width")] public SvgUnit Width { - get { return this._width; } - set { this._width = value; } + get { return this.Attributes.GetAttribute("width"); } + set { this.Attributes["width"] = value; } } + /// + /// Gets or sets the height of the resulting filter graphic. + /// [SvgAttribute("height")] public SvgUnit Height { - get { return this._height; } - set { this._height = value; } + get { return this.Attributes.GetAttribute("height"); } + set { this.Attributes["height"] = value; } } - public List Primitives - { - get { return this._primitives; } - } - - public Dictionary Results - { - get { return this._results; } - } + internal Dictionary> Buffer { get; private set; } + /// + /// Initializes a new instance of the class. + /// public SvgFilter() { - this._primitives = new List(); - this._results = new Dictionary(); + this.Buffer = new Dictionary>(); } + /// + /// Renders the and contents to the specified object. + /// + /// The object to render to. protected override void Render(SvgRenderer renderer) { // Do nothing } + /// + /// Creates a new object that is a copy of the current instance. + /// + /// + /// A new object that is a copy of this instance. + /// public override object Clone() { return (SvgFilter)this.MemberwiseClone(); } - public void ApplyFilter(Bitmap sourceGraphic, Graphics renderer) + public void ApplyFilter(SvgVisualElement element, SvgRenderer renderer) + { + this.Buffer.Clear(); + this.PopulateDefaults(element, renderer); + + IEnumerable primitives = this.Children.OfType(); + + if (primitives.Count() > 0) + { + foreach (var primitive in primitives) + { + this.Buffer.Add(primitive.Result, (e, r) => primitive.Process()); + } + + // Render the final filtered image + renderer.DrawImageUnscaled(this.Buffer.Last().Value(element, renderer), new Point(0, 0)); + } + } + + private void PopulateDefaults(SvgVisualElement element, SvgRenderer renderer) + { + this.ResetDefaults(); + + this.Buffer.Add(SvgFilterPrimitive.SourceGraphic, this.CreateSourceGraphic); + this.Buffer.Add(SvgFilterPrimitive.SourceAlpha, this.CreateSourceAlpha); + } + + #region Defaults + + private void ResetDefaults() { - // A bit inefficient to create all the defaults when they may not even be used - this.PopulateDefaults(sourceGraphic); - Bitmap result = null; + if (this.sourceGraphic != null) + { + this.sourceGraphic.Dispose(); + this.sourceGraphic = null; + } - foreach (SvgFilterPrimitive primitive in this.Primitives) + if (this.sourceAlpha != null) { - result = primitive.Apply(); - // Add the result to the dictionary for use by other primitives - this._results.Add(primitive.Result, result); + this.sourceAlpha.Dispose(); + this.sourceAlpha = null; + } + } + + private Bitmap CreateSourceGraphic(SvgVisualElement element, SvgRenderer renderer) + { + if (this.sourceGraphic == null) + { + RectangleF bounds = element.Path.GetBounds(); + this.sourceGraphic = new Bitmap((int)bounds.Width, (int)bounds.Height); + + using (var graphics = Graphics.FromImage(this.sourceGraphic)) + { + graphics.Clip = renderer.Clip; + graphics.Transform = renderer.Transform; + + element.RenderElement(SvgRenderer.FromGraphics(graphics)); + + graphics.Save(); + } } - // Render the final filtered image - renderer.DrawImageUnscaled(result, new Point(0,0)); + return this.sourceGraphic; } - private void PopulateDefaults(Bitmap sourceGraphic) + private Bitmap CreateSourceAlpha(SvgVisualElement element, SvgRenderer renderer) { - // Source graphic - //this._results.Add("SourceGraphic", sourceGraphic); + if (this.sourceAlpha == null) + { + Bitmap source = this.Buffer[SvgFilterPrimitive.SourceGraphic](element, renderer); + + float[][] colorMatrixElements = { + new float[] {0, 0, 0, 0, 0}, // red + new float[] {0, 0, 0, 0, 0}, // green + new float[] {0, 0, 0, 0, 0}, // blue + new float[] {0, 0, 0, 1, 1}, // alpha + new float[] {0, 0, 0, 0, 0} }; // translations + + var matrix = new ColorMatrix(colorMatrixElements); + + ImageAttributes attributes = new ImageAttributes(); + attributes.SetColorMatrix(matrix); + + this.sourceAlpha = new Bitmap(source.Width, source.Height); + + using (var graphics = Graphics.FromImage(this.sourceAlpha)) + { + + graphics.DrawImage(source, new Rectangle(0, 0, source.Width, source.Height), 0, 0, + source.Width, source.Height, GraphicsUnit.Pixel, attributes); + graphics.Save(); + } + } - // Source alpha - //this._results.Add("SourceAlpha", ImageProcessor.GetAlphaChannel(sourceGraphic)); + return this.sourceAlpha; } + #endregion } } \ No newline at end of file diff --git a/Filter Effects/SvgFilterPrimitive.cs b/Filter Effects/SvgFilterPrimitive.cs index 2588b47d18a3f14f85e3b58797fb368381ef474c..b962c343d0c346490901b4809bb7eb6131eec83c 100644 --- a/Filter Effects/SvgFilterPrimitive.cs +++ b/Filter Effects/SvgFilterPrimitive.cs @@ -6,42 +6,34 @@ using System.Drawing.Drawing2D; namespace Svg.FilterEffects { - public abstract class SvgFilterPrimitive + public abstract class SvgFilterPrimitive : SvgElement { - private string _in; - private string _in2; - private string _result; - private ISvgFilter _owner; + public static readonly string SourceGraphic = "SourceGraphic"; + public static readonly string SourceAlpha = "SourceAlpha"; + public static readonly string BackgroundImage = "BackgroundImage"; + public static readonly string BackgroundAlpha = "BackgroundAlpha"; + public static readonly string FillPaint = "FillPaint"; + public static readonly string StrokePaint = "StrokePaint"; - protected ISvgFilter Owner + [SvgAttribute("in")] + public string Input { - get { return this._owner; } - } - - public string In - { - get { return this._in; } - set { this._in = value; } - } - - public string In2 - { - get { return this._in2; } - set { this._in2 = value; } + get { return this.Attributes.GetAttribute("in"); } + set { this.Attributes["in"] = value; } } + [SvgAttribute("result")] public string Result { - get { return this._result; } - set { this._result = value; } + get { return this.Attributes.GetAttribute("result"); } + set { this.Attributes["result"] = value; } } - public SvgFilterPrimitive(ISvgFilter owner, string input) + protected SvgFilter Owner { - this._in = input; - this._owner = owner; + get { return (SvgFilter)this.Parent; } } - public abstract Bitmap Apply(); + public abstract Bitmap Process(); } } \ No newline at end of file diff --git a/Filter Effects/SvgGaussianBlur.cs b/Filter Effects/SvgGaussianBlur.cs deleted file mode 100644 index 2f55c23804160c7b469712ca15ea4243cc9442c1..0000000000000000000000000000000000000000 --- a/Filter Effects/SvgGaussianBlur.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Drawing; -using System.Drawing.Drawing2D; - -namespace Svg.FilterEffects -{ - public class SvgGaussianBlur : SvgFilterPrimitive - { - private float _standardDeviation; - - public SvgGaussianBlur(ISvgFilter owner, string inputGraphic) - : base(owner, inputGraphic) - { - - } - - /// - /// The standard deviation for the blur operation. - /// - public float StandardDeviation - { - get { return this._standardDeviation; } - set { this._standardDeviation = value; } - } - - public override Bitmap Apply() - { - Bitmap source = this.Owner.Results[this.In]; - Bitmap blur = new Bitmap(source.Width, source.Height); - - - - return source; - } - } -} \ No newline at end of file diff --git a/Filter Effects/SvgMerge.cs b/Filter Effects/SvgMerge.cs deleted file mode 100644 index 7809ceedfc7b99f2e052bffeb067700c32f3e60f..0000000000000000000000000000000000000000 --- a/Filter Effects/SvgMerge.cs +++ /dev/null @@ -1,40 +0,0 @@ -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 -{ - public class SvgMerge : SvgFilterPrimitive - { - private StringCollection _mergeResults; - - public StringCollection MergeResults - { - get { return this._mergeResults; } - } - - public SvgMerge(ISvgFilter owner, string input) - : base(owner, input) - { - this._mergeResults = new StringCollection(); - } - - public override Bitmap Apply() - { - Bitmap merged = new Bitmap((int)this.Owner.Width.Value, (int)this.Owner.Height.Value); - Graphics mergedGraphics = Graphics.FromImage(merged); - - foreach (string resultId in this.MergeResults) - mergedGraphics.DrawImageUnscaled(this.Owner.Results[resultId], new Point(0, 0)); - - mergedGraphics.Save(); - mergedGraphics.Dispose(); - - return merged; - } - } -} \ No newline at end of file diff --git a/Filter Effects/feGaussianBlur/RawBitmap.cs b/Filter Effects/feGaussianBlur/RawBitmap.cs new file mode 100644 index 0000000000000000000000000000000000000000..cde6f1ad6fa9d43581f529d73c07a0070a7eb8e3 --- /dev/null +++ b/Filter Effects/feGaussianBlur/RawBitmap.cs @@ -0,0 +1,69 @@ +using System; +using System.Drawing; +using System.Drawing.Imaging; +using System.Runtime.InteropServices; + +namespace Svg.FilterEffects +{ + internal sealed class RawBitmap : IDisposable + { + private Bitmap _originBitmap; + private BitmapData _bitmapData; + private IntPtr _ptr; + private int _bytes; + private byte[] _argbValues; + + public RawBitmap(Bitmap originBitmap) + { + _originBitmap = originBitmap; + _bitmapData = _originBitmap.LockBits(new Rectangle(0, 0, _originBitmap.Width, _originBitmap.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); + _ptr = _bitmapData.Scan0; + _bytes = this.Stride * _originBitmap.Height; + _argbValues = new byte[_bytes]; + Marshal.Copy(_ptr, _argbValues, 0, _bytes); + } + + #region IDisposable Members + + public void Dispose() + { + _originBitmap.UnlockBits(_bitmapData); + } + + #endregion + + public int Stride + { + get { return _bitmapData.Stride; } + } + + public int Width + { + get { return _bitmapData.Width; } + } + + public int Height + { + get { return _bitmapData.Height; } + } + + public byte[] ArgbValues + { + get { return _argbValues; } + set + { + _argbValues = value; + } + } + + public Bitmap Bitmap + { + get + { + Marshal.Copy(_argbValues, 0, _ptr, _bytes); + return _originBitmap; + } + } + + } +} \ No newline at end of file diff --git a/Filter Effects/feGaussianBlur/SvgGaussianBlur.cs b/Filter Effects/feGaussianBlur/SvgGaussianBlur.cs new file mode 100644 index 0000000000000000000000000000000000000000..6a553d44ae8a357bfc0804708b1ab6e505fea303 --- /dev/null +++ b/Filter Effects/feGaussianBlur/SvgGaussianBlur.cs @@ -0,0 +1,242 @@ +using System; +using System.Drawing; +using System.Collections.Generic; + +namespace Svg.FilterEffects +{ + public enum BlurType + { + Both, + HorizontalOnly, + VerticalOnly, + } + + [SvgElement("feGaussianBlur")] + public class SvgGaussianBlur + { + private int _radius; + 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 radius, BlurType blurType) + { + _radius = radius; + _blurType = blurType; + PreCalculate(); + } + + private void PreCalculate() + { + int sz = _radius * 2 + 1; + _kernel = new int[sz]; + _multable = new int[sz, 256]; + for (int i = 1; i <= _radius; i++) + { + int szi = _radius - i; + int szj = _radius + i; + _kernel[szj] = _kernel[szi] = (szi + 1) * (szi + 1); + _kernelSum += (_kernel[szj] + _kernel[szi]); + for (int j = 0; j < 256; j++) + { + _multable[szj, j] = _multable[szi, j] = _kernel[szj] * j; + } + } + _kernel[_radius] = (_radius + 1) * (_radius + 1); + _kernelSum += _kernel[_radius]; + for (int j = 0; j < 256; j++) + { + _multable[_radius, j] = _kernel[_radius] * j; + } + } + + public Bitmap Apply(Image inputImage) + { + using (RawBitmap src = new RawBitmap(new Bitmap(inputImage))) + { + using (RawBitmap dest = new RawBitmap(new Bitmap(inputImage.Width, inputImage.Height))) + { + int pixelCount = src.Width * src.Height; + int[] b = new int[pixelCount]; + int[] g = new int[pixelCount]; + int[] r = new int[pixelCount]; + int[] a = new int[pixelCount]; + + int[] b2 = new int[pixelCount]; + int[] g2 = new int[pixelCount]; + int[] r2 = new int[pixelCount]; + int[] a2 = new int[pixelCount]; + + int ptr = 0; + for (int i = 0; i < pixelCount; i++) + { + b[i] = src.ArgbValues[ptr]; + g[i] = src.ArgbValues[++ptr]; + r[i] = src.ArgbValues[++ptr]; + a[i] = src.ArgbValues[++ptr]; + ptr++; + } + + int bsum; + int gsum; + int rsum; + int asum; + int read; + + int start = 0; + int index = 0; + if (_blurType != BlurType.VerticalOnly) + { + for (int i = 0; i < pixelCount; i++) + { + bsum = gsum = rsum = asum = 0; + read = i - _radius; + for (int z = 0; z < _kernel.Length; z++) + { + if (read < start) + { + ptr = start; + } + else if (read > start + src.Width - 1) + { + ptr = start + src.Width - 1; + } + else + { + ptr = read; + } + bsum += _multable[z, b[ptr]]; + gsum += _multable[z, g[ptr]]; + rsum += _multable[z, r[ptr]]; + asum += _multable[z, a[ptr]]; + + ++read; + } + b2[i] = (bsum / _kernelSum); + g2[i] = (gsum / _kernelSum); + r2[i] = (rsum / _kernelSum); + a2[i] = (asum / _kernelSum); + + if (_blurType == BlurType.HorizontalOnly) + { + dest.ArgbValues[index] = (byte)(bsum / _kernelSum); + dest.ArgbValues[++index] = (byte)(gsum / _kernelSum); + dest.ArgbValues[++index] = (byte)(rsum / _kernelSum); + dest.ArgbValues[++index] = (byte)(asum / _kernelSum); + index++; + } + + if (i > 0 && i % src.Width == 0) + { + start += src.Width; + } + } + } + + if (_blurType == BlurType.HorizontalOnly) + { + return dest.Bitmap; + } + + int tempy; + index = 0; + for (int i = 0; i < src.Height; i++) + { + int y = i - _radius; + start = y * src.Width; + for (int j = 0; j < src.Width; j++) + { + bsum = gsum = rsum = asum = 0; + read = start + j; + tempy = y; + for (int z = 0; z < _kernel.Length; z++) + { + if (_blurType == BlurType.VerticalOnly) + { + if (tempy < 0) + { + ptr = j; + } + else if (tempy > src.Height - 1) + { + ptr = pixelCount - (src.Width - j); + } + else + { + ptr = read; + } + bsum += _multable[z, b[ptr]]; + gsum += _multable[z, g[ptr]]; + rsum += _multable[z, r[ptr]]; + asum += _multable[z, a[ptr]]; + } + else + { + if (tempy < 0) + { + ptr = j; + } + else if (tempy > src.Height - 1) + { + ptr = pixelCount - (src.Width - j); + } + else + { + ptr = read; + } + bsum += _multable[z, b2[ptr]]; + gsum += _multable[z, g2[ptr]]; + rsum += _multable[z, r2[ptr]]; + asum += _multable[z, a2[ptr]]; + } + read += src.Width; + ++tempy; + } + + dest.ArgbValues[index] = (byte)(bsum / _kernelSum); + dest.ArgbValues[++index] = (byte)(gsum / _kernelSum); + dest.ArgbValues[++index] = (byte)(rsum / _kernelSum); + dest.ArgbValues[++index] = (byte)(asum / _kernelSum); + index++; + } + } + return dest.Bitmap; + } + } + } + + public int Radius + { + get { return _radius; } + set + { + if (value < 1) + { + throw new InvalidOperationException("Radius must be greater then 0"); + } + _radius = value; + PreCalculate(); + } + } + + public BlurType BlurType + { + get { return _blurType; } + set + { + _blurType = value; + } + } + } +} \ No newline at end of file diff --git a/Filter Effects/feMerge/SvgMerge.cs b/Filter Effects/feMerge/SvgMerge.cs new file mode 100644 index 0000000000000000000000000000000000000000..6c1285bd314ec2b85a3ff3c2417962f71b453c53 --- /dev/null +++ b/Filter Effects/feMerge/SvgMerge.cs @@ -0,0 +1,38 @@ +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 +{ + public class SvgMerge : SvgFilterPrimitive + { + private StringCollection _mergeResults; + + public StringCollection MergeResults + { + get { return this._mergeResults; } + } + + public override Bitmap Process() + { + //Bitmap merged = new Bitmap((int)this.Owner.Width.Value, (int)this.Owner.Height.Value); + //Graphics mergedGraphics = Graphics.FromImage(merged); + + //foreach (string resultId in this.MergeResults) + //{ + // mergedGraphics.DrawImageUnscaled(this.Owner.Results[resultId](), new Point(0, 0)); + //} + + //mergedGraphics.Save(); + //mergedGraphics.Dispose(); + + //results.Add(this.Result, () => merged); + + return null; + } + } +} \ No newline at end of file diff --git a/Svg.csproj b/Svg.csproj index 1e5844ed296ccbcbac8472d1e6664324fda941b6..37194a4611da13fe3f3b2bd7c13a7acb4101b4e3 100644 --- a/Svg.csproj +++ b/Svg.csproj @@ -65,7 +65,6 @@ - @@ -85,12 +84,12 @@ - + - - + + @@ -121,7 +120,7 @@ - + diff --git a/Document Structure/SvgDocument.cs b/SvgDocument.cs similarity index 86% rename from Document Structure/SvgDocument.cs rename to SvgDocument.cs index 33f6496a374bba7ab6a8fdd36fd46b952dca414b..e350752d4c70099939ee7f90a2f282332862572f 100644 --- a/Document Structure/SvgDocument.cs +++ b/SvgDocument.cs @@ -12,7 +12,7 @@ using System.Xml; namespace Svg { /// - /// The class used to create and load all SVG documents. + /// The class used to create and load SVG documents. /// public class SvgDocument : SvgFragment, ITypeDescriptorContext { @@ -49,6 +49,9 @@ namespace Svg } } + /// + /// Gets or sets the Pixels Per Inch of the rendered image. + /// public int Ppi { get; set; } #region ITypeDescriptorContext Members @@ -106,7 +109,7 @@ namespace Svg } /// - /// Opens the document at the specified path and loads the contents. + /// Opens the document at the specified path and loads the SVG contents. /// /// A containing the path of the file to open. /// An with the contents loaded. @@ -117,11 +120,12 @@ namespace Svg } /// - /// Opens the document at the specified path and loads the contents. + /// Opens the document at the specified path and loads the SVG contents. /// /// A containing the path of the file to open. /// A dictionary of custom entity definitions to be used when resolving XML entities within the document. /// An with the contents loaded. + /// The document at the specified cannot be found. public static SvgDocument Open(string path, Dictionary entities) { if (string.IsNullOrEmpty(path)) @@ -147,10 +151,11 @@ namespace Svg } /// - /// Attempts to open an SVG document from the specified and adds the specified entities. + /// Opens an SVG document from the specified and adds the specified entities. /// /// The containing the SVG document to open. /// Custom entity definitions. + /// The parameter cannot be null. public static SvgDocument Open(Stream stream, Dictionary entities) { if (stream == null) @@ -164,6 +169,7 @@ namespace Svg { var elementStack = new Stack(); var value = new StringBuilder(); + bool elementEmpty; SvgElement element = null; SvgElement parent; SvgDocument svgDocument = null; @@ -179,7 +185,7 @@ namespace Svg case XmlNodeType.Element: // Does this element have a value or children // (Must do this check here before we progress to another node) - bool isEmpty = reader.IsEmptyElement; + elementEmpty = reader.IsEmptyElement; // Create element if (elementStack.Count > 0) { @@ -207,7 +213,7 @@ namespace Svg elementStack.Push(element); // Need to process if the element is empty - if (isEmpty) + if (elementEmpty) { goto case XmlNodeType.EndElement; } @@ -247,9 +253,20 @@ namespace Svg } } + /// + /// Opens an SVG document from the specified . + /// + /// The containing the SVG document XML. + /// The parameter cannot be null. public static SvgDocument Open(XmlDocument document) { - return null; + if (document == null) + { + throw new ArgumentNullException("document"); + } + + Stream stream = new MemoryStream(ASCIIEncoding.Default.GetBytes(document.InnerXml)); + return Open(stream, null); } public static Bitmap OpenAsBitmap(string path) @@ -279,7 +296,7 @@ namespace Svg throw new ArgumentNullException("renderer"); } - Render(renderer); + this.Render(renderer); } /// @@ -294,7 +311,7 @@ namespace Svg throw new ArgumentNullException("graphics"); } - Render(SvgRenderer.FromGraphics(graphics)); + this.Render(SvgRenderer.FromGraphics(graphics)); } /// diff --git a/SvgElementFactory.cs b/SvgElementFactory.cs index b96c1bbb15c640fe0db5a1f0f16522f994530dde..d83d080676c254986b4c0523ce2696253b0d965b 100644 --- a/SvgElementFactory.cs +++ b/SvgElementFactory.cs @@ -18,10 +18,16 @@ using Svg.Transforms; namespace Svg { + /// + /// Provides the methods required in order to parse and create instances from XML. + /// internal class SvgElementFactory { private static List availableElements; + /// + /// Gets a list of available types that can be used when creating an . + /// private static List AvailableElements { get @@ -30,6 +36,7 @@ namespace Svg { var svgTypes = from t in typeof(SvgDocument).Assembly.GetExportedTypes() where t.GetCustomAttributes(typeof(SvgElementAttribute), true).Length > 0 + && t.IsSubclassOf(typeof(SvgElement)) select new ElementInfo { ElementName = ((SvgElementAttribute)t.GetCustomAttributes(typeof(SvgElementAttribute), true)[0]).ElementName, ElementType = t }; availableElements = svgTypes.ToList(); @@ -39,20 +46,51 @@ namespace Svg } } + /// + /// Creates an from the current node in the specified . + /// + /// The containing the node to parse into an . + /// The parameter cannot be null. + /// The CreateDocument method can only be used to parse root <svg> elements. public static SvgDocument CreateDocument(XmlTextReader reader) { + if (reader == null) + { + throw new ArgumentNullException("reader"); + } + + if (reader.LocalName != "svg") + { + throw new InvalidOperationException("The CreateDocument method can only be used to parse root elements."); + } + return (SvgDocument)CreateElement(reader, true, null); } + /// + /// Creates an from the current node in the specified . + /// + /// The containing the node to parse into a subclass of . + /// The that the created element belongs to. + /// The and parameters cannot be null. public static SvgElement CreateElement(XmlTextReader reader, SvgDocument document) { + if (reader == null) + { + throw new ArgumentNullException("reader"); + } + + if (document == null) + { + throw new ArgumentNullException("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; Trace.TraceInformation("Begin CreateElement: {0}", elementName); @@ -137,11 +175,25 @@ namespace Svg } } + /// + /// Contains information about a type inheriting from . + /// private struct ElementInfo { + /// + /// Gets the SVG name of the . + /// public string ElementName { get; set; } + /// + /// Gets the of the subclass. + /// public Type ElementType { get; set; } + /// + /// Initializes a new instance of the struct. + /// + /// Name of the element. + /// Type of the element. public ElementInfo(string elementName, Type elementType) : this() { diff --git a/SvgRenderer.cs b/SvgRenderer.cs index 3c933b690c660a515f35cfb9ff8d615321489955..7af50e569dcc0e0386211c26516c376b0139432c 100644 --- a/SvgRenderer.cs +++ b/SvgRenderer.cs @@ -47,6 +47,11 @@ namespace Svg return renderer; } + public void DrawImageUnscaled(Image image, Point location) + { + this._innerGraphics.DrawImageUnscaled(image, location); + } + public void SetClip(Region region) { this._innerGraphics.SetClip(region, CombineMode.Complement);