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
...@@ -73,9 +73,10 @@ namespace Svg ...@@ -73,9 +73,10 @@ namespace Svg
if (this._owner.Parent != null) if (this._owner.Parent != null)
{ {
if (this._owner.Parent.Attributes[attributeName] != null) var parentAttribute = this._owner.Parent.Attributes[attributeName];
if (parentAttribute != null)
{ {
return (TAttributeType)this._owner.Parent.Attributes[attributeName]; return (TAttributeType)parentAttribute;
} }
} }
...@@ -91,8 +92,11 @@ namespace Svg ...@@ -91,8 +92,11 @@ namespace Svg
(value is SvgTextDecoration && (SvgTextDecoration)value == SvgTextDecoration.Inherit) || (value is SvgTextDecoration && (SvgTextDecoration)value == SvgTextDecoration.Inherit) ||
(value is XmlSpaceHandling && (XmlSpaceHandling)value == XmlSpaceHandling.inherit) || (value is XmlSpaceHandling && (XmlSpaceHandling)value == XmlSpaceHandling.inherit) ||
(value is SvgOverflow && (SvgOverflow)value == SvgOverflow.Inherit) || (value is SvgOverflow && (SvgOverflow)value == SvgOverflow.Inherit) ||
(value == SvgColourServer.Inherit) || (value is SvgColourServer && (SvgColourServer)value == SvgColourServer.Inherit) ||
(value is string && (string)value == "inherit") (value is SvgShapeRendering && (SvgShapeRendering)value == SvgShapeRendering.Inherit) ||
(value is SvgTextRendering && (SvgTextRendering)value == SvgTextRendering.Inherit) ||
(value is SvgImageRendering && (SvgImageRendering)value == SvgImageRendering.Inherit) ||
(value is string && ((string)value).ToLower() == "inherit")
); );
} }
......
...@@ -484,11 +484,10 @@ namespace Svg ...@@ -484,11 +484,10 @@ namespace Svg
renderer.SetBoundable(new GenericBoundable(0, 0, bitmap.Width, bitmap.Height)); renderer.SetBoundable(new GenericBoundable(0, 0, bitmap.Width, bitmap.Height));
//EO, 2014-12-05: Requested to ensure proper zooming (draw the svg in the bitmap size, ==> proper scaling) //EO, 2014-12-05: Requested to ensure proper zooming (draw the svg in the bitmap size, ==> proper scaling)
//EO, 2015-01-09, Added GetDimensions to use its returned size instead of this.Width and this.Height (request of Icarrere). //EO, 2015-01-09, Added GetDimensions to use its returned size instead of this.Width and this.Height (request of Icarrere).
//BBN, 2015-07-29, it is unnecassary to call again GetDimensions and transform to 1x1 //BBN, 2015-07-29, it is unnecassary to call again GetDimensions and transform to 1x1
//JA, 2015-12-18, this is actually necessary to correctly render the Draw(rasterHeight, rasterWidth) overload, otherwise the rendered graphic doesn't scale correctly //JA, 2015-12-18, this is actually necessary to correctly render the Draw(rasterHeight, rasterWidth) overload, otherwise the rendered graphic doesn't scale correctly
SizeF size = this.GetDimensions(); SizeF size = this.GetDimensions();
renderer.ScaleTransform(bitmap.Width / size.Width, bitmap.Height / size.Height); renderer.ScaleTransform(bitmap.Width / size.Width, bitmap.Height / size.Height);
//EO, 2014-12-05: Requested to ensure proper zooming out (reduce size). Otherwise it clip the image. //EO, 2014-12-05: Requested to ensure proper zooming out (reduce size). Otherwise it clip the image.
...@@ -564,12 +563,16 @@ namespace Svg ...@@ -564,12 +563,16 @@ namespace Svg
{ {
//Save previous culture and switch to invariant for writing //Save previous culture and switch to invariant for writing
var previousCulture = Thread.CurrentThread.CurrentCulture; var previousCulture = Thread.CurrentThread.CurrentCulture;
Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; try {
Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
base.Write(writer); base.Write(writer);
}
//Switch culture back finally
Thread.CurrentThread.CurrentCulture = previousCulture; {
// Make sure to set back the old culture even an error occurred.
//Switch culture back
Thread.CurrentThread.CurrentCulture = previousCulture;
}
} }
public void Write(Stream stream) public void Write(Stream stream)
......
...@@ -26,7 +26,7 @@ namespace Svg ...@@ -26,7 +26,7 @@ namespace Svg
set { this._dirty = value; } set { this._dirty = value; }
} }
private static float FixOpacityValue(float value) protected static float FixOpacityValue(float value)
{ {
const float max = 1.0f; const float max = 1.0f;
const float min = 0.0f; const float min = 0.0f;
...@@ -39,7 +39,7 @@ namespace Svg ...@@ -39,7 +39,7 @@ namespace Svg
[SvgAttribute("fill", true)] [SvgAttribute("fill", true)]
public virtual SvgPaintServer Fill public virtual SvgPaintServer Fill
{ {
get { return (this.Attributes["fill"] == null) ? SvgColourServer.NotSet : (SvgPaintServer)this.Attributes["fill"]; } get { return ((SvgPaintServer)this.Attributes["fill"] ?? SvgColourServer.NotSet); }
set { this.Attributes["fill"] = value; } set { this.Attributes["fill"] = value; }
} }
...@@ -49,14 +49,14 @@ namespace Svg ...@@ -49,14 +49,14 @@ namespace Svg
[SvgAttribute("stroke", true)] [SvgAttribute("stroke", true)]
public virtual SvgPaintServer Stroke public virtual SvgPaintServer Stroke
{ {
get { return (this.Attributes["stroke"] == null) ? null : (SvgPaintServer)this.Attributes["stroke"]; } get { return (SvgPaintServer)this.Attributes["stroke"]; }
set { this.Attributes["stroke"] = value; } set { this.Attributes["stroke"] = value; }
} }
[SvgAttribute("fill-rule", true)] [SvgAttribute("fill-rule", true)]
public virtual SvgFillRule FillRule public virtual SvgFillRule FillRule
{ {
get { return (this.Attributes["fill-rule"] == null) ? SvgFillRule.NonZero : (SvgFillRule)this.Attributes["fill-rule"]; } get { return (SvgFillRule)(this.Attributes["fill-rule"] ?? SvgFillRule.NonZero); }
set { this.Attributes["fill-rule"] = value; } set { this.Attributes["fill-rule"] = value; }
} }
...@@ -66,7 +66,7 @@ namespace Svg ...@@ -66,7 +66,7 @@ namespace Svg
[SvgAttribute("fill-opacity", true)] [SvgAttribute("fill-opacity", true)]
public virtual float FillOpacity public virtual float FillOpacity
{ {
get { return (this.Attributes["fill-opacity"] == null) ? this.Opacity : (float)this.Attributes["fill-opacity"]; } get { return (float)(this.Attributes["fill-opacity"] ?? this.Opacity); }
set { this.Attributes["fill-opacity"] = FixOpacityValue(value); } set { this.Attributes["fill-opacity"] = FixOpacityValue(value); }
} }
...@@ -76,28 +76,28 @@ namespace Svg ...@@ -76,28 +76,28 @@ namespace Svg
[SvgAttribute("stroke-width", true)] [SvgAttribute("stroke-width", true)]
public virtual SvgUnit StrokeWidth public virtual SvgUnit StrokeWidth
{ {
get { return (this.Attributes["stroke-width"] == null) ? new SvgUnit(1.0f) : (SvgUnit)this.Attributes["stroke-width"]; } get { return (SvgUnit)(this.Attributes["stroke-width"] ?? new SvgUnit(1.0f)); }
set { this.Attributes["stroke-width"] = value; } set { this.Attributes["stroke-width"] = value; }
} }
[SvgAttribute("stroke-linecap", true)] [SvgAttribute("stroke-linecap", true)]
public virtual SvgStrokeLineCap StrokeLineCap public virtual SvgStrokeLineCap StrokeLineCap
{ {
get { return (this.Attributes["stroke-linecap"] == null) ? SvgStrokeLineCap.Butt : (SvgStrokeLineCap)this.Attributes["stroke-linecap"]; } get { return (SvgStrokeLineCap)(this.Attributes["stroke-linecap"] ?? SvgStrokeLineCap.Butt); }
set { this.Attributes["stroke-linecap"] = value; } set { this.Attributes["stroke-linecap"] = value; }
} }
[SvgAttribute("stroke-linejoin", true)] [SvgAttribute("stroke-linejoin", true)]
public virtual SvgStrokeLineJoin StrokeLineJoin public virtual SvgStrokeLineJoin StrokeLineJoin
{ {
get { return (this.Attributes["stroke-linejoin"] == null) ? SvgStrokeLineJoin.Miter : (SvgStrokeLineJoin)this.Attributes["stroke-linejoin"]; } get { return (SvgStrokeLineJoin)(this.Attributes["stroke-linejoin"] ?? SvgStrokeLineJoin.Miter); }
set { this.Attributes["stroke-linejoin"] = value; } set { this.Attributes["stroke-linejoin"] = value; }
} }
[SvgAttribute("stroke-miterlimit", true)] [SvgAttribute("stroke-miterlimit", true)]
public virtual float StrokeMiterLimit public virtual float StrokeMiterLimit
{ {
get { return (this.Attributes["stroke-miterlimit"] == null) ? 4f : (float)this.Attributes["stroke-miterlimit"]; } get { return (float)(this.Attributes["stroke-miterlimit"] ?? 4f); }
set { this.Attributes["stroke-miterlimit"] = value; } set { this.Attributes["stroke-miterlimit"] = value; }
} }
...@@ -111,7 +111,7 @@ namespace Svg ...@@ -111,7 +111,7 @@ namespace Svg
[SvgAttribute("stroke-dashoffset", true)] [SvgAttribute("stroke-dashoffset", true)]
public virtual SvgUnit StrokeDashOffset public virtual SvgUnit StrokeDashOffset
{ {
get { return (this.Attributes["stroke-dashoffset"] == null) ? SvgUnit.Empty : (SvgUnit)this.Attributes["stroke-dashoffset"]; } get { return (SvgUnit)(this.Attributes["stroke-dashoffset"] ?? SvgUnit.Empty); }
set { this.Attributes["stroke-dashoffset"] = value; } set { this.Attributes["stroke-dashoffset"] = value; }
} }
...@@ -121,7 +121,7 @@ namespace Svg ...@@ -121,7 +121,7 @@ namespace Svg
[SvgAttribute("stroke-opacity", true)] [SvgAttribute("stroke-opacity", true)]
public virtual float StrokeOpacity public virtual float StrokeOpacity
{ {
get { return (this.Attributes["stroke-opacity"] == null) ? this.Opacity : (float)this.Attributes["stroke-opacity"]; } get { return (float)(this.Attributes["stroke-opacity"] ?? this.Opacity); }
set { this.Attributes["stroke-opacity"] = FixOpacityValue(value); } set { this.Attributes["stroke-opacity"] = FixOpacityValue(value); }
} }
...@@ -131,7 +131,7 @@ namespace Svg ...@@ -131,7 +131,7 @@ namespace Svg
/// <remarks>Apparently this can be set on non-sensical elements. Don't ask; just check the tests.</remarks> /// <remarks>Apparently this can be set on non-sensical elements. Don't ask; just check the tests.</remarks>
[SvgAttribute("stop-color", true)] [SvgAttribute("stop-color", true)]
[TypeConverter(typeof(SvgPaintServerFactory))] [TypeConverter(typeof(SvgPaintServerFactory))]
public SvgPaintServer StopColor public virtual SvgPaintServer StopColor
{ {
get { return this.Attributes["stop-color"] as SvgPaintServer; } get { return this.Attributes["stop-color"] as SvgPaintServer; }
set { this.Attributes["stop-color"] = value; } set { this.Attributes["stop-color"] = value; }
...@@ -143,10 +143,20 @@ namespace Svg ...@@ -143,10 +143,20 @@ namespace Svg
[SvgAttribute("opacity", true)] [SvgAttribute("opacity", true)]
public virtual float Opacity public virtual float Opacity
{ {
get { return (this.Attributes["opacity"] == null) ? 1.0f : (float)this.Attributes["opacity"]; } get { return (float)(this.Attributes["opacity"] ?? 1.0f); }
set { this.Attributes["opacity"] = FixOpacityValue(value); } set { this.Attributes["opacity"] = FixOpacityValue(value); }
} }
/// <summary>
/// Refers to the AnitAlias rendering of shapes.
/// </summary>
[SvgAttribute("shape-rendering")]
public virtual SvgShapeRendering ShapeRendering
{
get { return this.Attributes.GetInheritedAttribute<SvgShapeRendering>("shape-rendering"); }
set { this.Attributes["shape-rendering"] = value; }
}
/// <summary> /// <summary>
/// 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>
...@@ -163,7 +173,7 @@ namespace Svg ...@@ -163,7 +173,7 @@ namespace Svg
[SvgAttribute("font-size", true)] [SvgAttribute("font-size", true)]
public virtual SvgUnit FontSize public virtual SvgUnit FontSize
{ {
get { return (this.Attributes["font-size"] == null) ? SvgUnit.Empty : (SvgUnit)this.Attributes["font-size"]; } get { return (SvgUnit)(this.Attributes["font-size"] ?? SvgUnit.Empty); }
set { this.Attributes["font-size"] = value; this.IsPathDirty = true; } set { this.Attributes["font-size"] = value; this.IsPathDirty = true; }
} }
...@@ -173,7 +183,7 @@ namespace Svg ...@@ -173,7 +183,7 @@ namespace Svg
[SvgAttribute("font-style", true)] [SvgAttribute("font-style", true)]
public virtual SvgFontStyle FontStyle public virtual SvgFontStyle FontStyle
{ {
get { return (this.Attributes["font-style"] == null) ? SvgFontStyle.All : (SvgFontStyle)this.Attributes["font-style"]; } get { return (SvgFontStyle)(this.Attributes["font-style"] ?? SvgFontStyle.All); }
set { this.Attributes["font-style"] = value; this.IsPathDirty = true; } set { this.Attributes["font-style"] = value; this.IsPathDirty = true; }
} }
...@@ -183,7 +193,7 @@ namespace Svg ...@@ -183,7 +193,7 @@ namespace Svg
[SvgAttribute("font-variant", true)] [SvgAttribute("font-variant", true)]
public virtual SvgFontVariant FontVariant public virtual SvgFontVariant FontVariant
{ {
get { return (this.Attributes["font-variant"] == null) ? SvgFontVariant.Inherit : (SvgFontVariant)this.Attributes["font-variant"]; } get { return (SvgFontVariant)(this.Attributes["font-variant"] ?? SvgFontVariant.Inherit); }
set { this.Attributes["font-variant"] = value; this.IsPathDirty = true; } set { this.Attributes["font-variant"] = value; this.IsPathDirty = true; }
} }
...@@ -193,7 +203,7 @@ namespace Svg ...@@ -193,7 +203,7 @@ namespace Svg
[SvgAttribute("text-decoration", true)] [SvgAttribute("text-decoration", true)]
public virtual SvgTextDecoration TextDecoration public virtual SvgTextDecoration TextDecoration
{ {
get { return (this.Attributes["text-decoration"] == null) ? SvgTextDecoration.Inherit : (SvgTextDecoration)this.Attributes["text-decoration"]; } get { return (SvgTextDecoration)(this.Attributes["text-decoration"] ?? SvgTextDecoration.Inherit); }
set { this.Attributes["text-decoration"] = value; this.IsPathDirty = true; } set { this.Attributes["text-decoration"] = value; this.IsPathDirty = true; }
} }
...@@ -203,7 +213,7 @@ namespace Svg ...@@ -203,7 +213,7 @@ namespace Svg
[SvgAttribute("font-weight", true)] [SvgAttribute("font-weight", true)]
public virtual SvgFontWeight FontWeight public virtual SvgFontWeight FontWeight
{ {
get { return (this.Attributes["font-weight"] == null) ? SvgFontWeight.Inherit : (SvgFontWeight)this.Attributes["font-weight"]; } get { return (SvgFontWeight)(this.Attributes["font-weight"] ?? SvgFontWeight.Inherit); }
set { this.Attributes["font-weight"] = value; this.IsPathDirty = true; } set { this.Attributes["font-weight"] = value; this.IsPathDirty = true; }
} }
...@@ -223,7 +233,7 @@ namespace Svg ...@@ -223,7 +233,7 @@ namespace Svg
[SvgAttribute("font", true)] [SvgAttribute("font", true)]
public virtual string Font public virtual string Font
{ {
get { return (this.Attributes["font"] == null ? "" : this.Attributes["font"] as string); } get { return ((this.Attributes["font"] ?? string.Empty) as string); }
set set
{ {
var state = FontParseState.fontStyle; var state = FontParseState.fontStyle;
...@@ -297,9 +307,7 @@ namespace Svg ...@@ -297,9 +307,7 @@ namespace Svg
this.IsPathDirty = true; this.IsPathDirty = true;
} }
} }
private const string DefaultFontFamily = "Times New Roman";
/// <summary> /// <summary>
/// Get the font information based on data stored with the text object or inherited from the parent. /// Get the font information based on data stored with the text object or inherited from the parent.
/// </summary> /// </summary>
...@@ -379,11 +387,13 @@ namespace Svg ...@@ -379,11 +387,13 @@ namespace Svg
} }
} }
public static System.Drawing.Text.PrivateFontCollection PrivateFonts = new System.Drawing.Text.PrivateFontCollection();
public static object ValidateFontFamily(string fontFamilyList, SvgDocument doc) public static object ValidateFontFamily(string fontFamilyList, SvgDocument doc)
{ {
// 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 ?? string.Empty).Split(new[] { ',' }).Select(fontName => fontName.Trim(new[] { '"', ' ', '\'' }));
var families = System.Drawing.FontFamily.Families; var families = System.Drawing.FontFamily.Families;
Func<FontFamily, bool> getFamily;
FontFamily family; FontFamily family;
IEnumerable<SvgFontFace> sFaces; IEnumerable<SvgFontFace> sFaces;
...@@ -393,10 +403,13 @@ namespace Svg ...@@ -393,10 +403,13 @@ namespace Svg
{ {
if (doc.FontDefns().TryGetValue(f, out sFaces)) return sFaces; if (doc.FontDefns().TryGetValue(f, out sFaces)) return sFaces;
family = families.FirstOrDefault(ff => ff.Name.ToLower() == f.ToLower()); getFamily = new Func<FontFamily, bool>(ff => string.Equals(ff.Name, f, StringComparison.OrdinalIgnoreCase));
family = families.FirstOrDefault(getFamily);
if (family != null) return family;
family = PrivateFonts.Families.FirstOrDefault(getFamily);
if (family != null) return family; if (family != null) return family;
switch (f) switch (f.ToLower())
{ {
case "serif": case "serif":
return System.Drawing.FontFamily.GenericSerif; return System.Drawing.FontFamily.GenericSerif;
......
...@@ -22,7 +22,7 @@ namespace Svg ...@@ -22,7 +22,7 @@ namespace Svg
r.Width = bounds.Width; r.Width = bounds.Width;
r.Height = bounds.Height; r.Height = bounds.Height;
} }
public static RectangleF GetRectangle(this SvgRectangle r) public static RectangleF GetRectangle(this SvgRectangle r)
{ {
return new RectangleF(r.X, r.Y, r.Width, r.Height); return new RectangleF(r.X, r.Y, r.Width, r.Height);
...@@ -49,50 +49,57 @@ namespace Svg ...@@ -49,50 +49,57 @@ namespace Svg
var result = ""; var result = "";
var currentCulture = Thread.CurrentThread.CurrentCulture; var currentCulture = Thread.CurrentThread.CurrentCulture;
Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; try
using (StringWriter str = new StringWriter())
{ {
using (XmlTextWriter xml = new XmlTextWriter(str)) Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
using (StringWriter str = new StringWriter())
{ {
elem.Write(xml); using (XmlTextWriter xml = new XmlTextWriter(str))
result = str.ToString(); {
elem.Write(xml);
result = str.ToString();
}
} }
} }
Thread.CurrentThread.CurrentCulture = currentCulture; finally
{
// Make sure to set back the old culture even an error occurred.
Thread.CurrentThread.CurrentCulture = currentCulture;
}
return result; return result;
} }
public static bool HasNonEmptyCustomAttribute(this SvgElement element, string name) public static bool HasNonEmptyCustomAttribute(this SvgElement element, string name)
{ {
return element.CustomAttributes.ContainsKey(name) && !string.IsNullOrEmpty(element.CustomAttributes[name]); return element.CustomAttributes.ContainsKey(name) && !string.IsNullOrEmpty(element.CustomAttributes[name]);
} }
public static void ApplyRecursive(this SvgElement elem, Action<SvgElement> action) public static void ApplyRecursive(this SvgElement elem, Action<SvgElement> action)
{ {
action(elem); action(elem);
if(!(elem is SvgDocument)) //don't apply action to subtree of documents if (!(elem is SvgDocument)) //don't apply action to subtree of documents
{ {
foreach (var element in elem.Children) foreach (var element in elem.Children)
{ {
element.ApplyRecursive(action); element.ApplyRecursive(action);
} }
} }
} }
public static void ApplyRecursiveDepthFirst(this SvgElement elem, Action<SvgElement> action) public static void ApplyRecursiveDepthFirst(this SvgElement elem, Action<SvgElement> action)
{ {
if(!(elem is SvgDocument)) //don't apply action to subtree of documents if (!(elem is SvgDocument)) //don't apply action to subtree of documents
{ {
foreach (var element in elem.Children) foreach (var element in elem.Children)
{ {
element.ApplyRecursiveDepthFirst(action); element.ApplyRecursiveDepthFirst(action);
} }
} }
action(elem); action(elem);
} }
} }
} }
...@@ -133,6 +133,7 @@ namespace Svg.Text ...@@ -133,6 +133,7 @@ namespace Svg.Text
} }
} }
[CLSCompliant(false)]
public struct TT_OFFSET_TABLE public struct TT_OFFSET_TABLE
{ {
public ushort uMajorVersion; public ushort uMajorVersion;
...@@ -143,6 +144,7 @@ namespace Svg.Text ...@@ -143,6 +144,7 @@ namespace Svg.Text
public ushort uRangeShift; public ushort uRangeShift;
} }
[CLSCompliant(false)]
public struct TT_TABLE_DIRECTORY public struct TT_TABLE_DIRECTORY
{ {
public byte[] szTag; public byte[] szTag;
...@@ -155,6 +157,7 @@ namespace Svg.Text ...@@ -155,6 +157,7 @@ namespace Svg.Text
} }
} }
[CLSCompliant(false)]
public struct TT_NAME_TABLE_HEADER public struct TT_NAME_TABLE_HEADER
{ {
public ushort uFSelector; public ushort uFSelector;
...@@ -162,6 +165,7 @@ namespace Svg.Text ...@@ -162,6 +165,7 @@ namespace Svg.Text
public ushort uStorageOffset; public ushort uStorageOffset;
} }
[CLSCompliant(false)]
public struct TT_NAME_RECORD public struct TT_NAME_RECORD
{ {
public ushort uPlatformID; public ushort uPlatformID;
......
...@@ -62,7 +62,7 @@ namespace Svg ...@@ -62,7 +62,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; }
...@@ -72,7 +72,7 @@ namespace Svg ...@@ -72,7 +72,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; }
...@@ -82,7 +82,7 @@ namespace Svg ...@@ -82,7 +82,7 @@ namespace Svg
/// Refers to the style of the font. /// Refers to the style of the font.
/// </summary> /// </summary>
[SvgAttribute("font-style")] [SvgAttribute("font-style")]
public virtual SvgFontStyle FontStyle public override SvgFontStyle FontStyle
{ {
get { return (this.Attributes["font-style"] == null) ? SvgFontStyle.All : (SvgFontStyle)this.Attributes["font-style"]; } get { return (this.Attributes["font-style"] == null) ? SvgFontStyle.All : (SvgFontStyle)this.Attributes["font-style"]; }
set { this.Attributes["font-style"] = value; } set { this.Attributes["font-style"] = value; }
...@@ -92,7 +92,7 @@ namespace Svg ...@@ -92,7 +92,7 @@ namespace Svg
/// Refers to the varient of the font. /// Refers to the varient of the font.
/// </summary> /// </summary>
[SvgAttribute("font-variant")] [SvgAttribute("font-variant")]
public virtual SvgFontVariant FontVariant public override SvgFontVariant FontVariant
{ {
get { return (this.Attributes["font-variant"] == null) ? SvgFontVariant.Inherit : (SvgFontVariant)this.Attributes["font-variant"]; } get { return (this.Attributes["font-variant"] == null) ? SvgFontVariant.Inherit : (SvgFontVariant)this.Attributes["font-variant"]; }
set { this.Attributes["font-variant"] = value; } set { this.Attributes["font-variant"] = value; }
...@@ -102,7 +102,7 @@ namespace Svg ...@@ -102,7 +102,7 @@ namespace Svg
/// Refers to the boldness of the font. /// Refers to the boldness of the font.
/// </summary> /// </summary>
[SvgAttribute("font-weight")] [SvgAttribute("font-weight")]
public virtual SvgFontWeight FontWeight public override SvgFontWeight FontWeight
{ {
get { return (this.Attributes["font-weight"] == null) ? SvgFontWeight.Inherit : (SvgFontWeight)this.Attributes["font-weight"]; } get { return (this.Attributes["font-weight"] == null) ? SvgFontWeight.Inherit : (SvgFontWeight)this.Attributes["font-weight"]; }
set { this.Attributes["font-weight"] = value; } set { this.Attributes["font-weight"] = value; }
......
...@@ -79,15 +79,6 @@ namespace Svg ...@@ -79,15 +79,6 @@ namespace Svg
return _path; return _path;
} }
/// <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>
......
...@@ -13,10 +13,10 @@ namespace Svg ...@@ -13,10 +13,10 @@ namespace Svg
{ {
public abstract class SvgTextBase : SvgVisualElement public abstract class SvgTextBase : SvgVisualElement
{ {
protected SvgUnitCollection _x = new SvgUnitCollection(); [CLSCompliant(false)] protected SvgUnitCollection _x = new SvgUnitCollection();
protected SvgUnitCollection _y = new SvgUnitCollection(); [CLSCompliant(false)] protected SvgUnitCollection _y = new SvgUnitCollection();
protected SvgUnitCollection _dy = new SvgUnitCollection(); [CLSCompliant(false)] protected SvgUnitCollection _dy = new SvgUnitCollection();
protected SvgUnitCollection _dx = new SvgUnitCollection(); [CLSCompliant(false)] protected SvgUnitCollection _dx = new SvgUnitCollection();
private string _rotate; private string _rotate;
private List<float> _rotations = new List<float>(); private List<float> _rotations = new List<float>();
...@@ -215,15 +215,6 @@ namespace Svg ...@@ -215,15 +215,6 @@ namespace Svg
return this.Text; return this.Text;
} }
/// <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>
......
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Svg.DataTypes;
using System;
using System.Diagnostics;
using System.Drawing;
using System.IO;
namespace Svg.UnitTests
{
/// <summary>
/// Test Class of rendering SVGs with marker-end elements.
/// Based on Issue 212.
/// </summary>
/// <remarks>
/// Test use the following embedded resources:
/// - Issue212_MakerEnd\OperatingPlan.svg
/// </remarks>
[TestClass]
public class MarkerEndTest : SvgTestHelper
{
protected override string TestResource { get { return GetFullResourceString("Issue212_MakerEnd.OperatingPlan.svg"); } }
protected override int ExpectedSize { get { return 5000; } } //5321 //5410
[TestMethod]
public void TestOperatingPlanRendering()
{
LoadSvg(GetXMLDocFromResource());
}
[TestMethod]
public void TestArrowCodeCreation()
{
// Sample code from Issue 212. Thanks to podostro.
const int width = 50;
const int height = 50;
var document = new SvgDocument()
{
ID = "svgMap",
ViewBox = new SvgViewBox(0, 0, width, height)
};
var defsElement = new SvgDefinitionList() { ID = "defsMap" };
document.Children.Add(defsElement);
var groupElement = new SvgGroup() { ID = "gMap" };
document.Children.Add(groupElement);
var arrowPath = new SvgPath()
{
ID = "pathMarkerArrow",
Fill = new SvgColourServer(Color.Black),
PathData = SvgPathBuilder.Parse(@"M0,0 L4,2 L0,4 L1,2 z")
};
var arrowMarker = new SvgMarker()
{
ID = "markerArrow",
MarkerUnits = SvgMarkerUnits.StrokeWidth,
MarkerWidth = 5,
MarkerHeight = 5,
RefX = 3,
RefY = 2,
Orient = new SvgOrient() { IsAuto = true },
Children = { arrowPath }
};
defsElement.Children.Add(arrowMarker);
var line = new SvgLine()
{
ID = "lineLinkedPoint",
StartX = 0,
StartY = 15,
EndX = 35,
EndY = 35,
Stroke = new SvgColourServer(Color.Black),
StrokeWidth = 3,
MarkerEnd = new Uri(string.Format("url(#{0})", arrowMarker.ID), UriKind.Relative)
};
groupElement.Children.Add(line);
var svgXml = document.GetXML();
var img = document.Draw();
var file = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
File.WriteAllText(file + ".svg", svgXml);
img.Save(file + ".png");
Debug.WriteLine(string.Format("Svg saved to '{0}'", file));
Debugger.Break();
// Remove
var svg = new FileInfo(file + ".svg");
if (svg.Exists) svg.Delete();
var png = new FileInfo(file + ".png");
if (png.Exists) png.Delete();
}
}
}
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
namespace Svg.UnitTests
{
/// <summary>
/// Test Class of rendering SVGs as meterfile.
/// Based on Issue 210.
/// </summary>
/// <remarks>
/// Test use the following embedded resources:
/// - Issue210_Metafile\3DSceneSnapshotBIG.svg
/// </remarks>
[TestClass]
public class MetafileRenderingTest : SvgTestHelper
{
protected override string TestResource { get { return GetFullResourceString("Issue210_Metafile.3DSceneSnapshotBIG.svg"); } }
protected override int ExpectedSize { get { return 12500; } } //12896
[TestMethod]
[TestProperty(name: "speed", value: "slow")]
public void TestMetafileRendering()
{
LoadSvg(GetXMLDocFromResource());
}
protected override Image DrawSvg(SvgDocument svgDoc)
{
// GDI+
Metafile metafile;
using (var stream = new MemoryStream())
using (var img = new Bitmap((int)svgDoc.Width.Value, (int)svgDoc.Height.Value)) // Not necessary if you use Control.CreateGraphics().
using (Graphics ctrlGraphics = Graphics.FromImage(img)) // Control.CreateGraphics()
{
IntPtr handle = ctrlGraphics.GetHdc();
var rect = new RectangleF(0, 0, svgDoc.Width, svgDoc.Height);
metafile = new Metafile(stream,
handle,
rect,
MetafileFrameUnit.Pixel,
EmfType.EmfPlusOnly);
using (Graphics ig = Graphics.FromImage(metafile))
{
svgDoc.Draw(ig);
}
ctrlGraphics.ReleaseHdc(handle);
}
return metafile;
}
}
}
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Svg.Exceptions;
using System; using System;
using System.Diagnostics; using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Xml;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Svg.Exceptions;
namespace Svg.UnitTests namespace Svg.UnitTests
{ {
[TestClass()] [TestClass]
public class MultiThreadingTest public class MultiThreadingTest : SvgTestHelper
{ {
protected override string TestFile { get { return @"d:\temp\test.svg"; } }
protected override int ExpectedSize { get { return 600000; } }
private void LoadFile()
{
LoadSvg(GetXMLDocFromFile());
}
[TestMethod]
public void TestSingleThread()
{
LoadFile();
}
private const string TestFile = @"d:\temp\test.svg";
private const int ExpectedSize = 600000;
private XmlDocument GetXMLDoc()
{
var xmlDoc = new XmlDocument();
if(!System.IO.File.Exists(TestFile)) { Assert.Inconclusive("Test file missing"); }
xmlDoc.LoadXml(System.IO.File.ReadAllText(TestFile));
return xmlDoc;
}
[TestMethod] [TestMethod]
public void TestSingleThread() public void TestMultiThread()
{ {
LoadFile(); Parallel.For(0, 10, (x) =>
} {
LoadFile();
});
Trace.WriteLine("Done");
}
[TestMethod]
public void TestMultiThread()
{
bool valid = true;
Parallel.For(0, 10, (x) =>
{
LoadFile();
});
Trace.WriteLine("Done");
}
[TestMethod] [TestMethod]
[ExpectedException(typeof(SvgMemoryException))] [ExpectedException(typeof(SvgMemoryException))]
public void SVGGivesMemoryExceptionOnTooManyParallelTest() public void SVGGivesMemoryExceptionOnTooManyParallelTest()
{ {
try try
{ {
Parallel.For(0, 50, (x) => Parallel.For(0, 50, (x) =>
{ {
LoadFile(); LoadFile();
}); });
} }
catch (AggregateException ex) catch (AggregateException ex)
{ {
throw ex.InnerException; throw ex.InnerException;
} }
} }
private void LoadFile() }
{ }
var xml = GetXMLDoc();
Trace.WriteLine("Reading and drawing file");
SvgDocument d = SvgDocument.Open(xml);
var b = d.Draw();
Trace.WriteLine("Done reading file");
using (var ms = new MemoryStream())
{
b.Save(ms, ImageFormat.Png);
ms.Flush();
Assert.IsTrue(ms.Length >= ExpectedSize, "File does not match expected minimum size");
}
}
}
}
\ No newline at end of file
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Drawing.Text;
using System.Runtime.InteropServices;
namespace Svg.UnitTests
{
/// <summary>
/// Test Class of the feature to use Private Fonts in SVGs.
/// Based on Issue 204.
/// </summary>
/// <remarks>
/// Test use the following embedded resources:
/// - Issue204_PrivateFont\Text.svg
/// - Issue204_PrivateFont\BrushScriptMT2.ttf
/// </remarks>
[TestClass]
public class PrivateFontsTests : SvgTestHelper
{
private const string PrivateFontSvg = "Issue204_PrivateFont.Text.svg";
private const string PrivateFont = "Issue204_PrivateFont.BrushScriptMT2.ttf";
//private const string PrivateFontName = "Brush Script MT2";
protected override int ExpectedSize { get { return 3200; } } //3512
[TestMethod]
public void TestPrivateFont()
{
AddFontFromResource(SvgElement.PrivateFonts, GetFullResourceString(PrivateFont));
LoadSvg(GetXMLDocFromResource(GetFullResourceString(PrivateFontSvg)));
}
private void AddFontFromResource(PrivateFontCollection privateFontCollection, string fullFontResourceString)
{
var fontBytes = GetResourceBytes(fullFontResourceString);
var fontData = Marshal.AllocCoTaskMem(fontBytes.Length);
Marshal.Copy(fontBytes, 0, fontData, fontBytes.Length);
privateFontCollection.AddMemoryFont(fontData, fontBytes.Length); // Add font to collection.
Marshal.FreeCoTaskMem(fontData); // Do not forget to frees the memory block.
}
}
}
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" version="1.1">
<defs>
<symbol id="Lines" overflow="visible">
<text x="100" y="60" style="font-family: Brush Script MT2; font-size: 50px">
<tspan x="100" y="160">Line01</tspan>
<tspan x="100" y="220">Line02</tspan>
</text>
</symbol>
</defs>
<use xlink:href="#Lines"/>
</svg>
\ No newline at end of file
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg x="0" y="0" width="100%" height="100%" overflow="inherit" viewBox="0, 0, 265, 265" preserveAspectRatio="xMidYMid" font-size="0" id="svgmap" xml:space="default" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xml="http://www.w3.org/XML/1998/namespace" version="1.1">
<defs id="defsmap" xml:space="default">
<marker refX="3" refY="2" orient="auto" overflow="hidden" markerWidth="5" markerHeight="5" id="markerArrowLightBlue" xml:space="default">
<path d="M0 0 L4 2 L0 4 L1 2 z" id="pathMarkerArrowLightBlue" xml:space="default" style="fill:#ADD8E6;" />
</marker>
<marker refX="3" refY="2" orient="auto" overflow="hidden" markerWidth="5" markerHeight="5" id="markerArrowLightCoral" xml:space="default">
<path d="M0 0 L4 2 L0 4 L1 2 z" id="pathMarkerArrowLightCoral" xml:space="default" style="fill:#F08080;" />
</marker>
</defs>
<g id="gmap" xml:space="default">
<rect x="80" y="10" width="35" height="35" rx="7" ry="7" stroke="#ADD8E6" id="rectRoomX1Y0" xml:space="default" style="fill:#ADD8E6;" />
<line x1="78" y1="47" x2="49" y2="76" marker-end="url(#markerArrowLightBlue)" stroke="#ADD8E6" stroke-width="3" id="lineLinkedRoomX0Y1" xml:space="default" />
<rect x="150" y="10" width="35" height="35" rx="7" ry="7" stroke="#20B2AA" id="rectRoomX2Y0" xml:space="default" style="fill:#20B2AA;" />
<line x1="167.5" y1="47" x2="167.5" y2="76" marker-end="url(#markerArrowLightBlue)" stroke="#ADD8E6" stroke-width="3" id="lineLinkedRoomX2Y1" xml:space="default" />
<rect x="10" y="80" width="35" height="35" rx="7" ry="7" stroke="#ADD8E6" id="rectRoomX0Y1" xml:space="default" style="fill:#ADD8E6;" />
<line x1="47" y1="117" x2="76" y2="146" marker-end="url(#markerArrowLightBlue)" stroke="#ADD8E6" stroke-width="3" id="lineLinkedRoomX1Y2" xml:space="default" />
<rect x="80" y="80" width="35" height="35" rx="7" ry="7" stroke="#ADD8E6" id="rectRoomX1Y1" xml:space="default" style="fill:#ADD8E6;" />
<line x1="97.5" y1="78" x2="97.5" y2="49" marker-end="url(#markerArrowLightBlue)" stroke="#ADD8E6" stroke-width="3" id="lineLinkedRoomX1Y0" xml:space="default" />
<rect x="150" y="80" width="35" height="35" rx="7" ry="7" stroke="#ADD8E6" id="rectRoomX2Y1" xml:space="default" style="fill:#ADD8E6;" />
<line x1="148" y1="97.5" x2="119" y2="97.5" marker-end="url(#markerArrowLightBlue)" stroke="#ADD8E6" stroke-width="3" id="lineLinkedRoomX1Y1" xml:space="default" />
<rect x="220" y="80" width="35" height="35" rx="7" ry="7" stroke="#ADD8E6" id="rectRoomX3Y1" xml:space="default" style="fill:#ADD8E6;" />
<line x1="237.5" y1="117" x2="237.5" y2="146" marker-end="url(#markerArrowLightCoral)" stroke="#F08080" stroke-width="3" id="lineLinkedRoomX3Y2" xml:space="default" />
<rect x="10" y="150" width="35" height="35" rx="7" ry="7" stroke="#ADD8E6" id="rectRoomX0Y2" xml:space="default" style="fill:#ADD8E6;" />
<line x1="47" y1="187" x2="76" y2="216" marker-end="url(#markerArrowLightBlue)" stroke="#ADD8E6" stroke-width="3" id="lineLinkedRoomX1Y3" xml:space="default" />
<rect x="80" y="150" width="35" height="35" rx="7" ry="7" stroke="#ADD8E6" id="rectRoomX1Y2" xml:space="default" style="fill:#ADD8E6;" />
<line x1="78" y1="167.5" x2="49" y2="167.5" marker-end="url(#markerArrowLightBlue)" stroke="#ADD8E6" stroke-width="3" id="lineLinkedRoomX0Y2" xml:space="default" />
<rect x="150" y="150" width="35" height="35" rx="7" ry="7" stroke="#ADD8E6" id="rectRoomX2Y2" xml:space="default" style="fill:#ADD8E6;" />
<line x1="187" y1="148" x2="216" y2="119" marker-end="url(#markerArrowLightBlue)" stroke="#ADD8E6" stroke-width="3" id="lineLinkedRoomX3Y1" xml:space="default" />
<rect x="220" y="150" width="35" height="35" rx="7" ry="7" stroke="#F08080" id="rectRoomX3Y2" xml:space="default" style="fill:#F08080;" />
<rect x="80" y="220" width="35" height="35" rx="7" ry="7" stroke="#ADD8E6" id="rectRoomX1Y3" xml:space="default" style="fill:#ADD8E6;" />
<line x1="117" y1="218" x2="146" y2="189" marker-end="url(#markerArrowLightBlue)" stroke="#ADD8E6" stroke-width="3" id="lineLinkedRoomX2Y2" xml:space="default" />
</g>
</svg>
\ No newline at end of file
...@@ -55,8 +55,12 @@ ...@@ -55,8 +55,12 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="CssQueryTest.cs" /> <Compile Include="CssQueryTest.cs" />
<Compile Include="MarkerEndTest.cs" />
<Compile Include="MetafileRenderingTest.cs" />
<Compile Include="MultiThreadingTest.cs" /> <Compile Include="MultiThreadingTest.cs" />
<Compile Include="PrivateFontsTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SvgTestHelper.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\Source\Svg.csproj"> <ProjectReference Include="..\..\Source\Svg.csproj">
...@@ -65,8 +69,18 @@ ...@@ -65,8 +69,18 @@
</ProjectReference> </ProjectReference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<EmbeddedResource Include="Resources\Issue204_PrivateFont\BrushScriptMT2.ttf" />
<None Include="svgkey.snk" /> <None Include="svgkey.snk" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Resources\Issue204_PrivateFont\Text.svg" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Resources\Issue210_Metafile\3DSceneSnapshotBIG.svg" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Resources\Issue212_MakerEnd\OperatingPlan.svg" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets. Other similar extension points exist, see Microsoft.Common.targets.
......
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Xml;
namespace Svg.UnitTests
{
public abstract class SvgTestHelper
{
/// <summary>
/// Test file path.
/// </summary>
protected virtual string TestFile
{
get
{
const string msg = "Test file not overridden.";
Assert.Inconclusive(msg);
throw new NotImplementedException(msg);
}
}
/// <summary>
/// Full Unit Test resource string for test file.
/// </summary>
/// <remarks>
/// For the full Unit Test resource string you can use <see cref="GetFullResourceString(string)"/>.
/// </remarks>
protected virtual string TestResource
{
get
{
const string msg = "Test resource not overridden.";
Assert.Inconclusive(msg);
throw new NotImplementedException(msg);
}
}
/// <summary>
/// Expected size of svg file after drawing.
/// </summary>
protected virtual int ExpectedSize
{
get
{
const string msg = "Expected size not overridden.";
Assert.Inconclusive(msg);
throw new NotImplementedException(msg);
}
}
/// <summary>
/// Get full Unit Test resource string.
/// </summary>
/// <param name="resourcePath">Resource path.</param>
/// <returns>Full resource string.</returns>
/// <example>
/// var s = GetFullResourceString("Issue204_PrivateFont.Text.svg");
/// // s content: "Svg.UnitTests.Resources.Issue204_PrivateFont.Text.svg"
/// </example>
protected virtual string GetFullResourceString(string resourcePath)
{
const string DefaultResourcesDir = "Resources";
return string.Format("{0}.{1}.{2}",
this.GetType().Assembly.GetName().Name,
DefaultResourcesDir,
resourcePath);
}
/// <summary>
/// Get embedded resource as stream from Unit Test resources.
/// </summary>
/// <param name="fullResourceString">Full Unit Test resource string.</param>
/// <returns>Embedded resource data steam.</returns>
/// <remarks>Do not forget to close, dispose the stream.</remarks>
protected virtual Stream GetResourceStream(string fullResourceString)
{
Trace.WriteLine("Get resource data.");
var s = this.GetType().Assembly.GetManifestResourceStream(fullResourceString);
if (s == null)
Assert.Fail("Unable to find embedded resource", fullResourceString);
Trace.WriteLine("Done getting resource data.");
return s;
}
/// <summary>
/// Get embedded resource as byte array from Unit Test resources.
/// </summary>
/// <param name="fullResourceString">Full Unit Test resource string.</param>
/// <returns>Embedded resource data bytes.</returns>
protected virtual byte[] GetResourceBytes(string fullResourceString)
{
using (var s = GetResourceStream(fullResourceString))
{
var resource = new byte[s.Length];
s.Read(resource, 0, (int)s.Length);
return resource;
}
}
/// <summary>
/// Get embedded resource as xml document from Unit Test resources.
/// </summary>
/// <param name="fullResourceString">Full Unit Test resource string.</param>
/// <returns>Embedded resource data xml document.</returns>
protected virtual XmlDocument GetResourceXmlDoc(string fullResourceString)
{
using (var s = GetResourceStream(fullResourceString))
{
Trace.WriteLine("Load XmlDocument from resource data.");
var xmlDoc = new XmlDocument();
xmlDoc.Load(s);
Trace.WriteLine("Done XmlDocument loading from resource data.");
return xmlDoc;
}
}
/// <summary>
/// Get xml document from <see cref="TestFile"/>.
/// </summary>
/// <returns>File data as xml document.</returns>
protected virtual XmlDocument GetXMLDocFromFile()
{
return GetXMLDocFromFile(TestFile);
}
/// <summary>
/// Get xml document from file.
/// </summary>
/// <param name="file">File to load.</param>
/// <returns>File data as xml document.</returns>
protected virtual XmlDocument GetXMLDocFromFile(string file)
{
if (!File.Exists(file))
Assert.Fail("Test file missing.", file);
var xmlDoc = new XmlDocument();
xmlDoc.LoadXml(File.ReadAllText(file));
return xmlDoc;
}
/// <summary>
/// Get xml document from <see cref="TestResource"/>.
/// </summary>
/// <returns>Resource data as xml document.</returns>
protected virtual XmlDocument GetXMLDocFromResource()
{
return GetResourceXmlDoc(TestResource);
}
/// <summary>
/// Get xml document from resource.
/// </summary>
/// <param name="fullResourceString">Full Unit Test resource string.</param>
/// <returns>Resource data as xml document.</returns>
protected virtual XmlDocument GetXMLDocFromResource(string fullResourceString)
{
return GetResourceXmlDoc(fullResourceString);
}
/// <summary>
/// Load, draw and check svg file.
/// </summary>
/// <param name="xml">Svg file data.</param>
protected virtual void LoadSvg(XmlDocument xml)
{
Trace.WriteLine("SvgDocument open xml.");
var svgDoc = OpenSvg(xml);
Trace.WriteLine("Done SvgDocument open xml.");
Trace.WriteLine("Draw svg.");
var img = DrawSvg(svgDoc);
Trace.WriteLine("Done drawing.");
CheckSvg(svgDoc, img);
}
/// <summary>
/// Open SVG document from XML document.
/// </summary>
/// <param name="xml">XML document.</param>
/// <returns>Open SVG document.</returns>
protected virtual SvgDocument OpenSvg(XmlDocument xml)
{
return SvgDocument.Open(xml);
}
/// <summary>
/// Draw SVG.
/// </summary>
/// <param name="svgDoc">SVG document to draw.</param>
/// <returns>SVG as image.</returns>
protected virtual Image DrawSvg(SvgDocument svgDoc)
{
return svgDoc.Draw();
}
/// <summary>
/// Check svg file data.
/// </summary>
/// <param name="svgDoc">Svg document.</param>
/// <param name="img">Image of svg file from <paramref name="svgDoc"/>.</param>
protected virtual void CheckSvg(SvgDocument svgDoc, Image img)
{
using (var ms = new MemoryStream())
{
img.Save(ms, ImageFormat.Png);
ms.Flush();
Assert.IsTrue(ms.Length >= ExpectedSize, "Svg file does not match expected minimum size.");
}
}
/// <summary>
/// Compare Images.
/// </summary>
/// <param name="img1">Image 1.</param>
/// <param name="img2">Image 2.</param>
/// <returns>If images are completely equal: true; otherwise: false</returns>
protected virtual bool ImagesAreEqual(Bitmap img1, Bitmap img2)
{
float imgEqualPercentage; // To ignore.
return ImagesAreEqual(img1, img2, out imgEqualPercentage);
}
/// <summary>
/// Compare Images.
/// </summary>
/// <param name="img1">Image 1.</param>
/// <param name="img2">Image 2.</param>
/// <param name="imgEqualPercentage">Image equal value in percentage. 0.0% == completely unequal. 100.0% == completely equal.</param>
/// <returns>If images are completely equal: true; otherwise: false</returns>
protected virtual bool ImagesAreEqual(Bitmap img1, Bitmap img2, out float imgEqualPercentage)
{
Bitmap imgDiff; // To ignore.
return ImagesAreEqual(img1, img2, out imgEqualPercentage, out imgDiff);
}
/// <summary>
/// Compare Images.
/// </summary>
/// <param name="img1">Image 1.</param>
/// <param name="img2">Image 2.</param>
/// <param name="imgEqualPercentage">Image equal value in percentage. 0.0% == completely unequal. 100.0% == completely equal.</param>
/// <param name="imgDiff">Image with red pixel where <paramref name="img1"/> and <paramref name="img2"/> are unequal.</param>
/// <returns>If images are completely equal: true; otherwise: false</returns>
protected virtual bool ImagesAreEqual(Bitmap img1, Bitmap img2, out float imgEqualPercentage, out Bitmap imgDiff)
{
// Defaults.
var diffColor = Color.Red;
// Reset.
imgEqualPercentage = 0;
imgDiff = null;
// Requirements.
if (img1 == null)
return false;
if (img2 == null)
return false;
if (img1.Size.Width < 1 && img1.Height < 1)
return false;
if (!img1.Size.Equals(img2.Size))
return false;
// Compare bitmaps.
imgDiff = new Bitmap(img1.Size.Width, img1.Size.Height);
int diffPixelCount = 0;
for (int i = 0; i < img1.Width; ++i)
{
for (int j = 0; j < img1.Height; ++j)
{
Color color;
if ((color = img1.GetPixel(i, j)) == img2.GetPixel(i, j))
{
imgDiff.SetPixel(i, j, color);
}
else
{
++diffPixelCount;
imgDiff.SetPixel(i, j, diffColor);
}
}
}
// Calculate percentage.
int totalPixelCount = img1.Width * img1.Height;
var imgDiffFactor = ((float)diffPixelCount / totalPixelCount);
imgEqualPercentage = imgDiffFactor * 100;
return (imgDiffFactor == 1f);
}
}
}
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