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
No related merge requests found
Showing with 431 additions and 277 deletions
+431 -277
......@@ -25,13 +25,10 @@ namespace SVGViewer
if (openSvgFile.ShowDialog() == DialogResult.OK)
{
SvgDocument svgDoc = SvgDocument.Open(openSvgFile.FileName);
RenderSvg(svgDoc);
}
}
private string FXML = "";
private void textBox1_TextChanged(object sender, EventArgs e)
{
using(var s = new MemoryStream(UTF8Encoding.Default.GetBytes(textBox1.Text)))
......@@ -46,7 +43,13 @@ namespace SVGViewer
//var render = new DebugRenderer();
//svgDoc.Draw(render);
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
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>
/// Gets the <see cref="GraphicsPath"/> representing this element.
/// </summary>
......
......@@ -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>
/// Gets the bounds of the element.
/// </summary>
......
......@@ -31,7 +31,7 @@ namespace Svg
/// Gets or sets the marker (end cap) of the path.
/// </summary>
[SvgAttribute("marker-end")]
public Uri MarkerEnd
public virtual Uri MarkerEnd
{
get { return this.Attributes.GetAttribute<Uri>("marker-end").ReplaceWithNullIfNone(); }
set { this.Attributes["marker-end"] = value; }
......@@ -42,7 +42,7 @@ namespace Svg
/// Gets or sets the marker (start cap) of the path.
/// </summary>
[SvgAttribute("marker-mid")]
public Uri MarkerMid
public virtual Uri MarkerMid
{
get { return this.Attributes.GetAttribute<Uri>("marker-mid").ReplaceWithNullIfNone(); }
set { this.Attributes["marker-mid"] = value; }
......@@ -53,17 +53,12 @@ namespace Svg
/// Gets or sets the marker (start cap) of the path.
/// </summary>
[SvgAttribute("marker-start")]
public Uri MarkerStart
public virtual Uri MarkerStart
{
get { return this.Attributes.GetAttribute<Uri>("marker-start").ReplaceWithNullIfNone(); }
set { this.Attributes["marker-start"] = value; }
}
protected override bool RequiresSmoothRendering
{
get { return true; }
}
public override GraphicsPath Path(ISvgRenderer renderer)
{
if ((this._path == null || this.IsPathDirty) && base.StrokeWidth > 0)
......
......@@ -18,7 +18,7 @@ namespace Svg
/// Gets or sets the marker (end cap) of the path.
/// </summary>
[SvgAttribute("marker-end")]
public Uri MarkerEnd
public override Uri MarkerEnd
{
get { return this.Attributes.GetAttribute<Uri>("marker-end").ReplaceWithNullIfNone(); }
set { this.Attributes["marker-end"] = value; }
......@@ -29,7 +29,7 @@ namespace Svg
/// Gets or sets the marker (start cap) of the path.
/// </summary>
[SvgAttribute("marker-mid")]
public Uri MarkerMid
public override Uri MarkerMid
{
get { return this.Attributes.GetAttribute<Uri>("marker-mid").ReplaceWithNullIfNone(); }
set { this.Attributes["marker-mid"] = value; }
......@@ -40,7 +40,7 @@ namespace Svg
/// Gets or sets the marker (start cap) of the path.
/// </summary>
[SvgAttribute("marker-start")]
public Uri MarkerStart
public override Uri MarkerStart
{
get { return this.Attributes.GetAttribute<Uri>("marker-start").ReplaceWithNullIfNone(); }
set { this.Attributes["marker-start"] = value; }
......
......@@ -159,7 +159,13 @@ namespace Svg
/// </summary>
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>
......
......@@ -11,7 +11,7 @@ namespace Svg
/// </summary>
public abstract partial class SvgVisualElement : SvgElement, ISvgBoundable, ISvgStylable, ISvgClipable
{
private bool _requiresSmoothRendering;
private bool? _requiresSmoothRendering;
private Region _previousClip;
/// <summary>
......@@ -86,7 +86,28 @@ namespace Svg
/// </summary>
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>
......@@ -95,7 +116,6 @@ namespace Svg
public SvgVisualElement()
{
this.IsPathDirty = true;
this._requiresSmoothRendering = false;
}
protected virtual bool Renderable { get { return true; } }
......
using System;
using System.ComponentModel;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
namespace Svg
{
......@@ -15,13 +14,18 @@ namespace Svg
{
public override string ToString()
{
string ret = "";
foreach (var unit in this)
{
ret += unit.ToString() + " ";
}
return ret;
// The correct separator should be a single white space.
// More see:
// http://www.w3.org/TR/SVG/coords.html
// "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
// 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)
......
......@@ -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.
/// </summary>
[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"]; }
set { this.Attributes["font-size"] = value; }
......@@ -142,7 +142,7 @@ namespace Svg
/// Indicates which font family is to be used to render the text.
/// </summary>
[SvgAttribute("font-family")]
public virtual string FontFamily
public override string FontFamily
{
get { return this.Attributes["font-family"] as string; }
set { this.Attributes["font-family"] = value; }
......
......@@ -5,10 +5,10 @@ using System.Globalization;
namespace Svg
{
//just overrrides canconvert and returns true
public class BaseConverter : TypeConverter
//just overrrides canconvert and returns true
public class BaseConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
if (sourceType == typeof(string))
......@@ -29,43 +29,43 @@ namespace Svg
return base.CanConvertTo(context, destinationType);
}
}
public sealed class SvgBoolConverter : BaseConverter
{
public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
{
if (value == null)
{
return true;
}
if (!(value is string))
{
throw new ArgumentOutOfRangeException("value must be a string.");
}
// Note: currently only used by SvgVisualElement.Visible but if
// conversion is used elsewhere these checks below will need to change
string visibility = (string)value;
if ((visibility == "hidden") || (visibility == "collapse"))
return false;
else
return true;
public sealed class SvgBoolConverter : BaseConverter
{
public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
{
if (value == null)
{
return true;
}
if (!(value is string))
{
throw new ArgumentOutOfRangeException("value must be a string.");
}
// Note: currently only used by SvgVisualElement.Visible but if
// conversion is used elsewhere these checks below will need to change
string visibility = (string)value;
if ((visibility == "hidden") || (visibility == "collapse"))
return false;
else
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))
{
return ((bool)value) ? "visible" : "hidden";
return ((bool)value) ? "visible" : "hidden";
}
return base.ConvertTo(context, culture, value, destinationType);
}
}
//converts enums to lower case strings
public class EnumBaseConverter<T> : BaseConverter
}
//converts enums to lower case strings
public class EnumBaseConverter<T> : BaseConverter
where T : struct
{
/// <summary>If specified, upon conversion, the default value will result in 'null'.</summary>
......@@ -82,26 +82,26 @@ namespace Svg
}
/// <summary>Attempts to convert the provided value to <typeparamref name="T"/>.</summary>
public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
{
if (value == null)
{
public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
{
if (value == null)
{
if (this.DefaultValue.HasValue)
return this.DefaultValue.Value;
return Activator.CreateInstance(typeof(T));
}
if (!(value is string))
{
throw new ArgumentOutOfRangeException("value must be a string.");
}
return (T)Enum.Parse(typeof(T), (string)value, true);
return Activator.CreateInstance(typeof(T));
}
if (!(value is string))
{
throw new ArgumentOutOfRangeException("value must be a string.");
}
return (T)Enum.Parse(typeof(T), (string)value, true);
}
/// <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)
{
......@@ -121,13 +121,13 @@ namespace Svg
return base.ConvertTo(context, culture, value, destinationType);
}
}
}
public sealed class SvgFillRuleConverter : EnumBaseConverter<SvgFillRule>
{
public SvgFillRuleConverter() : base(SvgFillRule.NonZero) { }
}
public sealed class SvgColourInterpolationConverter : EnumBaseConverter<SvgColourInterpolation>
{
public SvgColourInterpolationConverter() : base(SvgColourInterpolation.SRGB) { }
......@@ -153,36 +153,51 @@ namespace Svg
public SvgStrokeLineJoinConverter() : base(SvgStrokeLineJoin.Miter) { }
}
public sealed class SvgMarkerUnitsConverter : EnumBaseConverter<SvgMarkerUnits>
{
public sealed class SvgMarkerUnitsConverter : EnumBaseConverter<SvgMarkerUnits>
{
public SvgMarkerUnitsConverter() : base(SvgMarkerUnits.StrokeWidth) { }
}
}
public sealed class SvgFontStyleConverter : EnumBaseConverter<SvgFontStyle>
{
public sealed class SvgFontStyleConverter : EnumBaseConverter<SvgFontStyle>
{
public SvgFontStyleConverter() : base(SvgFontStyle.All) { }
}
}
public sealed class SvgOverflowConverter : EnumBaseConverter<SvgOverflow>
{
public sealed class SvgOverflowConverter : EnumBaseConverter<SvgOverflow>
{
public SvgOverflowConverter() : base(SvgOverflow.Auto) { }
}
}
public sealed class SvgTextLengthAdjustConverter : EnumBaseConverter<SvgTextLengthAdjust>
{
public sealed class SvgTextLengthAdjustConverter : EnumBaseConverter<SvgTextLengthAdjust>
{
public SvgTextLengthAdjustConverter() : base(SvgTextLengthAdjust.Spacing) { }
}
}
public sealed class SvgTextPathMethodConverter : EnumBaseConverter<SvgTextPathMethod>
{
public sealed class SvgTextPathMethodConverter : EnumBaseConverter<SvgTextPathMethod>
{
public SvgTextPathMethodConverter() : base(SvgTextPathMethod.Align) { }
}
}
public sealed class SvgTextPathSpacingConverter : EnumBaseConverter<SvgTextPathSpacing>
{
public sealed class SvgTextPathSpacingConverter : EnumBaseConverter<SvgTextPathSpacing>
{
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 SvgFontVariantConverter() : base(SvgFontVariant.Normal) { }
......@@ -287,6 +302,7 @@ namespace Svg
public static class Enums
{
[CLSCompliant(false)]
public static bool TryParse<TEnum>(string value, out TEnum result) where TEnum : struct, IConvertible
{
var retValue = value == null ?
......
......@@ -33,129 +33,135 @@ namespace Svg
if (colour != null)
{
var oldCulture = Thread.CurrentThread.CurrentCulture;
Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.InvariantCulture;
colour = colour.Trim();
try {
Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.InvariantCulture;
if (colour.StartsWith("rgb"))
{
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);
colour = colour.Trim();
//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)
if (colour.StartsWith("rgb"))
{
try
{
//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("."))
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)
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
{
alphaValue = (int)alphaDecimal;
colorpart = System.Drawing.Color.FromArgb(alphaValue, int.Parse(values[0]), int.Parse(values[1]), int.Parse(values[2]));
}
}
Color 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));
return colorpart;
}
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
{
throw new SvgException("Colour is in an invalid format: '" + colour + "'");
}
}
// 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( "%" ) )
// HSL support
else if (colour.StartsWith("hsl")) {
try
{
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)
{
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())
finally
{
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;
// Make sure to set back the old culture even an error occurred.
Thread.CurrentThread.CurrentCulture = oldCulture;
}
Thread.CurrentThread.CurrentCulture = oldCulture;
}
return base.ConvertFrom(context, culture, value);
......
......@@ -180,7 +180,7 @@ namespace Svg
var currentStop = this.Stops[radial ? this.Stops.Count - 1 - actualStops : actualStops];
var boundWidth = renderer.GetBoundable().Bounds.Width;
mergedOpacity = opacity * currentStop.GetOpacity();
mergedOpacity = opacity * currentStop.Opacity;
position =
radial
? 1 - (currentStop.Offset.ToDeviceValue(renderer, UnitRenderingType.Horizontal, this) / boundWidth)
......
......@@ -57,7 +57,7 @@ namespace Svg
/// </summary>
[SvgAttribute("stop-color")]
[TypeConverter(typeof(SvgPaintServerFactory))]
public SvgPaintServer StopColor
public override SvgPaintServer StopColor
{
get
{
......@@ -72,16 +72,10 @@ namespace Svg
/// Gets or sets the opacity of the gradient stop (0-1).
/// </summary>
[SvgAttribute("stop-opacity")]
public string Opacity
public override float Opacity
{
get { return this.Attributes["stop-opacity"] as string; }
set { this.Attributes["stop-opacity"] = value; }
}
public float GetOpacity()
{
var opacity = this.Opacity;
return string.IsNullOrEmpty(opacity) ? 1.0f : float.Parse(opacity);
get { return (this.Attributes["stop-opacity"] == null) ? 1.0f : (float)this.Attributes["stop-opacity"]; }
set { this.Attributes["stop-opacity"] = FixOpacityValue(value); }
}
/// <summary>
......
......@@ -133,9 +133,14 @@ namespace Svg
/// <param name="pMarkerPoint2"></param>
public void RenderMarker(ISvgRenderer pRenderer, SvgVisualElement pOwner, PointF pRefPoint, PointF pMarkerPoint1, PointF pMarkerPoint2)
{
float xDiff = pMarkerPoint2.X - pMarkerPoint1.X;
float yDiff = pMarkerPoint2.Y - pMarkerPoint1.Y;
float fAngle1 = (float)(Math.Atan2(yDiff, xDiff) * 180.0 / Math.PI);
float fAngle1 = 0f;
if (Orient.IsAuto)
{
// 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);
}
......@@ -184,10 +189,22 @@ namespace Svg
switch (MarkerUnits)
{
case SvgMarkerUnits.StrokeWidth:
transMatrix.Translate(AdjustForViewBoxWidth(-RefX.ToDeviceValue(pRenderer, UnitRenderingType.Horizontal, this) *
pOwner.StrokeWidth.ToDeviceValue(pRenderer, UnitRenderingType.Other, this)),
AdjustForViewBoxHeight(-RefY.ToDeviceValue(pRenderer, UnitRenderingType.Vertical, this) *
pOwner.StrokeWidth.ToDeviceValue(pRenderer, UnitRenderingType.Other, this)));
if (ViewBox.Width > 0 && ViewBox.Height > 0)
{
transMatrix.Translate(AdjustForViewBoxWidth(-RefX.ToDeviceValue(pRenderer, UnitRenderingType.Horizontal, 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;
case SvgMarkerUnits.UserSpaceOnUse:
transMatrix.Translate(-RefX.ToDeviceValue(pRenderer, UnitRenderingType.Horizontal, this),
......
......@@ -25,12 +25,12 @@ namespace Svg
private SvgCoordinateUnits _patternUnits = SvgCoordinateUnits.Inherit;
private SvgCoordinateUnits _patternContentUnits = SvgCoordinateUnits.Inherit;
[SvgAttribute("overflow")]
public SvgOverflow Overflow
{
get { return this.Attributes.GetAttribute<SvgOverflow>("overflow"); }
set { this.Attributes["overflow"] = value; }
}
[SvgAttribute("overflow")]
public SvgOverflow Overflow
{
get { return this.Attributes.GetAttribute<SvgOverflow>("overflow"); }
set { this.Attributes["overflow"] = value; }
}
/// <summary>
......@@ -50,10 +50,10 @@ namespace Svg
/// <value></value>
[SvgAttribute("preserveAspectRatio")]
public SvgAspectRatio AspectRatio
{
get;
set;
}
{
get;
set;
}
/// <summary>
/// Gets or sets the width of the pattern.
......@@ -135,7 +135,7 @@ namespace Svg
set { this.Attributes["gradientTransform"] = value; }
}
protected Matrix EffectivePatternTransform
private Matrix EffectivePatternTransform
{
get
{
......@@ -251,25 +251,25 @@ namespace Svg
}
}
public override SvgElement DeepCopy()
{
return DeepCopy<SvgPatternServer>();
}
public override SvgElement DeepCopy<T>()
{
var newObj = base.DeepCopy<T>() as SvgPatternServer;
newObj.Overflow = this.Overflow;
newObj.ViewBox = this.ViewBox;
newObj.AspectRatio = this.AspectRatio;
newObj.X = this.X;
newObj.Y = this.Y;
newObj.Width = this.Width;
newObj.Height = this.Height;
return newObj;
}
public override SvgElement DeepCopy()
{
return DeepCopy<SvgPatternServer>();
}
public override SvgElement DeepCopy<T>()
{
var newObj = base.DeepCopy<T>() as SvgPatternServer;
newObj.Overflow = this.Overflow;
newObj.ViewBox = this.ViewBox;
newObj.AspectRatio = this.AspectRatio;
newObj.X = this.X;
newObj.Y = this.Y;
newObj.Width = this.Width;
newObj.Height = this.Height;
return newObj;
}
public SvgCoordinateUnits GetUnits()
{
......
......@@ -147,7 +147,7 @@ namespace Svg
{
var stop = Stops.Last();
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();
try
......
......@@ -104,14 +104,6 @@ namespace Svg
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>
/// Gets the bounds of the element.
/// </summary>
......
......@@ -522,10 +522,16 @@ namespace Svg
if (paths != null)
{
var curretCulture = CultureInfo.CurrentCulture;
Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
var s = string.Join(" ", paths.Select(p => p.ToString()).ToArray());
Thread.CurrentThread.CurrentCulture = curretCulture;
return s;
try {
Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
var s = string.Join(" ", paths.Select(p => p.ToString()).ToArray());
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 @@
<Compile Include="Paths\CoordinateParser.cs" />
<Compile Include="Rendering\IGraphicsProvider.cs" />
<Compile Include="Rendering\ISvgRenderer.cs" />
<Compile Include="Rendering\SvgRendering.cs" />
<Compile Include="SvgElementStyle.cs" />
<Compile Include="SvgNodeReader.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