Commit 101984ba authored by davescriven's avatar davescriven
Browse files

- Fixed #7986: public static SvgDocument Open(XmlDocument document) returns...

- Fixed #7986: public static SvgDocument Open(XmlDocument document) returns null: Implemented the proposed solution
- Added more XML API comments.
- Removed SvgVisualElementEvents.cs class - this was not used and not likely to be used
parent 76fbb491
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
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<SvgFilterPrimitive> Primitives { get; }
Dictionary<string, Bitmap> Results { get; }
SvgUnit Width { get; set; }
SvgUnit Height { get; set; }
}
}
\ No newline at end of file
...@@ -6,6 +6,6 @@ namespace Svg.FilterEffects ...@@ -6,6 +6,6 @@ namespace Svg.FilterEffects
{ {
public interface ISvgFilterable public interface ISvgFilterable
{ {
ISvgFilter Filter { get; set; } SvgFilter Filter { get; set; }
} }
} }
using System; using System;
using System.Linq;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
using System.Drawing; using System.Drawing;
...@@ -7,77 +8,161 @@ using System.Drawing.Drawing2D; ...@@ -7,77 +8,161 @@ using System.Drawing.Drawing2D;
namespace Svg.FilterEffects namespace Svg.FilterEffects
{ {
public class SvgFilter : SvgElement, ISvgFilter /// <summary>
/// A filter effect consists of a series of graphics operations that are applied to a given source graphic to produce a modified graphical result.
/// </summary>
[SvgElement("filter")]
public sealed class SvgFilter : SvgElement
{ {
private readonly List<SvgFilterPrimitive> _primitives; private Bitmap sourceGraphic;
private readonly Dictionary<string, Bitmap> _results; private Bitmap sourceAlpha;
private SvgUnit _width;
private SvgUnit _height;
/// <summary>
/// Gets or sets the width of the resulting filter graphic.
/// </summary>
[SvgAttribute("width")] [SvgAttribute("width")]
public SvgUnit Width public SvgUnit Width
{ {
get { return this._width; } get { return this.Attributes.GetAttribute<SvgUnit>("width"); }
set { this._width = value; } set { this.Attributes["width"] = value; }
} }
/// <summary>
/// Gets or sets the height of the resulting filter graphic.
/// </summary>
[SvgAttribute("height")] [SvgAttribute("height")]
public SvgUnit Height public SvgUnit Height
{ {
get { return this._height; } get { return this.Attributes.GetAttribute<SvgUnit>("height"); }
set { this._height = value; } set { this.Attributes["height"] = value; }
} }
public List<SvgFilterPrimitive> Primitives internal Dictionary<string, Func<SvgVisualElement, SvgRenderer, Bitmap>> Buffer { get; private set; }
{
get { return this._primitives; }
}
public Dictionary<string, Bitmap> Results
{
get { return this._results; }
}
/// <summary>
/// Initializes a new instance of the <see cref="SvgFilter"/> class.
/// </summary>
public SvgFilter() public SvgFilter()
{ {
this._primitives = new List<SvgFilterPrimitive>(); this.Buffer = new Dictionary<string, Func<SvgVisualElement, SvgRenderer, Bitmap>>();
this._results = new Dictionary<string, Bitmap>();
} }
/// <summary>
/// Renders the <see cref="SvgElement"/> and contents to the specified <see cref="SvgRenderer"/> object.
/// </summary>
/// <param name="renderer">The <see cref="SvgRenderer"/> object to render to.</param>
protected override void Render(SvgRenderer renderer) protected override void Render(SvgRenderer renderer)
{ {
// Do nothing // Do nothing
} }
/// <summary>
/// Creates a new object that is a copy of the current instance.
/// </summary>
/// <returns>
/// A new object that is a copy of this instance.
/// </returns>
public override object Clone() public override object Clone()
{ {
return (SvgFilter)this.MemberwiseClone(); return (SvgFilter)this.MemberwiseClone();
} }
public void ApplyFilter(Bitmap sourceGraphic, Graphics renderer) public void ApplyFilter(SvgVisualElement element, SvgRenderer renderer)
{ {
// A bit inefficient to create all the defaults when they may not even be used this.Buffer.Clear();
this.PopulateDefaults(sourceGraphic); this.PopulateDefaults(element, renderer);
Bitmap result = null;
IEnumerable<SvgFilterPrimitive> primitives = this.Children.OfType<SvgFilterPrimitive>();
foreach (SvgFilterPrimitive primitive in this.Primitives) if (primitives.Count() > 0)
{ {
result = primitive.Apply(); foreach (var primitive in primitives)
// Add the result to the dictionary for use by other primitives {
this._results.Add(primitive.Result, result); this.Buffer.Add(primitive.Result, (e, r) => primitive.Process());
} }
// Render the final filtered image // Render the final filtered image
renderer.DrawImageUnscaled(result, new Point(0,0)); 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()
{
if (this.sourceGraphic != null)
{
this.sourceGraphic.Dispose();
this.sourceGraphic = null;
}
if (this.sourceAlpha != null)
{
this.sourceAlpha.Dispose();
this.sourceAlpha = null;
}
} }
private void PopulateDefaults(Bitmap sourceGraphic) private Bitmap CreateSourceGraphic(SvgVisualElement element, SvgRenderer renderer)
{ {
// Source graphic if (this.sourceGraphic == null)
//this._results.Add("SourceGraphic", sourceGraphic); {
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();
}
}
return this.sourceGraphic;
}
private Bitmap CreateSourceAlpha(SvgVisualElement element, SvgRenderer renderer)
{
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 return this.sourceAlpha;
//this._results.Add("SourceAlpha", ImageProcessor.GetAlphaChannel(sourceGraphic));
} }
#endregion
} }
} }
\ No newline at end of file
...@@ -6,42 +6,34 @@ using System.Drawing.Drawing2D; ...@@ -6,42 +6,34 @@ using System.Drawing.Drawing2D;
namespace Svg.FilterEffects namespace Svg.FilterEffects
{ {
public abstract class SvgFilterPrimitive public abstract class SvgFilterPrimitive : SvgElement
{ {
private string _in; public static readonly string SourceGraphic = "SourceGraphic";
private string _in2; public static readonly string SourceAlpha = "SourceAlpha";
private string _result; public static readonly string BackgroundImage = "BackgroundImage";
private ISvgFilter _owner; 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; } get { return this.Attributes.GetAttribute<string>("in"); }
} set { this.Attributes["in"] = value; }
public string In
{
get { return this._in; }
set { this._in = value; }
}
public string In2
{
get { return this._in2; }
set { this._in2 = value; }
} }
[SvgAttribute("result")]
public string Result public string Result
{ {
get { return this._result; } get { return this.Attributes.GetAttribute<string>("result"); }
set { this._result = value; } set { this.Attributes["result"] = value; }
} }
public SvgFilterPrimitive(ISvgFilter owner, string input) protected SvgFilter Owner
{ {
this._in = input; get { return (SvgFilter)this.Parent; }
this._owner = owner;
} }
public abstract Bitmap Apply(); public abstract Bitmap Process();
} }
} }
\ No newline at end of file
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)
{
}
/// <summary>
/// The standard deviation for the blur operation.
/// </summary>
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
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
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
...@@ -17,24 +17,22 @@ namespace Svg.FilterEffects ...@@ -17,24 +17,22 @@ namespace Svg.FilterEffects
get { return this._mergeResults; } get { return this._mergeResults; }
} }
public SvgMerge(ISvgFilter owner, string input) public override Bitmap Process()
: base(owner, input)
{ {
this._mergeResults = new StringCollection(); //Bitmap merged = new Bitmap((int)this.Owner.Width.Value, (int)this.Owner.Height.Value);
} //Graphics mergedGraphics = Graphics.FromImage(merged);
public override Bitmap Apply() //foreach (string resultId in this.MergeResults)
{ //{
Bitmap merged = new Bitmap((int)this.Owner.Width.Value, (int)this.Owner.Height.Value); // mergedGraphics.DrawImageUnscaled(this.Owner.Results[resultId](), new Point(0, 0));
Graphics mergedGraphics = Graphics.FromImage(merged); //}
foreach (string resultId in this.MergeResults) //mergedGraphics.Save();
mergedGraphics.DrawImageUnscaled(this.Owner.Results[resultId], new Point(0, 0)); //mergedGraphics.Dispose();
mergedGraphics.Save(); //results.Add(this.Result, () => merged);
mergedGraphics.Dispose();
return merged; return null;
} }
} }
} }
\ No newline at end of file
...@@ -65,7 +65,6 @@ ...@@ -65,7 +65,6 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Basic Shapes\SvgVisualElement.cs" /> <Compile Include="Basic Shapes\SvgVisualElement.cs" />
<Compile Include="Basic Shapes\SvgVisualElementEvents.cs" />
<Compile Include="Basic Shapes\SvgCircle.cs" /> <Compile Include="Basic Shapes\SvgCircle.cs" />
<Compile Include="Basic Shapes\SvgEllipse.cs" /> <Compile Include="Basic Shapes\SvgEllipse.cs" />
<Compile Include="Basic Shapes\SvgLine.cs" /> <Compile Include="Basic Shapes\SvgLine.cs" />
...@@ -85,12 +84,12 @@ ...@@ -85,12 +84,12 @@
<Compile Include="Document Structure\SvgGroup.cs" /> <Compile Include="Document Structure\SvgGroup.cs" />
<Compile Include="Document Structure\SvgFragment.cs" /> <Compile Include="Document Structure\SvgFragment.cs" />
<Compile Include="Document Structure\SvgUse.cs" /> <Compile Include="Document Structure\SvgUse.cs" />
<Compile Include="Filter Effects\ISvgFilter.cs" /> <Compile Include="Filter Effects\feGaussianBlur\RawBitmap.cs" />
<Compile Include="Filter Effects\ISvgFilterable.cs" /> <Compile Include="Filter Effects\ISvgFilterable.cs" />
<Compile Include="Filter Effects\SvgFilter.cs" /> <Compile Include="Filter Effects\SvgFilter.cs" />
<Compile Include="Filter Effects\SvgFilterPrimitive.cs" /> <Compile Include="Filter Effects\SvgFilterPrimitive.cs" />
<Compile Include="Filter Effects\SvgGaussianBlur.cs" /> <Compile Include="Filter Effects\feGaussianBlur\SvgGaussianBlur.cs" />
<Compile Include="Filter Effects\SvgMerge.cs" /> <Compile Include="Filter Effects\feMerge\SvgMerge.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" />
...@@ -121,7 +120,7 @@ ...@@ -121,7 +120,7 @@
<Compile Include="Paths\SvgPathSegmentList.cs" /> <Compile Include="Paths\SvgPathSegmentList.cs" />
<Compile Include="Paths\SvgQuadraticCurveSegment.cs" /> <Compile Include="Paths\SvgQuadraticCurveSegment.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Document Structure\SvgDocument.cs" /> <Compile Include="SvgDocument.cs" />
<Compile Include="SvgAttributeAttribute.cs" /> <Compile Include="SvgAttributeAttribute.cs" />
<Compile Include="SvgAttributeCollection.cs" /> <Compile Include="SvgAttributeCollection.cs" />
<Compile Include="SvgElement.cs" /> <Compile Include="SvgElement.cs" />
......
...@@ -12,7 +12,7 @@ using System.Xml; ...@@ -12,7 +12,7 @@ using System.Xml;
namespace Svg namespace Svg
{ {
/// <summary> /// <summary>
/// The class used to create and load all SVG documents. /// The class used to create and load SVG documents.
/// </summary> /// </summary>
public class SvgDocument : SvgFragment, ITypeDescriptorContext public class SvgDocument : SvgFragment, ITypeDescriptorContext
{ {
...@@ -49,6 +49,9 @@ namespace Svg ...@@ -49,6 +49,9 @@ namespace Svg
} }
} }
/// <summary>
/// Gets or sets the Pixels Per Inch of the rendered image.
/// </summary>
public int Ppi { get; set; } public int Ppi { get; set; }
#region ITypeDescriptorContext Members #region ITypeDescriptorContext Members
...@@ -106,7 +109,7 @@ namespace Svg ...@@ -106,7 +109,7 @@ namespace Svg
} }
/// <summary> /// <summary>
/// Opens the document at the specified path and loads the contents. /// Opens the document at the specified path and loads the SVG contents.
/// </summary> /// </summary>
/// <param name="path">A <see cref="string"/> containing the path of the file to open.</param> /// <param name="path">A <see cref="string"/> containing the path of the file to open.</param>
/// <returns>An <see cref="SvgDocument"/> with the contents loaded.</returns> /// <returns>An <see cref="SvgDocument"/> with the contents loaded.</returns>
...@@ -117,11 +120,12 @@ namespace Svg ...@@ -117,11 +120,12 @@ namespace Svg
} }
/// <summary> /// <summary>
/// Opens the document at the specified path and loads the contents. /// Opens the document at the specified path and loads the SVG contents.
/// </summary> /// </summary>
/// <param name="path">A <see cref="string"/> containing the path of the file to open.</param> /// <param name="path">A <see cref="string"/> containing the path of the file to open.</param>
/// <param name="entities">A dictionary of custom entity definitions to be used when resolving XML entities within the document.</param> /// <param name="entities">A dictionary of custom entity definitions to be used when resolving XML entities within the document.</param>
/// <returns>An <see cref="SvgDocument"/> with the contents loaded.</returns> /// <returns>An <see cref="SvgDocument"/> with the contents loaded.</returns>
/// <exception cref="FileNotFoundException">The document at the specified <paramref name="path"/> cannot be found.</exception>
public static SvgDocument Open(string path, Dictionary<string, string> entities) public static SvgDocument Open(string path, Dictionary<string, string> entities)
{ {
if (string.IsNullOrEmpty(path)) if (string.IsNullOrEmpty(path))
...@@ -147,10 +151,11 @@ namespace Svg ...@@ -147,10 +151,11 @@ namespace Svg
} }
/// <summary> /// <summary>
/// Attempts to open an SVG document from the specified <see cref="Stream"/> and adds the specified entities. /// Opens an SVG document from the specified <see cref="Stream"/> and adds the specified entities.
/// </summary> /// </summary>
/// <param name="stream">The <see cref="Stream"/> containing the SVG document to open.</param> /// <param name="stream">The <see cref="Stream"/> containing the SVG document to open.</param>
/// <param name="entities">Custom entity definitions.</param> /// <param name="entities">Custom entity definitions.</param>
/// <exception cref="ArgumentNullException">The <paramref name="stream"/> parameter cannot be <c>null</c>.</exception>
public static SvgDocument Open(Stream stream, Dictionary<string, string> entities) public static SvgDocument Open(Stream stream, Dictionary<string, string> entities)
{ {
if (stream == null) if (stream == null)
...@@ -164,6 +169,7 @@ namespace Svg ...@@ -164,6 +169,7 @@ namespace Svg
{ {
var elementStack = new Stack<SvgElement>(); var elementStack = new Stack<SvgElement>();
var value = new StringBuilder(); var value = new StringBuilder();
bool elementEmpty;
SvgElement element = null; SvgElement element = null;
SvgElement parent; SvgElement parent;
SvgDocument svgDocument = null; SvgDocument svgDocument = null;
...@@ -179,7 +185,7 @@ namespace Svg ...@@ -179,7 +185,7 @@ namespace Svg
case XmlNodeType.Element: case XmlNodeType.Element:
// Does this element have a value or children // Does this element have a value or children
// (Must do this check here before we progress to another node) // (Must do this check here before we progress to another node)
bool isEmpty = reader.IsEmptyElement; elementEmpty = reader.IsEmptyElement;
// Create element // Create element
if (elementStack.Count > 0) if (elementStack.Count > 0)
{ {
...@@ -207,7 +213,7 @@ namespace Svg ...@@ -207,7 +213,7 @@ namespace Svg
elementStack.Push(element); elementStack.Push(element);
// Need to process if the element is empty // Need to process if the element is empty
if (isEmpty) if (elementEmpty)
{ {
goto case XmlNodeType.EndElement; goto case XmlNodeType.EndElement;
} }
...@@ -247,9 +253,20 @@ namespace Svg ...@@ -247,9 +253,20 @@ namespace Svg
} }
} }
/// <summary>
/// Opens an SVG document from the specified <see cref="XmlDocument"/>.
/// </summary>
/// <param name="document">The <see cref="XmlDocument"/> containing the SVG document XML.</param>
/// <exception cref="ArgumentNullException">The <paramref name="document"/> parameter cannot be <c>null</c>.</exception>
public static SvgDocument Open(XmlDocument document) 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) public static Bitmap OpenAsBitmap(string path)
...@@ -279,7 +296,7 @@ namespace Svg ...@@ -279,7 +296,7 @@ namespace Svg
throw new ArgumentNullException("renderer"); throw new ArgumentNullException("renderer");
} }
Render(renderer); this.Render(renderer);
} }
/// <summary> /// <summary>
...@@ -294,7 +311,7 @@ namespace Svg ...@@ -294,7 +311,7 @@ namespace Svg
throw new ArgumentNullException("graphics"); throw new ArgumentNullException("graphics");
} }
Render(SvgRenderer.FromGraphics(graphics)); this.Render(SvgRenderer.FromGraphics(graphics));
} }
/// <summary> /// <summary>
......
...@@ -18,10 +18,16 @@ using Svg.Transforms; ...@@ -18,10 +18,16 @@ using Svg.Transforms;
namespace Svg namespace Svg
{ {
/// <summary>
/// Provides the methods required in order to parse and create <see cref="SvgElement"/> instances from XML.
/// </summary>
internal class SvgElementFactory internal class SvgElementFactory
{ {
private static List<ElementInfo> availableElements; private static List<ElementInfo> availableElements;
/// <summary>
/// Gets a list of available types that can be used when creating an <see cref="SvgElement"/>.
/// </summary>
private static List<ElementInfo> AvailableElements private static List<ElementInfo> AvailableElements
{ {
get get
...@@ -30,6 +36,7 @@ namespace Svg ...@@ -30,6 +36,7 @@ namespace Svg
{ {
var svgTypes = from t in typeof(SvgDocument).Assembly.GetExportedTypes() var svgTypes = from t in typeof(SvgDocument).Assembly.GetExportedTypes()
where t.GetCustomAttributes(typeof(SvgElementAttribute), true).Length > 0 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 }; select new ElementInfo { ElementName = ((SvgElementAttribute)t.GetCustomAttributes(typeof(SvgElementAttribute), true)[0]).ElementName, ElementType = t };
availableElements = svgTypes.ToList(); availableElements = svgTypes.ToList();
...@@ -39,20 +46,51 @@ namespace Svg ...@@ -39,20 +46,51 @@ namespace Svg
} }
} }
/// <summary>
/// Creates an <see cref="SvgDocument"/> from the current node in the specified <see cref="XmlTextReader"/>.
/// </summary>
/// <param name="reader">The <see cref="XmlTextReader"/> containing the node to parse into an <see cref="SvgDocument"/>.</param>
/// <exception cref="ArgumentNullException">The <paramref name="reader"/> parameter cannot be <c>null</c>.</exception>
/// <exception cref="InvalidOperationException">The CreateDocument method can only be used to parse root &lt;svg&gt; elements.</exception>
public static SvgDocument CreateDocument(XmlTextReader reader) 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 <svg> elements.");
}
return (SvgDocument)CreateElement(reader, true, null); return (SvgDocument)CreateElement(reader, true, null);
} }
/// <summary>
/// Creates an <see cref="SvgElement"/> from the current node in the specified <see cref="XmlTextReader"/>.
/// </summary>
/// <param name="reader">The <see cref="XmlTextReader"/> containing the node to parse into a subclass of <see cref="SvgElement"/>.</param>
/// <param name="document">The <see cref="SvgDocument"/> that the created element belongs to.</param>
/// <exception cref="ArgumentNullException">The <paramref name="reader"/> and <paramref name="document"/> parameters cannot be <c>null</c>.</exception>
public static SvgElement CreateElement(XmlTextReader reader, SvgDocument document) 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); return CreateElement(reader, false, document);
} }
private static SvgElement CreateElement(XmlTextReader reader, bool fragmentIsDocument, SvgDocument document) private static SvgElement CreateElement(XmlTextReader reader, bool fragmentIsDocument, SvgDocument document)
{ {
SvgElement createdElement = null; SvgElement createdElement = null;
SvgFragment fragment;
string elementName = reader.LocalName; string elementName = reader.LocalName;
Trace.TraceInformation("Begin CreateElement: {0}", elementName); Trace.TraceInformation("Begin CreateElement: {0}", elementName);
...@@ -137,11 +175,25 @@ namespace Svg ...@@ -137,11 +175,25 @@ namespace Svg
} }
} }
/// <summary>
/// Contains information about a type inheriting from <see cref="SvgElement"/>.
/// </summary>
private struct ElementInfo private struct ElementInfo
{ {
/// <summary>
/// Gets the SVG name of the <see cref="SvgElement"/>.
/// </summary>
public string ElementName { get; set; } public string ElementName { get; set; }
/// <summary>
/// Gets the <see cref="Type"/> of the <see cref="SvgElement"/> subclass.
/// </summary>
public Type ElementType { get; set; } public Type ElementType { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="ElementInfo"/> struct.
/// </summary>
/// <param name="elementName">Name of the element.</param>
/// <param name="elementType">Type of the element.</param>
public ElementInfo(string elementName, Type elementType) public ElementInfo(string elementName, Type elementType)
: this() : this()
{ {
......
...@@ -47,6 +47,11 @@ namespace Svg ...@@ -47,6 +47,11 @@ namespace Svg
return renderer; return renderer;
} }
public void DrawImageUnscaled(Image image, Point location)
{
this._innerGraphics.DrawImageUnscaled(image, location);
}
public void SetClip(Region region) public void SetClip(Region region)
{ {
this._innerGraphics.SetClip(region, CombineMode.Complement); this._innerGraphics.SetClip(region, CombineMode.Complement);
......
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