Commit 6c1198d2 authored by joreg's avatar joreg
Browse files

Merge branch 'master' of https://github.com/vvvv/SVG

parents 220d8370 87e7be2d
...@@ -91,7 +91,7 @@ namespace Svg ...@@ -91,7 +91,7 @@ namespace Svg
/// <summary> /// <summary>
/// Renders the <see cref="SvgElement"/> and contents to the specified <see cref="Graphics"/> object. /// Renders the <see cref="SvgElement"/> and contents to the specified <see cref="Graphics"/> object.
/// </summary> /// </summary>
/// <param name="graphics">The <see cref="SvgRenderer"/> object to render to.</param> /// <param name="renderer">The <see cref="SvgRenderer"/> object to render to.</param>
protected override void Render(SvgRenderer renderer) protected override void Render(SvgRenderer renderer)
{ {
if (this.Path != null && this.Visible) if (this.Path != null && this.Visible)
......
...@@ -98,7 +98,7 @@ namespace Svg ...@@ -98,7 +98,7 @@ namespace Svg
/// <summary> /// <summary>
/// Called by the underlying <see cref="SvgElement"/> when an element has been removed from the /// Called by the underlying <see cref="SvgElement"/> when an element has been removed from the
/// <see cref="Children"/> collection. /// <see cref="SvgElement.Children"/> collection.
/// </summary> /// </summary>
/// <param name="child">The <see cref="SvgElement"/> that has been removed.</param> /// <param name="child">The <see cref="SvgElement"/> that has been removed.</param>
protected override void RemoveElement(SvgElement child) protected override void RemoveElement(SvgElement child)
......
...@@ -23,6 +23,13 @@ namespace Svg ...@@ -23,6 +23,13 @@ namespace Svg
throw new ArgumentOutOfRangeException("value must be a string."); throw new ArgumentOutOfRangeException("value must be a string.");
} }
//support exponents (the SVG that comes back from IE may be an exponent ugh!!!)
if ((value as string).Contains("e"))
{
var d = Decimal.Parse((string)value, System.Globalization.NumberStyles.Float);
value = d.ToString();
}
// http://www.w3.org/TR/CSS21/syndata.html#values // http://www.w3.org/TR/CSS21/syndata.html#values
// http://www.w3.org/TR/SVG11/coords.html#Units // http://www.w3.org/TR/SVG11/coords.html#Units
......
...@@ -47,9 +47,17 @@ namespace Svg ...@@ -47,9 +47,17 @@ namespace Svg
var r = new RectangleF(); var r = new RectangleF();
foreach(var c in this.Children) foreach(var c in this.Children)
{ {
if(c is SvgVisualElement) if (c is SvgVisualElement)
{
// First it should check if rectangle is empty or it will return the wrong Bounds.
// This is because when the Rectangle is Empty, the Union method adds as if the first values where X=0, Y=0
if (r.IsEmpty)
r = ((SvgVisualElement)c).Bounds;
else
r = RectangleF.Union(r, ((SvgVisualElement)c).Bounds); r = RectangleF.Union(r, ((SvgVisualElement)c).Bounds);
} }
}
return r; return r;
} }
} }
......
...@@ -38,9 +38,21 @@ namespace Svg ...@@ -38,9 +38,21 @@ namespace Svg
try try
{ {
int start = colour.IndexOf("(") + 1; int start = colour.IndexOf("(") + 1;
//get the values from the RGB string
string[] values = colour.Substring(start, colour.IndexOf(")") - start).Split(new char[]{',', ' '}, StringSplitOptions.RemoveEmptyEntries); string[] values = colour.Substring(start, colour.IndexOf(")") - start).Split(new char[]{',', ' '}, StringSplitOptions.RemoveEmptyEntries);
return System.Drawing.Color.FromArgb(int.Parse(values[0]), int.Parse(values[1]), int.Parse(values[2])); //determine the alpha value if this is an RGBA (it will be the 4th value if there is one)
int alphaValue = 255;
if (values.Length > 3)
{
//the alpha portion of the rgba is not an int 0-255 it is a decimal between 0 and 1
//so we have to determine the corosponding byte value
alphaValue = (int)(decimal.Parse(values[3]) * 255);
}
Color colorpart = System.Drawing.Color.FromArgb(alphaValue, int.Parse(values[0]), int.Parse(values[1]), int.Parse(values[2]));
return colorpart;
} }
catch catch
{ {
......
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections;
using System.Text;
using System.Drawing; using System.Drawing;
using System.Drawing.Drawing2D; using System.Drawing.Drawing2D;
...@@ -100,19 +97,20 @@ namespace Svg ...@@ -100,19 +97,20 @@ namespace Svg
} }
/// <summary> /// <summary>
/// Gets a <see cref="ColourBlend"/> representing the <see cref="SvgGradientServer"/>'s gradient stops. /// Gets a <see cref="ColorBlend"/> representing the <see cref="SvgGradientServer"/>'s gradient stops.
/// </summary> /// </summary>
/// <param name="owner">The parent <see cref="SvgVisualElement"/>.</param> /// <param name="owner">The parent <see cref="SvgVisualElement"/>.</param>
/// <param name="opacity">The opacity of the colour blend.</param> /// <param name="opacity">The opacity of the colour blend.</param>
protected ColorBlend GetColourBlend(SvgVisualElement owner, float opacity) protected ColorBlend GetColourBlend(SvgVisualElement owner, float opacity, bool radial)
{ {
ColorBlend blend = new ColorBlend();
int colourBlends = this.Stops.Count; int colourBlends = this.Stops.Count;
bool insertStart = false; bool insertStart = false;
bool insertEnd = false; bool insertEnd = false;
//gradient.Transform = renderingElement.Transforms.Matrix; //gradient.Transform = renderingElement.Transforms.Matrix;
//stops should be processed in reverse order if it's a radial gradient
// May need to increase the number of colour blends because the range *must* be from 0.0 to 1.0. // May need to increase the number of colour blends because the range *must* be from 0.0 to 1.0.
// E.g. 0.5 - 0.8 isn't valid therefore the rest need to be calculated. // E.g. 0.5 - 0.8 isn't valid therefore the rest need to be calculated.
...@@ -120,21 +118,33 @@ namespace Svg ...@@ -120,21 +118,33 @@ namespace Svg
if (this.Stops[0].Offset.Value > 0) if (this.Stops[0].Offset.Value > 0)
{ {
colourBlends++; colourBlends++;
// Indicate that a colour has to be dynamically added at the start
if (radial)
{
insertEnd = true;
}
else
{
insertStart = true; insertStart = true;
} }
}
// If the last stop doesn't end at 1 a stop // If the last stop doesn't end at 1 a stop
float lastValue = this.Stops[this.Stops.Count - 1].Offset.Value; float lastValue = this.Stops[this.Stops.Count - 1].Offset.Value;
if (lastValue < 100 || lastValue < 1) if (lastValue < 100 || lastValue < 1)
{ {
colourBlends++; colourBlends++;
// Indicate that a colour has to be dynamically added at the end if (radial)
{
insertStart = true;
}
else
{
insertEnd = true; insertEnd = true;
} }
}
blend.Positions = new float[colourBlends]; ColorBlend blend = new ColorBlend(colourBlends);
blend.Colors = new Color[colourBlends];
// Set positions and colour values // Set positions and colour values
int actualStops = 0; int actualStops = 0;
...@@ -144,15 +154,24 @@ namespace Svg ...@@ -144,15 +154,24 @@ namespace Svg
for (int i = 0; i < colourBlends; i++) for (int i = 0; i < colourBlends; i++)
{ {
mergedOpacity = opacity * this.Stops[actualStops].Opacity; var currentStop = this.Stops[radial ? this.Stops.Count - 1 - actualStops : actualStops];
position = (this.Stops[actualStops].Offset.ToDeviceValue(owner) / owner.Bounds.Width);
colour = Color.FromArgb((int)(mergedOpacity * 255), this.Stops[actualStops++].Colour); mergedOpacity = opacity * currentStop.Opacity;
position =
radial
? 1 - (currentStop.Offset.ToDeviceValue(owner) / owner.Bounds.Width)
: (currentStop.Offset.ToDeviceValue(owner) / owner.Bounds.Width);
colour = Color.FromArgb((int)(mergedOpacity * 255), currentStop.Colour);
actualStops++;
// Insert this colour before itself at position 0 // Insert this colour before itself at position 0
if (insertStart && i == 0) if (insertStart && i == 0)
{ {
blend.Positions[i] = 0.0f; blend.Positions[i] = 0.0f;
blend.Colors[i++] = colour; blend.Colors[i] = colour;
i++;
} }
blend.Positions[i] = position; blend.Positions[i] = position;
...@@ -161,8 +180,10 @@ namespace Svg ...@@ -161,8 +180,10 @@ namespace Svg
// Insert this colour after itself at position 0 // Insert this colour after itself at position 0
if (insertEnd && i == colourBlends - 2) if (insertEnd && i == colourBlends - 2)
{ {
blend.Positions[i + 1] = 1.0f; i++;
blend.Colors[++i] = colour;
blend.Positions[i] = 1.0f;
blend.Colors[i] = colour;
} }
} }
...@@ -184,12 +205,12 @@ namespace Svg ...@@ -184,12 +205,12 @@ namespace Svg
public override SvgElement DeepCopy<T>() public override SvgElement DeepCopy<T>()
{ {
var newObj = base.DeepCopy<T>() as SvgGradientServer; var newObj = base.DeepCopy<T>() as SvgGradientServer;
newObj.SpreadMethod = this.SpreadMethod; newObj.SpreadMethod = this.SpreadMethod;
newObj.GradientUnits = this.GradientUnits; newObj.GradientUnits = this.GradientUnits;
newObj.InheritGradient = this.InheritGradient; newObj.InheritGradient = this.InheritGradient;
return newObj;
return newObj;
} }
} }
} }
\ No newline at end of file
...@@ -109,7 +109,7 @@ namespace Svg ...@@ -109,7 +109,7 @@ namespace Svg
} }
LinearGradientBrush gradient = new LinearGradientBrush(start, end, Color.Transparent, Color.Transparent); LinearGradientBrush gradient = new LinearGradientBrush(start, end, Color.Transparent, Color.Transparent);
gradient.InterpolationColors = base.GetColourBlend(owner, opacity); gradient.InterpolationColors = base.GetColourBlend(owner, opacity, false);
// Needed to fix an issue where the gradient was being wrapped when though it had the correct bounds // Needed to fix an issue where the gradient was being wrapped when though it had the correct bounds
gradient.WrapMode = WrapMode.TileFlipX; gradient.WrapMode = WrapMode.TileFlipX;
......
...@@ -105,7 +105,7 @@ namespace Svg ...@@ -105,7 +105,7 @@ namespace Svg
/// <summary> /// <summary>
/// Gets a <see cref="Brush"/> representing the current paint server. /// Gets a <see cref="Brush"/> representing the current paint server.
/// </summary> /// </summary>
/// <param name="styleOwner">The owner <see cref="SvgVisualElement"/>.</param> /// <param name="renderingElement">The owner <see cref="SvgVisualElement"/>.</param>
/// <param name="opacity">The opacity of the brush.</param> /// <param name="opacity">The opacity of the brush.</param>
public override Brush GetBrush(SvgVisualElement renderingElement, float opacity) public override Brush GetBrush(SvgVisualElement renderingElement, float opacity)
{ {
......
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing; using System.Drawing;
using System.Drawing.Drawing2D; using System.Drawing.Drawing2D;
...@@ -33,14 +30,36 @@ namespace Svg ...@@ -33,14 +30,36 @@ namespace Svg
[SvgAttribute("fx")] [SvgAttribute("fx")]
public SvgUnit FocalX public SvgUnit FocalX
{ {
get { return this.Attributes.GetAttribute<SvgUnit>("fx"); } get
{
var value = this.Attributes.GetAttribute<SvgUnit>("fx");
if (value.IsEmpty || value.IsNone)
{
value = this.CenterX;
}
return value;
}
set { this.Attributes["fx"] = value; } set { this.Attributes["fx"] = value; }
} }
[SvgAttribute("fy")] [SvgAttribute("fy")]
public SvgUnit FocalY public SvgUnit FocalY
{ {
get { return this.Attributes.GetAttribute<SvgUnit>("fy"); } get
{
var value = this.Attributes.GetAttribute<SvgUnit>("fy");
if (value.IsEmpty || value.IsNone)
{
value = this.CenterY;
}
return value;
}
set { this.Attributes["fy"] = value; } set { this.Attributes["fy"] = value; }
} }
...@@ -57,28 +76,37 @@ namespace Svg ...@@ -57,28 +76,37 @@ namespace Svg
public override Brush GetBrush(SvgVisualElement renderingElement, float opacity) public override Brush GetBrush(SvgVisualElement renderingElement, float opacity)
{ {
float radius = this.Radius.ToDeviceValue(renderingElement);
if (radius <= 0)
{
return null;
}
GraphicsPath path = new GraphicsPath(); GraphicsPath path = new GraphicsPath();
float left = this.CenterX.ToDeviceValue(renderingElement); float left = this.CenterX.ToDeviceValue(renderingElement);
float top = this.CenterY.ToDeviceValue(renderingElement, true); float top = this.CenterY.ToDeviceValue(renderingElement, true);
float radius = this.Radius.ToDeviceValue(renderingElement);
RectangleF boundingBox = (this.GradientUnits == SvgCoordinateUnits.ObjectBoundingBox) ? renderingElement.Bounds : renderingElement.OwnerDocument.GetDimensions(); RectangleF boundingBox = (this.GradientUnits == SvgCoordinateUnits.ObjectBoundingBox) ? renderingElement.Bounds : renderingElement.OwnerDocument.GetDimensions();
if (radius > 0) path.AddEllipse(
{ boundingBox.Left + left - radius,
path.AddEllipse(left - radius, top - radius, radius * 2, radius * 2); boundingBox.Top + top - radius,
radius * 2,
radius * 2);
PathGradientBrush brush = new PathGradientBrush(path); PathGradientBrush brush = new PathGradientBrush(path);
ColorBlend blend = base.GetColourBlend(renderingElement, opacity); ColorBlend blend = base.GetColourBlend(renderingElement, opacity, true);
brush.InterpolationColors = blend; brush.InterpolationColors = blend;
brush.CenterPoint = new PointF(this.FocalX.ToDeviceValue(renderingElement), this.FocalY.ToDeviceValue(renderingElement, true)); brush.CenterPoint =
new PointF(
boundingBox.Left + this.FocalX.ToDeviceValue(renderingElement),
boundingBox.Top + this.FocalY.ToDeviceValue(renderingElement, true));
return brush; return brush;
} }
return null;
}
public override SvgElement DeepCopy() public override SvgElement DeepCopy()
{ {
...@@ -89,13 +117,14 @@ namespace Svg ...@@ -89,13 +117,14 @@ namespace Svg
public override SvgElement DeepCopy<T>() public override SvgElement DeepCopy<T>()
{ {
var newObj = base.DeepCopy<T>() as SvgRadialGradientServer; var newObj = base.DeepCopy<T>() as SvgRadialGradientServer;
newObj.CenterX = this.CenterX; newObj.CenterX = this.CenterX;
newObj.CenterY = this.CenterY; newObj.CenterY = this.CenterY;
newObj.Radius = this.Radius; newObj.Radius = this.Radius;
newObj.FocalX = this.FocalX; newObj.FocalX = this.FocalX;
newObj.FocalY = this.FocalY; newObj.FocalY = this.FocalY;
return newObj;
return newObj;
} }
} }
} }
\ No newline at end of file
...@@ -53,7 +53,12 @@ namespace Svg ...@@ -53,7 +53,12 @@ namespace Svg
/// <param name="item">The <see cref="SvgElement"/> to be added.</param> /// <param name="item">The <see cref="SvgElement"/> to be added.</param>
public void Insert(int index, SvgElement item) public void Insert(int index, SvgElement item)
{ {
InsertAndForceUniqueID(index, item, false, false); InsertAndForceUniqueID(index, item, true, true, LogIDChange);
}
private void LogIDChange(SvgElement elem, string oldId, string newID)
{
Console.WriteLine("ID of SVG element " + elem.ToString() + " changed from " + oldId + " to " + newID);
} }
public void InsertAndForceUniqueID(int index, SvgElement item, bool autoForceUniqueID = true, bool autoFixChildrenID = true, Action<SvgElement, string, string> logElementOldIDNewID = null) public void InsertAndForceUniqueID(int index, SvgElement item, bool autoForceUniqueID = true, bool autoFixChildrenID = true, Action<SvgElement, string, string> logElementOldIDNewID = null)
...@@ -81,7 +86,7 @@ namespace Svg ...@@ -81,7 +86,7 @@ namespace Svg
public void Add(SvgElement item) public void Add(SvgElement item)
{ {
this.AddAndForceUniqueID(item, false, false); this.AddAndForceUniqueID(item, true, true, LogIDChange);
} }
public void AddAndForceUniqueID(SvgElement item, bool autoForceUniqueID = true, bool autoFixChildrenID = true, Action<SvgElement, string, string> logElementOldIDNewID = null) public void AddAndForceUniqueID(SvgElement item, bool autoForceUniqueID = true, bool autoFixChildrenID = true, Action<SvgElement, string, string> logElementOldIDNewID = null)
......
...@@ -134,6 +134,19 @@ namespace Svg ...@@ -134,6 +134,19 @@ namespace Svg
SetPropertyValue(element, style[0].Trim(), style[1].Trim(), document); SetPropertyValue(element, style[0].Trim(), style[1].Trim(), document);
} }
//defaults for text can come from the document
if (element.ElementName == "text")
{
if (!styles.Contains("font-size") && document.CustomAttributes.ContainsKey("font-size") && document.CustomAttributes["font-size"] != null)
{
SetPropertyValue(element, "font-size" , document.CustomAttributes["font-size"], document);
}
if (!styles.Contains("font-family") && document.CustomAttributes.ContainsKey("font-family") && document.CustomAttributes["font-family"] != null)
{
SetPropertyValue(element, "font-family", document.CustomAttributes["font-family"], document);
}
}
continue; continue;
} }
...@@ -176,7 +189,14 @@ namespace Svg ...@@ -176,7 +189,14 @@ namespace Svg
try try
{ {
if (attributeName == "opacity" && attributeValue == "undefined")
{
attributeValue = "1";
}
descriptor.SetValue(element, descriptor.Converter.ConvertFrom(document, CultureInfo.InvariantCulture, attributeValue)); descriptor.SetValue(element, descriptor.Converter.ConvertFrom(document, CultureInfo.InvariantCulture, attributeValue));
} }
catch catch
{ {
......
...@@ -97,6 +97,7 @@ namespace Svg ...@@ -97,6 +97,7 @@ namespace Svg
/// Ensures that the specified ID is valid within the containing <see cref="SvgDocument"/>. /// Ensures that the specified ID is valid within the containing <see cref="SvgDocument"/>.
/// </summary> /// </summary>
/// <param name="id">A <see cref="string"/> containing the ID to validate.</param> /// <param name="id">A <see cref="string"/> containing the ID to validate.</param>
/// <param name="autoForceUniqueID">Creates a new unique id <see cref="string"/>.</param>
/// <exception cref="SvgException"> /// <exception cref="SvgException">
/// <para>The ID cannot start with a digit.</para> /// <para>The ID cannot start with a digit.</para>
/// <para>An element with the same ID already exists within the containing <see cref="SvgDocument"/>.</para> /// <para>An element with the same ID already exists within the containing <see cref="SvgDocument"/>.</para>
......
...@@ -19,6 +19,8 @@ namespace Svg ...@@ -19,6 +19,8 @@ namespace Svg
{ {
private SvgUnit _x; private SvgUnit _x;
private SvgUnit _y; private SvgUnit _y;
private SvgUnit _dy;
private SvgUnit _dx;
private SvgUnit _letterSpacing; private SvgUnit _letterSpacing;
private SvgUnit _wordSpacing; private SvgUnit _wordSpacing;
private SvgUnit _fontSize; private SvgUnit _fontSize;
...@@ -47,6 +49,8 @@ namespace Svg ...@@ -47,6 +49,8 @@ namespace Svg
{ {
this._fontFamily = DefaultFontFamily; this._fontFamily = DefaultFontFamily;
this._fontSize = new SvgUnit(0.0f); this._fontSize = new SvgUnit(0.0f);
this._dy = new SvgUnit(0.0f);
this._dx = new SvgUnit(0.0f);
} }
/// <summary> /// <summary>
...@@ -97,6 +101,25 @@ namespace Svg ...@@ -97,6 +101,25 @@ namespace Svg
} }
} }
/// <summary>
/// Gets or sets the dX.
/// </summary>
/// <value>The dX.</value>
[SvgAttribute("dx")]
public virtual SvgUnit Dx
{
get { return this._dx; }
set
{
if (_dx != value)
{
this._dx = value;
this.IsPathDirty = true;
OnAttributeChanged(new AttributeEventArgs { Attribute = "dx", Value = value });
}
}
}
/// <summary> /// <summary>
/// Gets or sets the Y. /// Gets or sets the Y.
/// </summary> /// </summary>
...@@ -116,6 +139,25 @@ namespace Svg ...@@ -116,6 +139,25 @@ namespace Svg
} }
} }
/// <summary>
/// Gets or sets the dY.
/// </summary>
/// <value>The dY.</value>
[SvgAttribute("dy")]
public virtual SvgUnit Dy
{
get { return this._dy; }
set
{
if (_dy != value)
{
this._dy = value;
this.IsPathDirty = true;
OnAttributeChanged(new AttributeEventArgs { Attribute = "dy", Value = value });
}
}
}
/// <summary> /// <summary>
/// Specifies spacing behavior between text characters. /// Specifies spacing behavior between text characters.
/// </summary> /// </summary>
...@@ -270,9 +312,11 @@ namespace Svg ...@@ -270,9 +312,11 @@ namespace Svg
get get
{ {
// Make sure the path is always null if there is no text // Make sure the path is always null if there is no text
//if (string.IsNullOrEmpty(this.Text)) //if there is a TSpan inside of this text element then path should not be null (even if this text is empty!)
// _path = null; if (string.IsNullOrWhiteSpace(this.Text) && this.Children.Where(x => x is SvgTextSpan).Select(x => x as SvgTextSpan).Count() == 0)
return _path = null;
//NOT SURE WHAT THIS IS ABOUT - Path gets created again anyway - WTF? //NOT SURE WHAT THIS IS ABOUT - Path gets created again anyway - WTF?
// When an empty string is passed to GraphicsPath, it rises an InvalidArgumentException...
if (_path == null || this.IsPathDirty) if (_path == null || this.IsPathDirty)
{ {
...@@ -289,7 +333,7 @@ namespace Svg ...@@ -289,7 +333,7 @@ namespace Svg
_path.StartFigure(); _path.StartFigure();
if (!string.IsNullOrEmpty(this.Text)) if (!string.IsNullOrEmpty(this.Text))
DrawString(_path, this.X, this.Y, SvgUnit.Empty, SvgUnit.Empty, font, fontSize, this.Text); DrawString(_path, this.X, this.Y, this.Dx, this.Dy, font, fontSize, this.Text);
foreach (var tspan in this.Children.Where(x => x is SvgTextSpan).Select(x => x as SvgTextSpan)) foreach (var tspan in this.Children.Where(x => x is SvgTextSpan).Select(x => x as SvgTextSpan))
{ {
...@@ -319,7 +363,7 @@ namespace Svg ...@@ -319,7 +363,7 @@ namespace Svg
private static string ValidateFontFamily(string fontFamilyList) private static string ValidateFontFamily(string fontFamilyList)
{ {
// Split font family list on "," and then trim start and end spaces and quotes. // Split font family list on "," and then trim start and end spaces and quotes.
var fontParts = fontFamilyList.Split(new[] { ',' }).Select(fontName => fontName.Trim(new[] { '"', ' ' })); var fontParts = fontFamilyList.Split(new[] { ',' }).Select(fontName => fontName.Trim(new[] { '"', ' ','\'' }));
var families = System.Drawing.FontFamily.Families; var families = System.Drawing.FontFamily.Families;
......
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