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 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="DebugRenderer.cs" />
<Compile Include="SvgViewer.cs">
<SubType>Form</SubType>
</Compile>
......
......@@ -43,6 +43,8 @@ namespace SVGViewer
private void RenderSvg(SvgDocument svgDoc)
{
var render = new DebugRenderer();
svgDoc.Draw(render);
svgImage.Image = svgDoc.Draw();
}
}
......
......@@ -205,8 +205,10 @@ namespace Svg
// we're assuming base64, as ascii encoding would be *highly* unsusual for images
// also assuming it's png or jpeg mimetype
byte[] imageBytes = Convert.FromBase64String(uriString.Substring(dataIdx));
Image image = Image.FromStream(new MemoryStream(imageBytes));
return image;
using (var stream = new MemoryStream(imageBytes))
{
return Image.FromStream(stream);
}
}
if (!uri.IsAbsoluteUri)
......@@ -219,16 +221,19 @@ namespace Svg
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))
{
var doc = SvgDocument.Open<SvgDocument>(ms);
var doc = SvgDocument.Open<SvgDocument>(stream);
doc.BaseUri = uri;
return doc.Draw();
}
else
{
return Bitmap.FromStream(ms);
return Bitmap.FromStream(stream);
}
}
}
}
......
......@@ -10,9 +10,13 @@ namespace Svg.Css
{
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 => Enumerable.Empty<SvgElement>();
}
public Selector<SvgElement> Universal(NamespacePrefix prefix)
{
......
......@@ -107,12 +107,12 @@ namespace Svg
}
float points;
IFontDefn currFont;
switch (type)
{
case SvgUnitType.Em:
currFont = GetFont(renderer, owner);
using (var currFont = GetFont(renderer, owner))
{
if (currFont == null)
{
points = (float)(value * 9);
......@@ -122,9 +122,11 @@ namespace Svg
{
_deviceValue = value * (currFont.SizeInPoints / 72.0f) * ppi;
}
}
break;
case SvgUnitType.Ex:
currFont = GetFont(renderer, owner);
using (var currFont = GetFont(renderer, owner))
{
if (currFont == null)
{
points = (float)(value * 9);
......@@ -135,6 +137,7 @@ namespace Svg
_deviceValue = value * 0.5f * (currFont.SizeInPoints / 72.0f) * ppi;
}
break;
}
case SvgUnitType.Centimeter:
_deviceValue = (float)((value / cmInInch) * ppi);
break;
......
......@@ -133,8 +133,8 @@ namespace Svg
var fScaleX = width / this.Width;
var fScaleY = height / this.Height; //(this.MinY < 0 ? -1 : 1) *
var fMinX = this.MinX;
var fMinY = this.MinY;
var fMinX = -this.MinX;
var fMinY = -this.MinY;
if (aspectRatio == null) aspectRatio = new SvgAspectRatio(SvgPreserveAspectRatio.xMidYMid, false);
if (aspectRatio.Align != SvgPreserveAspectRatio.none)
......@@ -197,7 +197,7 @@ namespace Svg
renderer.SetClip(new Region(new RectangleF(x, y, width, height)), CombineMode.Intersect);
renderer.ScaleTransform(fScaleX, fScaleY, MatrixOrder.Prepend);
renderer.TranslateTransform(x, y);
renderer.TranslateTransform(-fMinX, -fMinY);
renderer.TranslateTransform(fMinX, fMinY);
}
}
......
......@@ -91,6 +91,12 @@ namespace Svg.Document_Structure
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()
{
return DeepCopy<SvgSymbol>();
......
......@@ -70,21 +70,23 @@ namespace Svg
protected override void Render(ISvgRenderer renderer)
{
if (!Visible || !Displayable)
return;
this.PushTransforms(renderer);
if (this.Visible && this.Displayable && this.PushTransforms(renderer))
{
this.SetClip(renderer);
SvgVisualElement element = (SvgVisualElement)this.OwnerDocument.IdManager.GetElementById(this.ReferencedElement);
// For the time of rendering we want the referenced element to inherit
// this elements transforms
SvgElement parent = element._parent;
var element = (SvgVisualElement)this.OwnerDocument.IdManager.GetElementById(this.ReferencedElement);
if (element != null)
{
var origParent = element.Parent;
element._parent = this;
element.RenderElement(renderer);
element._parent = parent;
element._parent = origParent;
}
this.ResetClip(renderer);
this.PopTransforms(renderer);
}
}
public override SvgElement DeepCopy()
......
......@@ -86,7 +86,8 @@ namespace Svg.FilterEffects
}
var colorMatrix = new ColorMatrix(colorMatrixElements);
var imageAttrs = new ImageAttributes();
using (var imageAttrs = new ImageAttributes())
{
imageAttrs.SetColorMatrix(colorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
var result = new Bitmap(inputImage.Width, inputImage.Height);
......@@ -98,6 +99,7 @@ namespace Svg.FilterEffects
}
buffer[this.Result] = result;
}
}
public override SvgElement DeepCopy()
......
......@@ -170,11 +170,12 @@ namespace Svg
/// <param name="pMarkerPoint"></param>
private void RenderPart2(float fAngle, ISvgRenderer pRenderer, SvgPath pOwner, PointF pMarkerPoint)
{
Pen pRenderPen = CreatePen(pOwner, pRenderer);
GraphicsPath markerPath = GetClone(pOwner);
Matrix transMatrix = new Matrix();
using (var pRenderPen = CreatePen(pOwner, pRenderer))
{
using (var markerPath = GetClone(pOwner))
{
using (var transMatrix = new Matrix())
{
transMatrix.Translate(pMarkerPoint.X, pMarkerPoint.Y);
if (Orient.IsAuto)
transMatrix.Rotate(fAngle);
......@@ -202,13 +203,14 @@ namespace Svg
if (pFill != null)
{
Brush pBrush = pFill.GetBrush(this, pRenderer, fOpacity);
using (var pBrush = pFill.GetBrush(this, pRenderer, fOpacity))
{
pRenderer.FillPath(pBrush, markerPath);
pBrush.Dispose();
}
pRenderPen.Dispose();
markerPath.Dispose();
transMatrix.Dispose();
}
}
}
}
}
/// <summary>
......@@ -240,9 +242,11 @@ namespace Svg
switch (MarkerUnits)
{
case SvgMarkerUnits.strokeWidth:
Matrix transMatrix = new Matrix();
using (var transMatrix = new Matrix())
{
transMatrix.Scale(AdjustForViewBoxWidth(pPath.StrokeWidth), AdjustForViewBoxHeight(pPath.StrokeWidth));
pRet.Transform(transMatrix);
}
break;
case SvgMarkerUnits.userSpaceOnUse:
break;
......
......@@ -128,11 +128,13 @@ namespace Svg
// Transform the path based on the scaling
var gradBounds = path.GetBounds();
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.Scale(scale, scale, MatrixOrder.Append);
scaleMat.Translate(transCenter.X, transCenter.Y, MatrixOrder.Append);
path.Transform(scaleMat);
}
// calculate the brush
var brush = new PathGradientBrush(path);
......@@ -167,7 +169,8 @@ namespace Svg
};
var pathBounds = path.GetBounds();
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.Scale(.95f, .95f, MatrixOrder.Append);
transform.Translate(pathCenter.X, pathCenter.Y, MatrixOrder.Append);
......@@ -178,6 +181,7 @@ namespace Svg
{
transform.TransformPoints(points);
}
}
return bounds.Height / (points[2].Y - points[1].Y);
}
......
This diff is collapsed.
......@@ -12,11 +12,8 @@ namespace Svg
void DrawImageUnscaled(Image image, Point location);
void DrawPath(Pen pen, GraphicsPath path);
void FillPath(Brush brush, GraphicsPath path);
float FontBaselineOffset(IFontDefn font);
ISvgBoundable GetBoundable();
Region GetClip();
IList<RectangleF> MeasureCharacters(string text, IFontDefn font);
SizeF MeasureString(string text, IFontDefn font);
ISvgBoundable PopBoundable();
void RotateTransform(float fAngle, MatrixOrder order = MatrixOrder.Append);
void ScaleTransform(float sx, float sy, MatrixOrder order = MatrixOrder.Append);
......
......@@ -98,21 +98,6 @@ namespace Svg
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()
{
return _innerGraphics;
......
......@@ -171,10 +171,13 @@ namespace Svg
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));
return doc;
}
}
/// <summary>
/// Attempts to open an SVG document from the specified <see cref="Stream"/>.
......
......@@ -254,6 +254,8 @@ namespace Svg
get { return this._customAttributes; }
}
private static readonly Matrix _zeroMatrix = new Matrix(0, 0, 0, 0, 0, 0);
/// <summary>
/// Applies the required transforms to <see cref="ISvgRenderer"/>.
/// </summary>
......@@ -268,9 +270,9 @@ namespace Svg
{
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)
{
......
......@@ -14,13 +14,13 @@ namespace Svg
/// </summary>
internal class SvgElementFactory
{
private static List<ElementInfo> availableElements;
private static Dictionary<string, ElementInfo> availableElements;
private static Parser cssParser = new Parser();
/// <summary>
/// Gets a list of available types that can be used when creating an <see cref="SvgElement"/>.
/// </summary>
public static List<ElementInfo> AvailableElements
public static Dictionary<string, ElementInfo> AvailableElements
{
get
{
......@@ -31,7 +31,10 @@ namespace Svg
&& t.IsSubclassOf(typeof(SvgElement))
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;
......@@ -91,8 +94,8 @@ namespace Svg
}
else
{
ElementInfo validType = AvailableElements.SingleOrDefault(e => e.ElementName == elementName);
if (validType != null)
ElementInfo validType = null;
if (AvailableElements.TryGetValue(elementName, out validType))
{
createdElement = (SvgElement) Activator.CreateInstance(validType.ElementType);
}
......
......@@ -86,5 +86,10 @@ namespace Svg
return provider.GetGraphics();
}
}
public void Dispose()
{
_font.Dispose();
}
}
}
......@@ -7,7 +7,7 @@ using System.Drawing.Drawing2D;
namespace Svg
{
public interface IFontDefn
public interface IFontDefn : IDisposable
{
float Size { 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