Commit 2a58f88d authored by Tebjan Halm's avatar Tebjan Halm
Browse files

Merge pull request #213 from HeinrichAD/master

CurrentCulture Fix; SVG Viewer NullReferenceException fix; Little Maker rendering fix; Some optimization; Add "shape-rendering" support; Add "customer/ private fonts" support
parents a935f4ee 0f1186d9
...@@ -25,13 +25,10 @@ namespace SVGViewer ...@@ -25,13 +25,10 @@ namespace SVGViewer
if (openSvgFile.ShowDialog() == DialogResult.OK) if (openSvgFile.ShowDialog() == DialogResult.OK)
{ {
SvgDocument svgDoc = SvgDocument.Open(openSvgFile.FileName); SvgDocument svgDoc = SvgDocument.Open(openSvgFile.FileName);
RenderSvg(svgDoc); RenderSvg(svgDoc);
} }
} }
private string FXML = "";
private void textBox1_TextChanged(object sender, EventArgs e) private void textBox1_TextChanged(object sender, EventArgs e)
{ {
using(var s = new MemoryStream(UTF8Encoding.Default.GetBytes(textBox1.Text))) using(var s = new MemoryStream(UTF8Encoding.Default.GetBytes(textBox1.Text)))
...@@ -46,7 +43,13 @@ namespace SVGViewer ...@@ -46,7 +43,13 @@ namespace SVGViewer
//var render = new DebugRenderer(); //var render = new DebugRenderer();
//svgDoc.Draw(render); //svgDoc.Draw(render);
svgImage.Image = svgDoc.Draw(); svgImage.Image = svgDoc.Draw();
svgImage.Image.Save(System.IO.Path.Combine(System.IO.Path.GetDirectoryName(svgDoc.BaseUri.LocalPath), "output.png"));
string outputDir;
if (svgDoc.BaseUri == null)
outputDir = System.IO.Path.GetDirectoryName(Application.ExecutablePath);
else
outputDir = System.IO.Path.GetDirectoryName(svgDoc.BaseUri.LocalPath);
svgImage.Image.Save(System.IO.Path.Combine(outputDir, "output.png"));
} }
} }
} }
...@@ -84,17 +84,6 @@ namespace Svg ...@@ -84,17 +84,6 @@ namespace Svg
get { return this.Path(null).GetBounds(); } get { return this.Path(null).GetBounds(); }
} }
/// <summary>
/// Gets a value indicating whether the circle requires anti-aliasing when being rendered.
/// </summary>
/// <value>
/// <c>true</c> if the circle requires anti-aliasing; otherwise, <c>false</c>.
/// </value>
protected override bool RequiresSmoothRendering
{
get { return true; }
}
/// <summary> /// <summary>
/// Gets the <see cref="GraphicsPath"/> representing this element. /// Gets the <see cref="GraphicsPath"/> representing this element.
/// </summary> /// </summary>
......
...@@ -80,15 +80,6 @@ namespace Svg ...@@ -80,15 +80,6 @@ namespace Svg
} }
} }
/// <summary>
/// Gets or sets a value to determine if anti-aliasing should occur when the element is being rendered.
/// </summary>
/// <value></value>
protected override bool RequiresSmoothRendering
{
get { return true; }
}
/// <summary> /// <summary>
/// Gets the bounds of the element. /// Gets the bounds of the element.
/// </summary> /// </summary>
......
...@@ -31,7 +31,7 @@ namespace Svg ...@@ -31,7 +31,7 @@ namespace Svg
/// Gets or sets the marker (end cap) of the path. /// Gets or sets the marker (end cap) of the path.
/// </summary> /// </summary>
[SvgAttribute("marker-end")] [SvgAttribute("marker-end")]
public Uri MarkerEnd public virtual Uri MarkerEnd
{ {
get { return this.Attributes.GetAttribute<Uri>("marker-end").ReplaceWithNullIfNone(); } get { return this.Attributes.GetAttribute<Uri>("marker-end").ReplaceWithNullIfNone(); }
set { this.Attributes["marker-end"] = value; } set { this.Attributes["marker-end"] = value; }
...@@ -42,7 +42,7 @@ namespace Svg ...@@ -42,7 +42,7 @@ namespace Svg
/// Gets or sets the marker (start cap) of the path. /// Gets or sets the marker (start cap) of the path.
/// </summary> /// </summary>
[SvgAttribute("marker-mid")] [SvgAttribute("marker-mid")]
public Uri MarkerMid public virtual Uri MarkerMid
{ {
get { return this.Attributes.GetAttribute<Uri>("marker-mid").ReplaceWithNullIfNone(); } get { return this.Attributes.GetAttribute<Uri>("marker-mid").ReplaceWithNullIfNone(); }
set { this.Attributes["marker-mid"] = value; } set { this.Attributes["marker-mid"] = value; }
...@@ -53,17 +53,12 @@ namespace Svg ...@@ -53,17 +53,12 @@ namespace Svg
/// Gets or sets the marker (start cap) of the path. /// Gets or sets the marker (start cap) of the path.
/// </summary> /// </summary>
[SvgAttribute("marker-start")] [SvgAttribute("marker-start")]
public Uri MarkerStart public virtual Uri MarkerStart
{ {
get { return this.Attributes.GetAttribute<Uri>("marker-start").ReplaceWithNullIfNone(); } get { return this.Attributes.GetAttribute<Uri>("marker-start").ReplaceWithNullIfNone(); }
set { this.Attributes["marker-start"] = value; } set { this.Attributes["marker-start"] = value; }
} }
protected override bool RequiresSmoothRendering
{
get { return true; }
}
public override GraphicsPath Path(ISvgRenderer renderer) public override GraphicsPath Path(ISvgRenderer renderer)
{ {
if ((this._path == null || this.IsPathDirty) && base.StrokeWidth > 0) if ((this._path == null || this.IsPathDirty) && base.StrokeWidth > 0)
......
...@@ -18,7 +18,7 @@ namespace Svg ...@@ -18,7 +18,7 @@ namespace Svg
/// Gets or sets the marker (end cap) of the path. /// Gets or sets the marker (end cap) of the path.
/// </summary> /// </summary>
[SvgAttribute("marker-end")] [SvgAttribute("marker-end")]
public Uri MarkerEnd public override Uri MarkerEnd
{ {
get { return this.Attributes.GetAttribute<Uri>("marker-end").ReplaceWithNullIfNone(); } get { return this.Attributes.GetAttribute<Uri>("marker-end").ReplaceWithNullIfNone(); }
set { this.Attributes["marker-end"] = value; } set { this.Attributes["marker-end"] = value; }
...@@ -29,7 +29,7 @@ namespace Svg ...@@ -29,7 +29,7 @@ namespace Svg
/// Gets or sets the marker (start cap) of the path. /// Gets or sets the marker (start cap) of the path.
/// </summary> /// </summary>
[SvgAttribute("marker-mid")] [SvgAttribute("marker-mid")]
public Uri MarkerMid public override Uri MarkerMid
{ {
get { return this.Attributes.GetAttribute<Uri>("marker-mid").ReplaceWithNullIfNone(); } get { return this.Attributes.GetAttribute<Uri>("marker-mid").ReplaceWithNullIfNone(); }
set { this.Attributes["marker-mid"] = value; } set { this.Attributes["marker-mid"] = value; }
...@@ -40,7 +40,7 @@ namespace Svg ...@@ -40,7 +40,7 @@ namespace Svg
/// Gets or sets the marker (start cap) of the path. /// Gets or sets the marker (start cap) of the path.
/// </summary> /// </summary>
[SvgAttribute("marker-start")] [SvgAttribute("marker-start")]
public Uri MarkerStart public override Uri MarkerStart
{ {
get { return this.Attributes.GetAttribute<Uri>("marker-start").ReplaceWithNullIfNone(); } get { return this.Attributes.GetAttribute<Uri>("marker-start").ReplaceWithNullIfNone(); }
set { this.Attributes["marker-start"] = value; } set { this.Attributes["marker-start"] = value; }
......
...@@ -159,7 +159,13 @@ namespace Svg ...@@ -159,7 +159,13 @@ namespace Svg
/// </summary> /// </summary>
protected override bool RequiresSmoothRendering protected override bool RequiresSmoothRendering
{ {
get { return (CornerRadiusX.Value > 0 || CornerRadiusY.Value > 0); } get
{
if (base.RequiresSmoothRendering)
return (CornerRadiusX.Value > 0 || CornerRadiusY.Value > 0);
else
return false;
}
} }
/// <summary> /// <summary>
......
...@@ -11,7 +11,7 @@ namespace Svg ...@@ -11,7 +11,7 @@ namespace Svg
/// </summary> /// </summary>
public abstract partial class SvgVisualElement : SvgElement, ISvgBoundable, ISvgStylable, ISvgClipable public abstract partial class SvgVisualElement : SvgElement, ISvgBoundable, ISvgStylable, ISvgClipable
{ {
private bool _requiresSmoothRendering; private bool? _requiresSmoothRendering;
private Region _previousClip; private Region _previousClip;
/// <summary> /// <summary>
...@@ -86,7 +86,28 @@ namespace Svg ...@@ -86,7 +86,28 @@ namespace Svg
/// </summary> /// </summary>
protected virtual bool RequiresSmoothRendering protected virtual bool RequiresSmoothRendering
{ {
get { return this._requiresSmoothRendering; } get
{
if (_requiresSmoothRendering == null)
_requiresSmoothRendering = ConvertShapeRendering2AntiAlias(ShapeRendering);
return _requiresSmoothRendering.Value;
}
}
private bool ConvertShapeRendering2AntiAlias(SvgShapeRendering shapeRendering)
{
switch (shapeRendering)
{
case SvgShapeRendering.OptimizeSpeed:
case SvgShapeRendering.CrispEdges:
case SvgShapeRendering.GeometricPrecision:
return false;
default:
// SvgShapeRendering.Auto
// SvgShapeRendering.Inherit
return true;
}
} }
/// <summary> /// <summary>
...@@ -95,7 +116,6 @@ namespace Svg ...@@ -95,7 +116,6 @@ namespace Svg
public SvgVisualElement() public SvgVisualElement()
{ {
this.IsPathDirty = true; this.IsPathDirty = true;
this._requiresSmoothRendering = false;
} }
protected virtual bool Renderable { get { return true; } } protected virtual bool Renderable { get { return true; } }
......
using System; using System;
using System.ComponentModel;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.ComponentModel;
using System.Text;
using System.Globalization; using System.Globalization;
using System.Linq;
namespace Svg namespace Svg
{ {
...@@ -15,13 +14,18 @@ namespace Svg ...@@ -15,13 +14,18 @@ namespace Svg
{ {
public override string ToString() public override string ToString()
{ {
string ret = ""; // The correct separator should be a single white space.
foreach (var unit in this) // More see:
{ // http://www.w3.org/TR/SVG/coords.html
ret += unit.ToString() + " "; // "Superfluous white space and separators such as commas can be eliminated
} // (e.g., 'M 100 100 L 200 200' contains unnecessary spaces and could be expressed more compactly as 'M100 100L200 200')."
// http://www.w3.org/TR/SVGTiny12/paths.html#PathDataGeneralInformation
return ret; // https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/d#Notes
#if Net4
return String.Join(" ", this.Select(u => u.ToString()));
#else
return String.Join(" ", this.Select(u => u.ToString()).ToArray());
#endif
} }
public static bool IsNullOrEmpty(SvgUnitCollection collection) public static bool IsNullOrEmpty(SvgUnitCollection collection)
......
...@@ -132,7 +132,7 @@ namespace Svg ...@@ -132,7 +132,7 @@ namespace Svg
/// Refers to the size of the font from baseline to baseline when multiple lines of text are set solid in a multiline layout environment. /// Refers to the size of the font from baseline to baseline when multiple lines of text are set solid in a multiline layout environment.
/// </summary> /// </summary>
[SvgAttribute("font-size")] [SvgAttribute("font-size")]
public virtual SvgUnit FontSize public override SvgUnit FontSize
{ {
get { return (this.Attributes["font-size"] == null) ? SvgUnit.Empty : (SvgUnit)this.Attributes["font-size"]; } get { return (this.Attributes["font-size"] == null) ? SvgUnit.Empty : (SvgUnit)this.Attributes["font-size"]; }
set { this.Attributes["font-size"] = value; } set { this.Attributes["font-size"] = value; }
...@@ -142,7 +142,7 @@ namespace Svg ...@@ -142,7 +142,7 @@ namespace Svg
/// Indicates which font family is to be used to render the text. /// Indicates which font family is to be used to render the text.
/// </summary> /// </summary>
[SvgAttribute("font-family")] [SvgAttribute("font-family")]
public virtual string FontFamily public override string FontFamily
{ {
get { return this.Attributes["font-family"] as string; } get { return this.Attributes["font-family"] as string; }
set { this.Attributes["font-family"] = value; } set { this.Attributes["font-family"] = value; }
......
...@@ -5,10 +5,10 @@ using System.Globalization; ...@@ -5,10 +5,10 @@ using System.Globalization;
namespace Svg namespace Svg
{ {
//just overrrides canconvert and returns true //just overrrides canconvert and returns true
public class BaseConverter : TypeConverter public class BaseConverter : TypeConverter
{ {
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{ {
if (sourceType == typeof(string)) if (sourceType == typeof(string))
...@@ -29,43 +29,43 @@ namespace Svg ...@@ -29,43 +29,43 @@ namespace Svg
return base.CanConvertTo(context, destinationType); return base.CanConvertTo(context, destinationType);
} }
} }
public sealed class SvgBoolConverter : BaseConverter public sealed class SvgBoolConverter : BaseConverter
{ {
public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
{ {
if (value == null) if (value == null)
{ {
return true; return true;
} }
if (!(value is string)) if (!(value is string))
{ {
throw new ArgumentOutOfRangeException("value must be a string."); throw new ArgumentOutOfRangeException("value must be a string.");
} }
// Note: currently only used by SvgVisualElement.Visible but if // Note: currently only used by SvgVisualElement.Visible but if
// conversion is used elsewhere these checks below will need to change // conversion is used elsewhere these checks below will need to change
string visibility = (string)value; string visibility = (string)value;
if ((visibility == "hidden") || (visibility == "collapse")) if ((visibility == "hidden") || (visibility == "collapse"))
return false; return false;
else else
return true; return true;
} }
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
{ {
if (destinationType == typeof(string)) if (destinationType == typeof(string))
{ {
return ((bool)value) ? "visible" : "hidden"; return ((bool)value) ? "visible" : "hidden";
} }
return base.ConvertTo(context, culture, value, destinationType); return base.ConvertTo(context, culture, value, destinationType);
} }
} }
//converts enums to lower case strings //converts enums to lower case strings
public class EnumBaseConverter<T> : BaseConverter public class EnumBaseConverter<T> : BaseConverter
where T : struct where T : struct
{ {
/// <summary>If specified, upon conversion, the default value will result in 'null'.</summary> /// <summary>If specified, upon conversion, the default value will result in 'null'.</summary>
...@@ -82,26 +82,26 @@ namespace Svg ...@@ -82,26 +82,26 @@ namespace Svg
} }
/// <summary>Attempts to convert the provided value to <typeparamref name="T"/>.</summary> /// <summary>Attempts to convert the provided value to <typeparamref name="T"/>.</summary>
public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
{ {
if (value == null) if (value == null)
{ {
if (this.DefaultValue.HasValue) if (this.DefaultValue.HasValue)
return this.DefaultValue.Value; return this.DefaultValue.Value;
return Activator.CreateInstance(typeof(T)); return Activator.CreateInstance(typeof(T));
} }
if (!(value is string)) if (!(value is string))
{ {
throw new ArgumentOutOfRangeException("value must be a string."); throw new ArgumentOutOfRangeException("value must be a string.");
} }
return (T)Enum.Parse(typeof(T), (string)value, true); return (T)Enum.Parse(typeof(T), (string)value, true);
} }
/// <summary>Attempts to convert the value to the destination type.</summary> /// <summary>Attempts to convert the value to the destination type.</summary>
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
{ {
if (destinationType == typeof(string) && value is T) if (destinationType == typeof(string) && value is T)
{ {
...@@ -121,13 +121,13 @@ namespace Svg ...@@ -121,13 +121,13 @@ namespace Svg
return base.ConvertTo(context, culture, value, destinationType); return base.ConvertTo(context, culture, value, destinationType);
} }
} }
public sealed class SvgFillRuleConverter : EnumBaseConverter<SvgFillRule> public sealed class SvgFillRuleConverter : EnumBaseConverter<SvgFillRule>
{ {
public SvgFillRuleConverter() : base(SvgFillRule.NonZero) { } public SvgFillRuleConverter() : base(SvgFillRule.NonZero) { }
} }
public sealed class SvgColourInterpolationConverter : EnumBaseConverter<SvgColourInterpolation> public sealed class SvgColourInterpolationConverter : EnumBaseConverter<SvgColourInterpolation>
{ {
public SvgColourInterpolationConverter() : base(SvgColourInterpolation.SRGB) { } public SvgColourInterpolationConverter() : base(SvgColourInterpolation.SRGB) { }
...@@ -153,36 +153,51 @@ namespace Svg ...@@ -153,36 +153,51 @@ namespace Svg
public SvgStrokeLineJoinConverter() : base(SvgStrokeLineJoin.Miter) { } public SvgStrokeLineJoinConverter() : base(SvgStrokeLineJoin.Miter) { }
} }
public sealed class SvgMarkerUnitsConverter : EnumBaseConverter<SvgMarkerUnits> public sealed class SvgMarkerUnitsConverter : EnumBaseConverter<SvgMarkerUnits>
{ {
public SvgMarkerUnitsConverter() : base(SvgMarkerUnits.StrokeWidth) { } public SvgMarkerUnitsConverter() : base(SvgMarkerUnits.StrokeWidth) { }
} }
public sealed class SvgFontStyleConverter : EnumBaseConverter<SvgFontStyle> public sealed class SvgFontStyleConverter : EnumBaseConverter<SvgFontStyle>
{ {
public SvgFontStyleConverter() : base(SvgFontStyle.All) { } public SvgFontStyleConverter() : base(SvgFontStyle.All) { }
} }
public sealed class SvgOverflowConverter : EnumBaseConverter<SvgOverflow> public sealed class SvgOverflowConverter : EnumBaseConverter<SvgOverflow>
{ {
public SvgOverflowConverter() : base(SvgOverflow.Auto) { } public SvgOverflowConverter() : base(SvgOverflow.Auto) { }
} }
public sealed class SvgTextLengthAdjustConverter : EnumBaseConverter<SvgTextLengthAdjust> public sealed class SvgTextLengthAdjustConverter : EnumBaseConverter<SvgTextLengthAdjust>
{ {
public SvgTextLengthAdjustConverter() : base(SvgTextLengthAdjust.Spacing) { } public SvgTextLengthAdjustConverter() : base(SvgTextLengthAdjust.Spacing) { }
} }
public sealed class SvgTextPathMethodConverter : EnumBaseConverter<SvgTextPathMethod> public sealed class SvgTextPathMethodConverter : EnumBaseConverter<SvgTextPathMethod>
{ {
public SvgTextPathMethodConverter() : base(SvgTextPathMethod.Align) { } public SvgTextPathMethodConverter() : base(SvgTextPathMethod.Align) { }
} }
public sealed class SvgTextPathSpacingConverter : EnumBaseConverter<SvgTextPathSpacing> public sealed class SvgTextPathSpacingConverter : EnumBaseConverter<SvgTextPathSpacing>
{ {
public SvgTextPathSpacingConverter() : base(SvgTextPathSpacing.Exact) { } public SvgTextPathSpacingConverter() : base(SvgTextPathSpacing.Exact) { }
} }
public sealed class SvgShapeRenderingConverter : EnumBaseConverter<SvgShapeRendering>
{
public SvgShapeRenderingConverter() : base(SvgShapeRendering.Inherit) { }
}
public sealed class SvgTextRenderingConverter : EnumBaseConverter<SvgTextRendering>
{
public SvgTextRenderingConverter() : base(SvgTextRendering.Inherit) { }
}
public sealed class SvgImageRenderingConverter : EnumBaseConverter<SvgImageRendering>
{
public SvgImageRenderingConverter() : base(SvgImageRendering.Inherit) { }
}
public sealed class SvgFontVariantConverter : EnumBaseConverter<SvgFontVariant> public sealed class SvgFontVariantConverter : EnumBaseConverter<SvgFontVariant>
{ {
public SvgFontVariantConverter() : base(SvgFontVariant.Normal) { } public SvgFontVariantConverter() : base(SvgFontVariant.Normal) { }
...@@ -287,6 +302,7 @@ namespace Svg ...@@ -287,6 +302,7 @@ namespace Svg
public static class Enums public static class Enums
{ {
[CLSCompliant(false)]
public static bool TryParse<TEnum>(string value, out TEnum result) where TEnum : struct, IConvertible public static bool TryParse<TEnum>(string value, out TEnum result) where TEnum : struct, IConvertible
{ {
var retValue = value == null ? var retValue = value == null ?
......
...@@ -33,129 +33,135 @@ namespace Svg ...@@ -33,129 +33,135 @@ namespace Svg
if (colour != null) if (colour != null)
{ {
var oldCulture = Thread.CurrentThread.CurrentCulture; var oldCulture = Thread.CurrentThread.CurrentCulture;
Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.InvariantCulture; try {
Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.InvariantCulture;
colour = colour.Trim();
if (colour.StartsWith("rgb")) colour = colour.Trim();
{
try
{
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);
//determine the alpha value if this is an RGBA (it will be the 4th value if there is one) if (colour.StartsWith("rgb"))
int alphaValue = 255; {
if (values.Length > 3) try
{ {
//the alpha portion of the rgba is not an int 0-255 it is a decimal between 0 and 1 int start = colour.IndexOf("(") + 1;
//so we have to determine the corosponding byte value
var alphastring = values[3]; //get the values from the RGB string
if(alphastring.StartsWith(".")) string[] values = colour.Substring(start, colour.IndexOf(")") - start).Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries);
//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)
{ {
alphastring = "0" + alphastring; //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
var alphastring = values[3];
if (alphastring.StartsWith("."))
{
alphastring = "0" + alphastring;
}
var alphaDecimal = decimal.Parse(alphastring);
var alphaDecimal = decimal.Parse(alphastring); if (alphaDecimal <= 1)
{
alphaValue = (int)(alphaDecimal * 255);
}
else
{
alphaValue = (int)alphaDecimal;
}
}
if(alphaDecimal <= 1) Color colorpart;
if (values[0].Trim().EndsWith("%"))
{ {
alphaValue = (int)(alphaDecimal * 255); colorpart = System.Drawing.Color.FromArgb(alphaValue, (int)(255 * float.Parse(values[0].Trim().TrimEnd('%')) / 100f),
(int)(255 * float.Parse(values[1].Trim().TrimEnd('%')) / 100f),
(int)(255 * float.Parse(values[2].Trim().TrimEnd('%')) / 100f));
} }
else else
{ {
alphaValue = (int)alphaDecimal; colorpart = System.Drawing.Color.FromArgb(alphaValue, int.Parse(values[0]), int.Parse(values[1]), int.Parse(values[2]));
} }
}
Color colorpart; return colorpart;
if (values[0].Trim().EndsWith("%"))
{
colorpart = System.Drawing.Color.FromArgb(alphaValue, (int)(255 * float.Parse(values[0].Trim().TrimEnd('%')) / 100f),
(int)(255 * float.Parse(values[1].Trim().TrimEnd('%')) / 100f),
(int)(255 * float.Parse(values[2].Trim().TrimEnd('%')) / 100f));
} }
else catch
{ {
colorpart = System.Drawing.Color.FromArgb(alphaValue, int.Parse(values[0]), int.Parse(values[1]), int.Parse(values[2])); throw new SvgException("Colour is in an invalid format: '" + colour + "'");
} }
return colorpart;
} }
catch // HSL support
{ else if (colour.StartsWith("hsl")) {
throw new SvgException("Colour is in an invalid format: '" + colour + "'"); try
}
}
// HSL support
else if ( colour.StartsWith( "hsl" ) ) {
try
{
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);
if ( values[1].EndsWith( "%" ) )
{ {
values[1] = values[1].TrimEnd( '%' ); 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);
if (values[1].EndsWith("%"))
{
values[1] = values[1].TrimEnd('%');
}
if (values[2].EndsWith("%"))
{
values[2] = values[2].TrimEnd('%');
}
// Get the HSL values in a range from 0 to 1.
double h = double.Parse(values[0]) / 360.0;
double s = double.Parse(values[1]) / 100.0;
double l = double.Parse(values[2]) / 100.0;
// Convert the HSL color to an RGB color
Color colorpart = Hsl2Rgb(h, s, l);
return colorpart;
} }
if ( values[2].EndsWith( "%" ) ) catch
{ {
values[2] = values[2].TrimEnd( '%' ); throw new SvgException("Colour is in an invalid format: '" + colour + "'");
} }
// Get the HSL values in a range from 0 to 1.
double h = double.Parse( values[0] ) / 360.0;
double s = double.Parse( values[1] ) / 100.0;
double l = double.Parse( values[2] ) / 100.0;
// Convert the HSL color to an RGB color
Color colorpart = Hsl2Rgb( h, s, l );
return colorpart;
} }
catch else if (colour.StartsWith("#") && colour.Length == 4)
{ {
throw new SvgException("Colour is in an invalid format: '" + colour + "'"); colour = string.Format(culture, "#{0}{0}{1}{1}{2}{2}", colour[1], colour[2], colour[3]);
return base.ConvertFrom(context, culture, colour);
} }
switch (colour.ToLowerInvariant())
{
case "activeborder": return SystemColors.ActiveBorder;
case "activecaption": return SystemColors.ActiveCaption;
case "appworkspace": return SystemColors.AppWorkspace;
case "background": return SystemColors.Desktop;
case "buttonface": return SystemColors.Control;
case "buttonhighlight": return SystemColors.ControlLightLight;
case "buttonshadow": return SystemColors.ControlDark;
case "buttontext": return SystemColors.ControlText;
case "captiontext": return SystemColors.ActiveCaptionText;
case "graytext": return SystemColors.GrayText;
case "highlight": return SystemColors.Highlight;
case "highlighttext": return SystemColors.HighlightText;
case "inactiveborder": return SystemColors.InactiveBorder;
case "inactivecaption": return SystemColors.InactiveCaption;
case "inactivecaptiontext": return SystemColors.InactiveCaptionText;
case "infobackground": return SystemColors.Info;
case "infotext": return SystemColors.InfoText;
case "menu": return SystemColors.Menu;
case "menutext": return SystemColors.MenuText;
case "scrollbar": return SystemColors.ScrollBar;
case "threeddarkshadow": return SystemColors.ControlDarkDark;
case "threedface": return SystemColors.Control;
case "threedhighlight": return SystemColors.ControlLight;
case "threedlightshadow": return SystemColors.ControlLightLight;
case "window": return SystemColors.Window;
case "windowframe": return SystemColors.WindowFrame;
case "windowtext": return SystemColors.WindowText;
}
} }
else if (colour.StartsWith("#") && colour.Length == 4) finally
{
colour = string.Format(culture, "#{0}{0}{1}{1}{2}{2}", colour[1], colour[2], colour[3]);
return base.ConvertFrom(context, culture, colour);
}
switch (colour.ToLowerInvariant())
{ {
case "activeborder": return SystemColors.ActiveBorder; // Make sure to set back the old culture even an error occurred.
case "activecaption": return SystemColors.ActiveCaption; Thread.CurrentThread.CurrentCulture = oldCulture;
case "appworkspace": return SystemColors.AppWorkspace;
case "background": return SystemColors.Desktop;
case "buttonface": return SystemColors.Control;
case "buttonhighlight": return SystemColors.ControlLightLight;
case "buttonshadow": return SystemColors.ControlDark;
case "buttontext": return SystemColors.ControlText;
case "captiontext": return SystemColors.ActiveCaptionText;
case "graytext": return SystemColors.GrayText;
case "highlight": return SystemColors.Highlight;
case "highlighttext": return SystemColors.HighlightText;
case "inactiveborder": return SystemColors.InactiveBorder;
case "inactivecaption": return SystemColors.InactiveCaption;
case "inactivecaptiontext": return SystemColors.InactiveCaptionText;
case "infobackground": return SystemColors.Info;
case "infotext": return SystemColors.InfoText;
case "menu": return SystemColors.Menu;
case "menutext": return SystemColors.MenuText;
case "scrollbar": return SystemColors.ScrollBar;
case "threeddarkshadow": return SystemColors.ControlDarkDark;
case "threedface": return SystemColors.Control;
case "threedhighlight": return SystemColors.ControlLight;
case "threedlightshadow": return SystemColors.ControlLightLight;
case "window": return SystemColors.Window;
case "windowframe": return SystemColors.WindowFrame;
case "windowtext": return SystemColors.WindowText;
} }
Thread.CurrentThread.CurrentCulture = oldCulture;
} }
return base.ConvertFrom(context, culture, value); return base.ConvertFrom(context, culture, value);
......
...@@ -180,7 +180,7 @@ namespace Svg ...@@ -180,7 +180,7 @@ namespace Svg
var currentStop = this.Stops[radial ? this.Stops.Count - 1 - actualStops : actualStops]; var currentStop = this.Stops[radial ? this.Stops.Count - 1 - actualStops : actualStops];
var boundWidth = renderer.GetBoundable().Bounds.Width; var boundWidth = renderer.GetBoundable().Bounds.Width;
mergedOpacity = opacity * currentStop.GetOpacity(); mergedOpacity = opacity * currentStop.Opacity;
position = position =
radial radial
? 1 - (currentStop.Offset.ToDeviceValue(renderer, UnitRenderingType.Horizontal, this) / boundWidth) ? 1 - (currentStop.Offset.ToDeviceValue(renderer, UnitRenderingType.Horizontal, this) / boundWidth)
......
...@@ -57,7 +57,7 @@ namespace Svg ...@@ -57,7 +57,7 @@ namespace Svg
/// </summary> /// </summary>
[SvgAttribute("stop-color")] [SvgAttribute("stop-color")]
[TypeConverter(typeof(SvgPaintServerFactory))] [TypeConverter(typeof(SvgPaintServerFactory))]
public SvgPaintServer StopColor public override SvgPaintServer StopColor
{ {
get get
{ {
...@@ -72,16 +72,10 @@ namespace Svg ...@@ -72,16 +72,10 @@ namespace Svg
/// Gets or sets the opacity of the gradient stop (0-1). /// Gets or sets the opacity of the gradient stop (0-1).
/// </summary> /// </summary>
[SvgAttribute("stop-opacity")] [SvgAttribute("stop-opacity")]
public string Opacity public override float Opacity
{ {
get { return this.Attributes["stop-opacity"] as string; } get { return (this.Attributes["stop-opacity"] == null) ? 1.0f : (float)this.Attributes["stop-opacity"]; }
set { this.Attributes["stop-opacity"] = value; } set { this.Attributes["stop-opacity"] = FixOpacityValue(value); }
}
public float GetOpacity()
{
var opacity = this.Opacity;
return string.IsNullOrEmpty(opacity) ? 1.0f : float.Parse(opacity);
} }
/// <summary> /// <summary>
......
...@@ -133,9 +133,14 @@ namespace Svg ...@@ -133,9 +133,14 @@ namespace Svg
/// <param name="pMarkerPoint2"></param> /// <param name="pMarkerPoint2"></param>
public void RenderMarker(ISvgRenderer pRenderer, SvgVisualElement pOwner, PointF pRefPoint, PointF pMarkerPoint1, PointF pMarkerPoint2) public void RenderMarker(ISvgRenderer pRenderer, SvgVisualElement pOwner, PointF pRefPoint, PointF pMarkerPoint1, PointF pMarkerPoint2)
{ {
float xDiff = pMarkerPoint2.X - pMarkerPoint1.X; float fAngle1 = 0f;
float yDiff = pMarkerPoint2.Y - pMarkerPoint1.Y; if (Orient.IsAuto)
float fAngle1 = (float)(Math.Atan2(yDiff, xDiff) * 180.0 / Math.PI); {
// Only calculate this if needed.
float xDiff = pMarkerPoint2.X - pMarkerPoint1.X;
float yDiff = pMarkerPoint2.Y - pMarkerPoint1.Y;
fAngle1 = (float)(Math.Atan2(yDiff, xDiff) * 180.0 / Math.PI);
}
RenderPart2(fAngle1, pRenderer, pOwner, pRefPoint); RenderPart2(fAngle1, pRenderer, pOwner, pRefPoint);
} }
...@@ -184,10 +189,22 @@ namespace Svg ...@@ -184,10 +189,22 @@ namespace Svg
switch (MarkerUnits) switch (MarkerUnits)
{ {
case SvgMarkerUnits.StrokeWidth: case SvgMarkerUnits.StrokeWidth:
transMatrix.Translate(AdjustForViewBoxWidth(-RefX.ToDeviceValue(pRenderer, UnitRenderingType.Horizontal, this) * if (ViewBox.Width > 0 && ViewBox.Height > 0)
pOwner.StrokeWidth.ToDeviceValue(pRenderer, UnitRenderingType.Other, this)), {
AdjustForViewBoxHeight(-RefY.ToDeviceValue(pRenderer, UnitRenderingType.Vertical, this) * transMatrix.Translate(AdjustForViewBoxWidth(-RefX.ToDeviceValue(pRenderer, UnitRenderingType.Horizontal, this) *
pOwner.StrokeWidth.ToDeviceValue(pRenderer, UnitRenderingType.Other, this))); pOwner.StrokeWidth.ToDeviceValue(pRenderer, UnitRenderingType.Other, this)),
AdjustForViewBoxHeight(-RefY.ToDeviceValue(pRenderer, UnitRenderingType.Vertical, this) *
pOwner.StrokeWidth.ToDeviceValue(pRenderer, UnitRenderingType.Other, this)));
}
else
{
// SvgMarkerUnits.UserSpaceOnUse
// TODO: We know this isn't correct.
// But use this until the TODOs from AdjustForViewBoxWidth and AdjustForViewBoxHeight are done.
// MORE see Unit Test "MakerEndTest.TestArrowCodeCreation()"
transMatrix.Translate(-RefX.ToDeviceValue(pRenderer, UnitRenderingType.Horizontal, this),
-RefY.ToDeviceValue(pRenderer, UnitRenderingType.Vertical, this));
}
break; break;
case SvgMarkerUnits.UserSpaceOnUse: case SvgMarkerUnits.UserSpaceOnUse:
transMatrix.Translate(-RefX.ToDeviceValue(pRenderer, UnitRenderingType.Horizontal, this), transMatrix.Translate(-RefX.ToDeviceValue(pRenderer, UnitRenderingType.Horizontal, this),
......
...@@ -25,12 +25,12 @@ namespace Svg ...@@ -25,12 +25,12 @@ namespace Svg
private SvgCoordinateUnits _patternUnits = SvgCoordinateUnits.Inherit; private SvgCoordinateUnits _patternUnits = SvgCoordinateUnits.Inherit;
private SvgCoordinateUnits _patternContentUnits = SvgCoordinateUnits.Inherit; private SvgCoordinateUnits _patternContentUnits = SvgCoordinateUnits.Inherit;
[SvgAttribute("overflow")] [SvgAttribute("overflow")]
public SvgOverflow Overflow public SvgOverflow Overflow
{ {
get { return this.Attributes.GetAttribute<SvgOverflow>("overflow"); } get { return this.Attributes.GetAttribute<SvgOverflow>("overflow"); }
set { this.Attributes["overflow"] = value; } set { this.Attributes["overflow"] = value; }
} }
/// <summary> /// <summary>
...@@ -50,10 +50,10 @@ namespace Svg ...@@ -50,10 +50,10 @@ namespace Svg
/// <value></value> /// <value></value>
[SvgAttribute("preserveAspectRatio")] [SvgAttribute("preserveAspectRatio")]
public SvgAspectRatio AspectRatio public SvgAspectRatio AspectRatio
{ {
get; get;
set; set;
} }
/// <summary> /// <summary>
/// Gets or sets the width of the pattern. /// Gets or sets the width of the pattern.
...@@ -135,7 +135,7 @@ namespace Svg ...@@ -135,7 +135,7 @@ namespace Svg
set { this.Attributes["gradientTransform"] = value; } set { this.Attributes["gradientTransform"] = value; }
} }
protected Matrix EffectivePatternTransform private Matrix EffectivePatternTransform
{ {
get get
{ {
...@@ -251,25 +251,25 @@ namespace Svg ...@@ -251,25 +251,25 @@ namespace Svg
} }
} }
public override SvgElement DeepCopy() public override SvgElement DeepCopy()
{ {
return DeepCopy<SvgPatternServer>(); return DeepCopy<SvgPatternServer>();
} }
public override SvgElement DeepCopy<T>() public override SvgElement DeepCopy<T>()
{ {
var newObj = base.DeepCopy<T>() as SvgPatternServer; var newObj = base.DeepCopy<T>() as SvgPatternServer;
newObj.Overflow = this.Overflow; newObj.Overflow = this.Overflow;
newObj.ViewBox = this.ViewBox; newObj.ViewBox = this.ViewBox;
newObj.AspectRatio = this.AspectRatio; newObj.AspectRatio = this.AspectRatio;
newObj.X = this.X; newObj.X = this.X;
newObj.Y = this.Y; newObj.Y = this.Y;
newObj.Width = this.Width; newObj.Width = this.Width;
newObj.Height = this.Height; newObj.Height = this.Height;
return newObj; return newObj;
} }
public SvgCoordinateUnits GetUnits() public SvgCoordinateUnits GetUnits()
{ {
......
...@@ -147,7 +147,7 @@ namespace Svg ...@@ -147,7 +147,7 @@ namespace Svg
{ {
var stop = Stops.Last(); var stop = Stops.Last();
var origColor = stop.GetColor(renderingElement); var origColor = stop.GetColor(renderingElement);
var renderColor = System.Drawing.Color.FromArgb((int)(opacity * stop.GetOpacity() * 255), origColor); var renderColor = System.Drawing.Color.FromArgb((int)(opacity * stop.Opacity * 255), origColor);
var origClip = renderer.GetClip(); var origClip = renderer.GetClip();
try try
......
...@@ -104,14 +104,6 @@ namespace Svg ...@@ -104,14 +104,6 @@ namespace Svg
OnAttributeChanged(new AttributeEventArgs{ Attribute = "d", Value = this.Attributes.GetAttribute<SvgPathSegmentList>("d") }); OnAttributeChanged(new AttributeEventArgs{ Attribute = "d", Value = this.Attributes.GetAttribute<SvgPathSegmentList>("d") });
} }
/// <summary>
/// Gets or sets a value to determine if anti-aliasing should occur when the element is being rendered.
/// </summary>
protected override bool RequiresSmoothRendering
{
get { return true; }
}
/// <summary> /// <summary>
/// Gets the bounds of the element. /// Gets the bounds of the element.
/// </summary> /// </summary>
......
...@@ -522,10 +522,16 @@ namespace Svg ...@@ -522,10 +522,16 @@ namespace Svg
if (paths != null) if (paths != null)
{ {
var curretCulture = CultureInfo.CurrentCulture; var curretCulture = CultureInfo.CurrentCulture;
Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; try {
var s = string.Join(" ", paths.Select(p => p.ToString()).ToArray()); Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
Thread.CurrentThread.CurrentCulture = curretCulture; var s = string.Join(" ", paths.Select(p => p.ToString()).ToArray());
return s; return s;
}
finally
{
// Make sure to set back the old culture even an error occurred.
Thread.CurrentThread.CurrentCulture = curretCulture;
}
} }
} }
......
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
namespace Svg
{
/// <summary>
/// The creator of SVG content might want to provide a hint about what tradeoffs to make as the browser renders <path> element or basic shapes. The shape-rendering attribute provides these hints.
/// </summary>
/// <references>https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/shape-rendering</references>
/// <remarks>
/// Default is <see cref="Inherit"/>. That means the value comes from the parent element. If parents are also not set, then the value is <see cref="Auto"/>.
/// </remarks>
[TypeConverter(typeof(SvgShapeRenderingConverter))]
public enum SvgShapeRendering
{
/// <summary>
/// Indicates that the SVG shape rendering properties from the parent will be used.
/// </summary>
/// <AnitAlias>Based of parent. If parents are also not set, then <see cref="Auto"/></AnitAlias>
Inherit,
/// <summary>
/// Indicates that the user agent shall make appropriate tradeoffs to balance speed, crisp edges and geometric precision, but with geometric precision given more importance than speed and crisp edges.
/// </summary>
/// <AnitAlias>true</AnitAlias>
Auto,
/// <summary>
/// Indicates that the user agent shall emphasize rendering speed over geometric precision and crisp edges. This option will sometimes cause the user agent to turn off shape anti-aliasing.
/// </summary>
/// <AnitAlias>false</AnitAlias>
OptimizeSpeed,
/// <summary>
/// Indicates that the user agent shall attempt to emphasize the contrast between clean edges of artwork over rendering speed and geometric precision. To achieve crisp edges, the user agent might turn off anti-aliasing for all lines and curves or possibly just for straight lines which are close to vertical or horizontal. Also, the user agent might adjust line positions and line widths to align edges with device pixels.
/// </summary>
/// <AnitAlias>false</AnitAlias>
CrispEdges,
/// <summary>
/// Indicates that the user agent shall emphasize geometric precision over speed and crisp edges.
/// </summary>
/// <AnitAlias>false</AnitAlias>
GeometricPrecision
}
/// <summary>
/// The creator of SVG content might want to provide a hint about what tradeoffs to make as the browser renders text. The text-rendering attribute provides these hints.
/// </summary>
/// <references>https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/text-rendering</references>
/// <remarks>Not Implemented yet.</remarks>
[TypeConverter(typeof(SvgTextRenderingConverter))]
public enum SvgTextRendering
{
/// <summary>
/// Indicates that the SVG shape rendering properties from the parent will be used.
/// </summary>
Inherit,
/// <summary>
/// Indicates that the browser shall make appropriate tradeoffs to balance speed, legibility and geometric precision, but with legibility given more importance than speed and geometric precision.
/// </summary>
Auto,
/// <summary>
/// Indicates that the user agent shall emphasize rendering speed over legibility and geometric precision. This option will sometimes cause some browsers to turn off text anti-aliasing.
/// </summary>
OptimizeSpeed,
/// <summary>
/// Indicates that the browser shall emphasize legibility over rendering speed and geometric precision. The user agent will often choose whether to apply anti-aliasing techniques, built-in font hinting or both to produce the most legible text.
/// </summary>
OptimizeLegibility,
/// <summary>
/// Indicates that the browser shall emphasize geometric precision over legibility and rendering speed. This option will usually cause the user agent to suspend the use of hinting so that glyph outlines are drawn with comparable geometric precision to the rendering of path data.
/// </summary>
GeometricPrecision
}
/// <summary>
/// The image-rendering attribute provides a hint to the browser about how to make speed vs. quality tradeoffs as it performs image processing.
/// </summary>
/// <references>https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/image-rendering</references>
/// <remarks>Not Implemented yet.</remarks>
[TypeConverter(typeof(SvgImageRenderingConverter))]
public enum SvgImageRendering
{
/// <summary>
/// Indicates that the SVG shape rendering properties from the parent will be used.
/// </summary>
Inherit,
/// <summary>
/// Indicates that the user agent shall make appropriate tradeoffs to balance speed and quality, but quality shall be given more importance than speed.
/// </summary>
Auto,
/// <summary>
/// Indicates that the user agent shall emphasize rendering speed over quality.
/// </summary>
OptimizeSpeed,
/// <summary>
/// Indicates that the user agent shall emphasize quality over rendering speed.
/// </summary>
OptimizeQuality
}
}
...@@ -115,6 +115,7 @@ ...@@ -115,6 +115,7 @@
<Compile Include="Paths\CoordinateParser.cs" /> <Compile Include="Paths\CoordinateParser.cs" />
<Compile Include="Rendering\IGraphicsProvider.cs" /> <Compile Include="Rendering\IGraphicsProvider.cs" />
<Compile Include="Rendering\ISvgRenderer.cs" /> <Compile Include="Rendering\ISvgRenderer.cs" />
<Compile Include="Rendering\SvgRendering.cs" />
<Compile Include="SvgElementStyle.cs" /> <Compile Include="SvgElementStyle.cs" />
<Compile Include="SvgNodeReader.cs" /> <Compile Include="SvgNodeReader.cs" />
<Compile Include="Css\CssQuery.cs" /> <Compile Include="Css\CssQuery.cs" />
......
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