Commit 46e375e4 authored by Eric Domke's avatar Eric Domke
Browse files

Bug Fixes

- Fixing path parsing algorithm to deal with nuanced arc cases and
hopefully improve performance
- Attempts at better memory management
- Working toward getting symbols to render correctly
parent 7c70bd11
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Svg;
using System.Drawing.Drawing2D;
using System.Drawing;
namespace SVGViewer
{
class DebugRenderer : ISvgRenderer
{
private Region _clip = new Region();
private Matrix _transform = new Matrix();
private Stack<ISvgBoundable> _boundables = new Stack<ISvgBoundable>();
public void SetBoundable(ISvgBoundable boundable)
{
_boundables.Push(boundable);
}
public ISvgBoundable GetBoundable()
{
return _boundables.Peek();
}
public ISvgBoundable PopBoundable()
{
return _boundables.Pop();
}
public float DpiY
{
get { return 96; }
}
public void DrawImage(Image image, RectangleF destRect, RectangleF srcRect, GraphicsUnit graphicsUnit)
{
}
public void DrawImageUnscaled(Image image, Point location)
{
}
public void DrawPath(Pen pen, GraphicsPath path)
{
var newPath = (GraphicsPath)path.Clone();
newPath.Transform(_transform);
}
public void FillPath(Brush brush, GraphicsPath path)
{
var newPath = (GraphicsPath)path.Clone();
newPath.Transform(_transform);
}
public Region GetClip()
{
return _clip;
}
public void RotateTransform(float fAngle, MatrixOrder order = MatrixOrder.Append)
{
_transform.Rotate(fAngle, order);
}
public void ScaleTransform(float sx, float sy, MatrixOrder order = MatrixOrder.Append)
{
_transform.Scale(sx, sy, order);
}
public void SetClip(Region region, CombineMode combineMode = CombineMode.Replace)
{
switch (combineMode)
{
case CombineMode.Intersect:
_clip.Intersect(region);
break;
case CombineMode.Complement:
_clip.Complement(region);
break;
case CombineMode.Exclude:
_clip.Exclude(region);
break;
case CombineMode.Union:
_clip.Union(region);
break;
case CombineMode.Xor:
_clip.Xor(region);
break;
default:
_clip = region;
break;
}
}
public void TranslateTransform(float dx, float dy, MatrixOrder order = MatrixOrder.Append)
{
_transform.Translate(dx, dy, order);
}
public SmoothingMode SmoothingMode
{
get { return SmoothingMode.Default; }
set { /* Do Nothing */ }
}
public Matrix Transform
{
get { return _transform; }
set { _transform = value; }
}
public void Dispose()
{
}
}
}
...@@ -93,6 +93,7 @@ ...@@ -93,6 +93,7 @@
<Reference Include="System.Xml" /> <Reference Include="System.Xml" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="DebugRenderer.cs" />
<Compile Include="SvgViewer.cs"> <Compile Include="SvgViewer.cs">
<SubType>Form</SubType> <SubType>Form</SubType>
</Compile> </Compile>
......
...@@ -43,6 +43,8 @@ namespace SVGViewer ...@@ -43,6 +43,8 @@ namespace SVGViewer
private void RenderSvg(SvgDocument svgDoc) private void RenderSvg(SvgDocument svgDoc)
{ {
var render = new DebugRenderer();
svgDoc.Draw(render);
svgImage.Image = svgDoc.Draw(); svgImage.Image = svgDoc.Draw();
} }
} }
......
...@@ -205,8 +205,10 @@ namespace Svg ...@@ -205,8 +205,10 @@ namespace Svg
// we're assuming base64, as ascii encoding would be *highly* unsusual for images // we're assuming base64, as ascii encoding would be *highly* unsusual for images
// also assuming it's png or jpeg mimetype // also assuming it's png or jpeg mimetype
byte[] imageBytes = Convert.FromBase64String(uriString.Substring(dataIdx)); byte[] imageBytes = Convert.FromBase64String(uriString.Substring(dataIdx));
Image image = Image.FromStream(new MemoryStream(imageBytes)); using (var stream = new MemoryStream(imageBytes))
return image; {
return Image.FromStream(stream);
}
} }
if (!uri.IsAbsoluteUri) if (!uri.IsAbsoluteUri)
...@@ -219,16 +221,19 @@ namespace Svg ...@@ -219,16 +221,19 @@ namespace Svg
using (WebResponse webResponse = httpRequest.GetResponse()) using (WebResponse webResponse = httpRequest.GetResponse())
{ {
MemoryStream ms = BufferToMemoryStream(webResponse.GetResponseStream()); using (var stream = webResponse.GetResponseStream())
{
stream.Position = 0;
if (uri.LocalPath.EndsWith(".svg", StringComparison.InvariantCultureIgnoreCase)) if (uri.LocalPath.EndsWith(".svg", StringComparison.InvariantCultureIgnoreCase))
{ {
var doc = SvgDocument.Open<SvgDocument>(ms); var doc = SvgDocument.Open<SvgDocument>(stream);
doc.BaseUri = uri; doc.BaseUri = uri;
return doc.Draw(); return doc.Draw();
} }
else else
{ {
return Bitmap.FromStream(ms); return Bitmap.FromStream(stream);
}
} }
} }
} }
......
...@@ -10,9 +10,13 @@ namespace Svg.Css ...@@ -10,9 +10,13 @@ namespace Svg.Css
{ {
public Selector<SvgElement> Type(NamespacePrefix prefix, string name) public Selector<SvgElement> Type(NamespacePrefix prefix, string name)
{ {
var type = SvgElementFactory.AvailableElements.SingleOrDefault(e => e.ElementName == name); SvgElementFactory.ElementInfo type = null;
if (SvgElementFactory.AvailableElements.TryGetValue(name, out type))
{
return nodes => nodes.Where(n => n.GetType() == type.ElementType); return nodes => nodes.Where(n => n.GetType() == type.ElementType);
} }
return nodes => Enumerable.Empty<SvgElement>();
}
public Selector<SvgElement> Universal(NamespacePrefix prefix) public Selector<SvgElement> Universal(NamespacePrefix prefix)
{ {
......
...@@ -107,12 +107,12 @@ namespace Svg ...@@ -107,12 +107,12 @@ namespace Svg
} }
float points; float points;
IFontDefn currFont;
switch (type) switch (type)
{ {
case SvgUnitType.Em: case SvgUnitType.Em:
currFont = GetFont(renderer, owner); using (var currFont = GetFont(renderer, owner))
{
if (currFont == null) if (currFont == null)
{ {
points = (float)(value * 9); points = (float)(value * 9);
...@@ -122,9 +122,11 @@ namespace Svg ...@@ -122,9 +122,11 @@ namespace Svg
{ {
_deviceValue = value * (currFont.SizeInPoints / 72.0f) * ppi; _deviceValue = value * (currFont.SizeInPoints / 72.0f) * ppi;
} }
}
break; break;
case SvgUnitType.Ex: case SvgUnitType.Ex:
currFont = GetFont(renderer, owner); using (var currFont = GetFont(renderer, owner))
{
if (currFont == null) if (currFont == null)
{ {
points = (float)(value * 9); points = (float)(value * 9);
...@@ -135,6 +137,7 @@ namespace Svg ...@@ -135,6 +137,7 @@ namespace Svg
_deviceValue = value * 0.5f * (currFont.SizeInPoints / 72.0f) * ppi; _deviceValue = value * 0.5f * (currFont.SizeInPoints / 72.0f) * ppi;
} }
break; break;
}
case SvgUnitType.Centimeter: case SvgUnitType.Centimeter:
_deviceValue = (float)((value / cmInInch) * ppi); _deviceValue = (float)((value / cmInInch) * ppi);
break; break;
......
...@@ -133,8 +133,8 @@ namespace Svg ...@@ -133,8 +133,8 @@ namespace Svg
var fScaleX = width / this.Width; var fScaleX = width / this.Width;
var fScaleY = height / this.Height; //(this.MinY < 0 ? -1 : 1) * var fScaleY = height / this.Height; //(this.MinY < 0 ? -1 : 1) *
var fMinX = this.MinX; var fMinX = -this.MinX;
var fMinY = this.MinY; var fMinY = -this.MinY;
if (aspectRatio == null) aspectRatio = new SvgAspectRatio(SvgPreserveAspectRatio.xMidYMid, false); if (aspectRatio == null) aspectRatio = new SvgAspectRatio(SvgPreserveAspectRatio.xMidYMid, false);
if (aspectRatio.Align != SvgPreserveAspectRatio.none) if (aspectRatio.Align != SvgPreserveAspectRatio.none)
...@@ -197,7 +197,7 @@ namespace Svg ...@@ -197,7 +197,7 @@ namespace Svg
renderer.SetClip(new Region(new RectangleF(x, y, width, height)), CombineMode.Intersect); renderer.SetClip(new Region(new RectangleF(x, y, width, height)), CombineMode.Intersect);
renderer.ScaleTransform(fScaleX, fScaleY, MatrixOrder.Prepend); renderer.ScaleTransform(fScaleX, fScaleY, MatrixOrder.Prepend);
renderer.TranslateTransform(x, y); renderer.TranslateTransform(x, y);
renderer.TranslateTransform(-fMinX, -fMinY); renderer.TranslateTransform(fMinX, fMinY);
} }
} }
......
...@@ -91,6 +91,12 @@ namespace Svg.Document_Structure ...@@ -91,6 +91,12 @@ namespace Svg.Document_Structure
return true; return true;
} }
// Only render if the parent is set to a Use element
protected override void Render(ISvgRenderer renderer)
{
if (_parent is SvgUse) base.Render(renderer);
}
public override SvgElement DeepCopy() public override SvgElement DeepCopy()
{ {
return DeepCopy<SvgSymbol>(); return DeepCopy<SvgSymbol>();
......
...@@ -70,21 +70,23 @@ namespace Svg ...@@ -70,21 +70,23 @@ namespace Svg
protected override void Render(ISvgRenderer renderer) protected override void Render(ISvgRenderer renderer)
{ {
if (!Visible || !Displayable) if (this.Visible && this.Displayable && this.PushTransforms(renderer))
return; {
this.SetClip(renderer);
this.PushTransforms(renderer);
SvgVisualElement element = (SvgVisualElement)this.OwnerDocument.IdManager.GetElementById(this.ReferencedElement); var element = (SvgVisualElement)this.OwnerDocument.IdManager.GetElementById(this.ReferencedElement);
// For the time of rendering we want the referenced element to inherit if (element != null)
// this elements transforms {
SvgElement parent = element._parent; var origParent = element.Parent;
element._parent = this; element._parent = this;
element.RenderElement(renderer); element.RenderElement(renderer);
element._parent = parent; element._parent = origParent;
}
this.ResetClip(renderer);
this.PopTransforms(renderer); this.PopTransforms(renderer);
} }
}
public override SvgElement DeepCopy() public override SvgElement DeepCopy()
......
...@@ -86,7 +86,8 @@ namespace Svg.FilterEffects ...@@ -86,7 +86,8 @@ namespace Svg.FilterEffects
} }
var colorMatrix = new ColorMatrix(colorMatrixElements); var colorMatrix = new ColorMatrix(colorMatrixElements);
var imageAttrs = new ImageAttributes(); using (var imageAttrs = new ImageAttributes())
{
imageAttrs.SetColorMatrix(colorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap); imageAttrs.SetColorMatrix(colorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
var result = new Bitmap(inputImage.Width, inputImage.Height); var result = new Bitmap(inputImage.Width, inputImage.Height);
...@@ -98,6 +99,7 @@ namespace Svg.FilterEffects ...@@ -98,6 +99,7 @@ namespace Svg.FilterEffects
} }
buffer[this.Result] = result; buffer[this.Result] = result;
} }
}
public override SvgElement DeepCopy() public override SvgElement DeepCopy()
......
...@@ -170,11 +170,12 @@ namespace Svg ...@@ -170,11 +170,12 @@ namespace Svg
/// <param name="pMarkerPoint"></param> /// <param name="pMarkerPoint"></param>
private void RenderPart2(float fAngle, ISvgRenderer pRenderer, SvgPath pOwner, PointF pMarkerPoint) private void RenderPart2(float fAngle, ISvgRenderer pRenderer, SvgPath pOwner, PointF pMarkerPoint)
{ {
Pen pRenderPen = CreatePen(pOwner, pRenderer); using (var pRenderPen = CreatePen(pOwner, pRenderer))
{
GraphicsPath markerPath = GetClone(pOwner); using (var markerPath = GetClone(pOwner))
{
Matrix transMatrix = new Matrix(); using (var transMatrix = new Matrix())
{
transMatrix.Translate(pMarkerPoint.X, pMarkerPoint.Y); transMatrix.Translate(pMarkerPoint.X, pMarkerPoint.Y);
if (Orient.IsAuto) if (Orient.IsAuto)
transMatrix.Rotate(fAngle); transMatrix.Rotate(fAngle);
...@@ -202,13 +203,14 @@ namespace Svg ...@@ -202,13 +203,14 @@ namespace Svg
if (pFill != null) if (pFill != null)
{ {
Brush pBrush = pFill.GetBrush(this, pRenderer, fOpacity); using (var pBrush = pFill.GetBrush(this, pRenderer, fOpacity))
{
pRenderer.FillPath(pBrush, markerPath); pRenderer.FillPath(pBrush, markerPath);
pBrush.Dispose();
} }
pRenderPen.Dispose(); }
markerPath.Dispose(); }
transMatrix.Dispose(); }
}
} }
/// <summary> /// <summary>
...@@ -240,9 +242,11 @@ namespace Svg ...@@ -240,9 +242,11 @@ namespace Svg
switch (MarkerUnits) switch (MarkerUnits)
{ {
case SvgMarkerUnits.strokeWidth: case SvgMarkerUnits.strokeWidth:
Matrix transMatrix = new Matrix(); using (var transMatrix = new Matrix())
{
transMatrix.Scale(AdjustForViewBoxWidth(pPath.StrokeWidth), AdjustForViewBoxHeight(pPath.StrokeWidth)); transMatrix.Scale(AdjustForViewBoxWidth(pPath.StrokeWidth), AdjustForViewBoxHeight(pPath.StrokeWidth));
pRet.Transform(transMatrix); pRet.Transform(transMatrix);
}
break; break;
case SvgMarkerUnits.userSpaceOnUse: case SvgMarkerUnits.userSpaceOnUse:
break; break;
......
...@@ -128,11 +128,13 @@ namespace Svg ...@@ -128,11 +128,13 @@ namespace Svg
// Transform the path based on the scaling // Transform the path based on the scaling
var gradBounds = path.GetBounds(); var gradBounds = path.GetBounds();
var transCenter = new PointF(gradBounds.Left + gradBounds.Width / 2, gradBounds.Top + gradBounds.Height / 2); var transCenter = new PointF(gradBounds.Left + gradBounds.Width / 2, gradBounds.Top + gradBounds.Height / 2);
var scaleMat = new Matrix(); using (var scaleMat = new Matrix())
{
scaleMat.Translate(-1 * transCenter.X, -1 * transCenter.Y, MatrixOrder.Append); scaleMat.Translate(-1 * transCenter.X, -1 * transCenter.Y, MatrixOrder.Append);
scaleMat.Scale(scale, scale, MatrixOrder.Append); scaleMat.Scale(scale, scale, MatrixOrder.Append);
scaleMat.Translate(transCenter.X, transCenter.Y, MatrixOrder.Append); scaleMat.Translate(transCenter.X, transCenter.Y, MatrixOrder.Append);
path.Transform(scaleMat); path.Transform(scaleMat);
}
// calculate the brush // calculate the brush
var brush = new PathGradientBrush(path); var brush = new PathGradientBrush(path);
...@@ -167,7 +169,8 @@ namespace Svg ...@@ -167,7 +169,8 @@ namespace Svg
}; };
var pathBounds = path.GetBounds(); var pathBounds = path.GetBounds();
var pathCenter = new PointF(pathBounds.X + pathBounds.Width / 2, pathBounds.Y + pathBounds.Height / 2); var pathCenter = new PointF(pathBounds.X + pathBounds.Width / 2, pathBounds.Y + pathBounds.Height / 2);
var transform = new Matrix(); using (var transform = new Matrix())
{
transform.Translate(-1 * pathCenter.X, -1 * pathCenter.Y, MatrixOrder.Append); transform.Translate(-1 * pathCenter.X, -1 * pathCenter.Y, MatrixOrder.Append);
transform.Scale(.95f, .95f, MatrixOrder.Append); transform.Scale(.95f, .95f, MatrixOrder.Append);
transform.Translate(pathCenter.X, pathCenter.Y, MatrixOrder.Append); transform.Translate(pathCenter.X, pathCenter.Y, MatrixOrder.Append);
...@@ -178,6 +181,7 @@ namespace Svg ...@@ -178,6 +181,7 @@ namespace Svg
{ {
transform.TransformPoints(points); transform.TransformPoints(points);
} }
}
return bounds.Height / (points[2].Y - points[1].Y); return bounds.Height / (points[2].Y - points[1].Y);
} }
......
This diff is collapsed.
...@@ -12,11 +12,8 @@ namespace Svg ...@@ -12,11 +12,8 @@ namespace Svg
void DrawImageUnscaled(Image image, Point location); void DrawImageUnscaled(Image image, Point location);
void DrawPath(Pen pen, GraphicsPath path); void DrawPath(Pen pen, GraphicsPath path);
void FillPath(Brush brush, GraphicsPath path); void FillPath(Brush brush, GraphicsPath path);
float FontBaselineOffset(IFontDefn font);
ISvgBoundable GetBoundable(); ISvgBoundable GetBoundable();
Region GetClip(); Region GetClip();
IList<RectangleF> MeasureCharacters(string text, IFontDefn font);
SizeF MeasureString(string text, IFontDefn font);
ISvgBoundable PopBoundable(); ISvgBoundable PopBoundable();
void RotateTransform(float fAngle, MatrixOrder order = MatrixOrder.Append); void RotateTransform(float fAngle, MatrixOrder order = MatrixOrder.Append);
void ScaleTransform(float sx, float sy, MatrixOrder order = MatrixOrder.Append); void ScaleTransform(float sx, float sy, MatrixOrder order = MatrixOrder.Append);
......
...@@ -98,21 +98,6 @@ namespace Svg ...@@ -98,21 +98,6 @@ namespace Svg
this._innerGraphics.Dispose(); this._innerGraphics.Dispose();
} }
public float FontBaselineOffset(IFontDefn font)
{
return font.Ascent(this);
}
public IList<RectangleF> MeasureCharacters(string text, IFontDefn font)
{
return font.MeasureCharacters(this, text);
}
public SizeF MeasureString(string text, IFontDefn font)
{
return font.MeasureString(this, text);
}
Graphics IGraphicsProvider.GetGraphics() Graphics IGraphicsProvider.GetGraphics()
{ {
return _innerGraphics; return _innerGraphics;
......
...@@ -171,10 +171,13 @@ namespace Svg ...@@ -171,10 +171,13 @@ namespace Svg
throw new FileNotFoundException("The specified document cannot be found.", path); throw new FileNotFoundException("The specified document cannot be found.", path);
} }
var doc = Open<T>(File.OpenRead(path), entities); using (var stream = File.OpenRead(path))
{
var doc = Open<T>(stream, entities);
doc.BaseUri = new Uri(System.IO.Path.GetFullPath(path)); doc.BaseUri = new Uri(System.IO.Path.GetFullPath(path));
return doc; return doc;
} }
}
/// <summary> /// <summary>
/// Attempts to open an SVG document from the specified <see cref="Stream"/>. /// Attempts to open an SVG document from the specified <see cref="Stream"/>.
......
...@@ -254,6 +254,8 @@ namespace Svg ...@@ -254,6 +254,8 @@ namespace Svg
get { return this._customAttributes; } get { return this._customAttributes; }
} }
private static readonly Matrix _zeroMatrix = new Matrix(0, 0, 0, 0, 0, 0);
/// <summary> /// <summary>
/// Applies the required transforms to <see cref="ISvgRenderer"/>. /// Applies the required transforms to <see cref="ISvgRenderer"/>.
/// </summary> /// </summary>
...@@ -268,9 +270,9 @@ namespace Svg ...@@ -268,9 +270,9 @@ namespace Svg
{ {
return true; return true;
} }
if (this.Transforms.Count == 1 && this.Transforms[0].Matrix.Equals(new Matrix(0, 0, 0, 0, 0, 0))) return false; if (this.Transforms.Count == 1 && this.Transforms[0].Matrix.Equals(_zeroMatrix)) return false;
Matrix transformMatrix = renderer.Transform; Matrix transformMatrix = renderer.Transform.Clone();
foreach (SvgTransform transformation in this.Transforms) foreach (SvgTransform transformation in this.Transforms)
{ {
......
...@@ -14,13 +14,13 @@ namespace Svg ...@@ -14,13 +14,13 @@ namespace Svg
/// </summary> /// </summary>
internal class SvgElementFactory internal class SvgElementFactory
{ {
private static List<ElementInfo> availableElements; private static Dictionary<string, ElementInfo> availableElements;
private static Parser cssParser = new Parser(); private static Parser cssParser = new Parser();
/// <summary> /// <summary>
/// Gets a list of available types that can be used when creating an <see cref="SvgElement"/>. /// Gets a list of available types that can be used when creating an <see cref="SvgElement"/>.
/// </summary> /// </summary>
public static List<ElementInfo> AvailableElements public static Dictionary<string, ElementInfo> AvailableElements
{ {
get get
{ {
...@@ -31,7 +31,10 @@ namespace Svg ...@@ -31,7 +31,10 @@ namespace Svg
&& t.IsSubclassOf(typeof(SvgElement)) && 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 = (from t in svgTypes
where t.ElementName != "svg"
group t by t.ElementName into types
select types).ToDictionary(e => e.Key, e => e.SingleOrDefault());
} }
return availableElements; return availableElements;
...@@ -91,8 +94,8 @@ namespace Svg ...@@ -91,8 +94,8 @@ namespace Svg
} }
else else
{ {
ElementInfo validType = AvailableElements.SingleOrDefault(e => e.ElementName == elementName); ElementInfo validType = null;
if (validType != null) if (AvailableElements.TryGetValue(elementName, out validType))
{ {
createdElement = (SvgElement) Activator.CreateInstance(validType.ElementType); createdElement = (SvgElement) Activator.CreateInstance(validType.ElementType);
} }
......
...@@ -86,5 +86,10 @@ namespace Svg ...@@ -86,5 +86,10 @@ namespace Svg
return provider.GetGraphics(); return provider.GetGraphics();
} }
} }
public void Dispose()
{
_font.Dispose();
}
} }
} }
...@@ -7,7 +7,7 @@ using System.Drawing.Drawing2D; ...@@ -7,7 +7,7 @@ using System.Drawing.Drawing2D;
namespace Svg namespace Svg
{ {
public interface IFontDefn public interface IFontDefn : IDisposable
{ {
float Size { get; } float Size { get; }
float SizeInPoints { get; } float SizeInPoints { get; }
......
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