Merge pull request #69 from mono/dev/evenodd

[SVG] Add support for `fill-rule="evenodd"`
This commit is contained in:
Matthew Leibowitz 2019-02-11 04:40:50 +02:00 коммит произвёл GitHub
Родитель 11fca118aa 87b2183b43
Коммит 517b656399
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
3 изменённых файлов: 72 добавлений и 24 удалений

Просмотреть файл

@ -274,7 +274,7 @@ namespace SkiaSharp.Extended.Svg
case "line":
if (stroke != null || fill != null)
{
var elementPath = ReadElement(e);
var elementPath = ReadElement(e, style);
if (elementPath == null)
break;
@ -408,7 +408,7 @@ namespace SkiaSharp.Extended.Svg
return new SKSvgImage(rect, uri, bytes);
}
private SKPath ReadElement(XElement e)
private SKPath ReadElement(XElement e, Dictionary<string, string> style = null)
{
var path = new SKPath();
@ -431,25 +431,25 @@ namespace SkiaSharp.Extended.Svg
path.AddCircle(circle.Center.X, circle.Center.Y, circle.Radius);
break;
case "path":
var d = e.Attribute("d")?.Value;
if (!string.IsNullOrWhiteSpace(d))
{
path.Dispose();
path = SKPath.ParseSvgPathData(d);
}
break;
case "polygon":
case "polyline":
var close = elementName == "polygon";
var p = e.Attribute("points")?.Value;
if (!string.IsNullOrWhiteSpace(p))
string data = null;
if (elementName == "path")
{
p = "M" + p;
if (close)
p += " Z";
path.Dispose();
path = SKPath.ParseSvgPathData(p);
data = e.Attribute("d")?.Value;
}
else
{
data = "M" + e.Attribute("points")?.Value;
if (elementName == "polygon")
data += " Z";
}
if (!string.IsNullOrWhiteSpace(data))
{
path.Dispose();
path = SKPath.ParseSvgPathData(data);
}
path.FillType = ReadFillRule(style);
break;
case "line":
var line = ReadLine(e);
@ -583,7 +583,7 @@ namespace SkiaSharp.Extended.Svg
{
var fontStyle = ReadStyle(e);
if (!fontStyle.TryGetValue("font-family", out string ffamily) || string.IsNullOrWhiteSpace(ffamily))
if (fontStyle == null || !fontStyle.TryGetValue("font-family", out string ffamily) || string.IsNullOrWhiteSpace(ffamily))
ffamily = paint.Typeface?.FamilyName;
var fweight = ReadFontWeight(fontStyle, paint.Typeface?.FontWeight ?? (int)SKFontStyleWeight.Normal);
var fwidth = ReadFontWidth(fontStyle, paint.Typeface?.FontWidth ?? (int)SKFontStyleWidth.Normal);
@ -591,15 +591,38 @@ namespace SkiaSharp.Extended.Svg
paint.Typeface = SKTypeface.FromFamilyName(ffamily, fweight, fwidth, fstyle);
if (fontStyle.TryGetValue("font-size", out string fsize) && !string.IsNullOrWhiteSpace(fsize))
if (fontStyle != null && fontStyle.TryGetValue("font-size", out string fsize) && !string.IsNullOrWhiteSpace(fsize))
paint.TextSize = ReadNumber(fsize);
}
private static SKPathFillType ReadFillRule(Dictionary<string, string> style, SKPathFillType defaultFillRule = SKPathFillType.Winding)
{
var fillRule = defaultFillRule;
if (style != null && style.TryGetValue("fill-rule", out string rule) && !string.IsNullOrWhiteSpace(rule))
{
switch (rule)
{
case "evenodd":
fillRule = SKPathFillType.EvenOdd;
break;
case "nonzero":
fillRule = SKPathFillType.Winding;
break;
default:
fillRule = defaultFillRule;
break;
}
}
return fillRule;
}
private static SKFontStyleSlant ReadFontStyle(Dictionary<string, string> fontStyle, SKFontStyleSlant defaultStyle = SKFontStyleSlant.Upright)
{
var style = defaultStyle;
if (fontStyle.TryGetValue("font-style", out string fstyle) && !string.IsNullOrWhiteSpace(fstyle))
if (fontStyle != null && fontStyle.TryGetValue("font-style", out string fstyle) && !string.IsNullOrWhiteSpace(fstyle))
{
switch (fstyle)
{
@ -624,7 +647,7 @@ namespace SkiaSharp.Extended.Svg
private int ReadFontWidth(Dictionary<string, string> fontStyle, int defaultWidth = (int)SKFontStyleWidth.Normal)
{
var width = defaultWidth;
if (fontStyle.TryGetValue("font-stretch", out string fwidth) && !string.IsNullOrWhiteSpace(fwidth) && !int.TryParse(fwidth, out width))
if (fontStyle != null && fontStyle.TryGetValue("font-stretch", out string fwidth) && !string.IsNullOrWhiteSpace(fwidth) && !int.TryParse(fwidth, out width))
{
switch (fwidth)
{
@ -674,7 +697,7 @@ namespace SkiaSharp.Extended.Svg
{
var weight = defaultWeight;
if (fontStyle.TryGetValue("font-weight", out string fweight) && !string.IsNullOrWhiteSpace(fweight) && !int.TryParse(fweight, out weight))
if (fontStyle != null && fontStyle.TryGetValue("font-weight", out string fweight) && !string.IsNullOrWhiteSpace(fweight) && !int.TryParse(fweight, out weight))
{
switch (fweight)
{
@ -709,7 +732,7 @@ namespace SkiaSharp.Extended.Svg
private string GetString(Dictionary<string, string> style, string name, string defaultValue = "")
{
if (style.TryGetValue(name, out string v))
if (style != null && style.TryGetValue(name, out string v))
return v;
return defaultValue;
}
@ -1342,7 +1365,7 @@ namespace SkiaSharp.Extended.Svg
private float ReadNumber(Dictionary<string, string> style, string key, float defaultValue)
{
float value = defaultValue;
if (style.TryGetValue(key, out string strValue))
if (style != null && style.TryGetValue(key, out string strValue))
{
value = ReadNumber(strValue);
}

Просмотреть файл

@ -413,6 +413,16 @@ namespace SkiaSharp.Extended.Svg.Tests
Assert.Equal(SKColors.White, bmp.GetPixel(11, 20));
}
[Fact]
public void FillRulesAreRespected()
{
var path = Path.Combine(PathToImages, "fill-rule.svg");
var bmp = LoadSvgBitmap(path, SKColors.Green);
Assert.Equal(SKColors.Black, bmp.GetPixel(60, 60));
Assert.Equal(SKColors.Green, bmp.GetPixel(160, 60));
}
private static SKBitmap LoadSvgBitmap(string svgPath, SKColor? background = null)
{
// open the SVG

Просмотреть файл

@ -0,0 +1,15 @@
<svg viewBox="-10 -10 220 120" xmlns="http://www.w3.org/2000/svg">
<!-- Default value for fill-rule -->
<polygon fill-rule="nonzero" stroke="red"
points="50,0 21,90 98,35 2,35 79,90"/>
<!--
The points in the center of the shape has 2
path segments (materialized by the red stroke)
between them and Infinity therefor there are
considered outside the shape, that's why the
interior of the star is hollow (but not the branch).
-->
<polygon fill-rule="evenodd" stroke="red"
points="150,0 121,90 198,35 102,35 179,90"/>
</svg>

После

Ширина:  |  Высота:  |  Размер: 548 B