Skip to content

Commit 92a5338

Browse files
committed
Got colored text working
1 parent 597b895 commit 92a5338

File tree

10 files changed

+163
-64
lines changed

10 files changed

+163
-64
lines changed

Samples/Example/Example.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
<Resource Include="Images\brush.svg" />
4848
<Resource Include="Images\error.svg" />
4949
<Resource Include="Images\example radgrad01.svg" />
50+
<Resource Include="Images\boldgreen.svg" />
5051
<Resource Include="Images\rect.svg" />
5152
<Resource Include="Images\test_3.svg" />
5253
<Resource Include="Images\tombigel_green_router.svg" />
Lines changed: 13 additions & 0 deletions
Loading

Source/SVGImage/SVG/PaintServers/PaintServerManager.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -224,10 +224,12 @@ private int ParseColorNumber(string value)
224224
{
225225
if (value.EndsWith("%"))
226226
{
227-
var nr = int.Parse(value.Substring(0, value.Length - 1)); //TODO: should this be double?
227+
var nr = double.Parse(value.Substring(0, value.Length - 1));
228228
if (nr < 0)
229-
nr = 255 - nr;
230-
return nr * 255 / 100;
229+
nr = 255 - nr; //TODO: what is this trying to do?
230+
var result = (int)Math.Round((nr * 255) / 100);
231+
232+
return MathUtil.Clamp(result, 0, 255);
231233
}
232234

233235
return int.Parse(value);

Source/SVGImage/SVG/SVGRender.cs

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,8 @@ public DrawingGroup LoadDrawing(Stream stream)
116116

117117
public DrawingGroup CreateDrawing(SVG svg)
118118
{
119-
return this.LoadGroup(svg.Elements, svg.ViewBox, false);
119+
var drawingGroup = this.LoadGroup(svg.Elements, svg.ViewBox, false);
120+
return drawingGroup;
120121
}
121122

122123
public DrawingGroup CreateDrawing(Shape shape)
@@ -444,9 +445,9 @@ internal DrawingGroup LoadGroup(IList<Shape> elements, Rect? viewBox, bool isSwi
444445
GeometryGroup gp = textRender2.BuildTextGeometry(textShape);
445446
if (gp != null)
446447
{
447-
foreach (Geometry gm in gp.Children)
448+
foreach (Geometry gm in GetStyledSpans(gp))
448449
{
449-
if (TextRenderBase.GetElement(gm) is TextShapeBase tspan)
450+
if (TextRender.GetElement(gm) is TextShapeBase tspan)
450451
{
451452
var di = this.NewDrawingItem(tspan, gm);
452453
AddDrawingToGroup(grp, shape, di);
@@ -481,6 +482,31 @@ internal DrawingGroup LoadGroup(IList<Shape> elements, Rect? viewBox, bool isSwi
481482
return grp;
482483
}
483484

485+
private static IEnumerable<Geometry> GetStyledSpans(Geometry geometry)
486+
{
487+
if (geometry is GeometryGroup gg)
488+
{
489+
if (!(TextRender.GetElement(gg) is null))
490+
{
491+
yield return geometry;
492+
}
493+
else
494+
{
495+
foreach (var g in gg.Children)
496+
{
497+
foreach (var subg in GetStyledSpans(g))
498+
{
499+
yield return subg;
500+
}
501+
}
502+
}
503+
}
504+
else
505+
{
506+
yield return geometry;
507+
}
508+
}
509+
484510
private void AddDrawingToGroup(DrawingGroup grp, Shape shape, Drawing drawing)
485511
{
486512
if (shape.Clip != null || shape.Transform != null || shape.Filter != null)

Source/SVGImage/SVG/Shapes/TextRender.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,27 @@ public override GeometryGroup BuildTextGeometry(TextShape text)
2929
}
3030
}
3131

32+
33+
34+
public static readonly DependencyProperty TextSpanTextStyleProperty = DependencyProperty.RegisterAttached(
35+
"TextSpanTextStyle", typeof(TextStyle), typeof(DependencyObject));
36+
private static void SetTextSpanTextStyle(DependencyObject obj, TextStyle value)
37+
{
38+
obj.SetValue(TextSpanTextStyleProperty, value);
39+
}
40+
public static TextStyle GetTextSpanTextStyle(DependencyObject obj)
41+
{
42+
return (TextStyle)obj.GetValue(TextSpanTextStyleProperty);
43+
}
44+
3245
private sealed class TextChunk
3346
{
3447
public List<GlyphRun> GlyphRuns { get; set; } = new List<GlyphRun>();
3548
public Dictionary<GlyphRun, List<Rect>> BackgroundDecorations { get; set; } = new Dictionary<GlyphRun, List<Rect>>();
3649
public Dictionary<GlyphRun, List<Rect>> ForegroundDecorations { get; set; } = new Dictionary<GlyphRun, List<Rect>>();
3750
public Dictionary<GlyphRun, Rect> GlyphRunBounds { get; set; } = new Dictionary<GlyphRun, Rect>();
51+
public Dictionary<GlyphRun, TextStyle> TextStyles { get; set; } = new Dictionary<GlyphRun, TextStyle>();
52+
public Dictionary<GlyphRun, TextShapeBase> TextContainers { get; set; } = new Dictionary<GlyphRun, TextShapeBase>();
3853
public TextAlignment TextAlignment { get; set; }
3954

4055
public GeometryGroup BuildGeometry()
@@ -46,6 +61,14 @@ public GeometryGroup BuildGeometry()
4661
{
4762
var runGeometry = !nonZeroAlignmentOffset ? glyphRun.BuildGeometry() : glyphRun.CreateOffsetRun(alignmentOffset, 0).BuildGeometry();
4863
geometryGroup.Children.Add(runGeometry);
64+
if (TextStyles.TryGetValue(glyphRun, out TextStyle textStyle))
65+
{
66+
TextRender.SetTextSpanTextStyle(runGeometry, textStyle);
67+
}
68+
if (TextContainers.TryGetValue(glyphRun, out TextShapeBase textContainer))
69+
{
70+
TextRender.SetElement(runGeometry, textContainer);
71+
}
4972
if (BackgroundDecorations.TryGetValue(glyphRun, out List<Rect> backgroundDecorations))
5073
{
5174
foreach (var decoration in backgroundDecorations)
@@ -148,7 +171,9 @@ private static GeometryGroup CreateGeometry(TextShape root, TextRenderState stat
148171
}
149172
var runGeometry = run.BuildGeometry();
150173
currentTextChunk.GlyphRuns.Add(run);
174+
currentTextChunk.TextStyles[run] = textStyle;
151175
currentTextChunk.GlyphRunBounds[run] = runGeometry.Bounds;
176+
currentTextChunk.TextContainers[run] = (TextShapeBase)textString.Parent;
152177
if (textStyle.TextDecoration != null && textStyle.TextDecoration.Count > 0)
153178
{
154179
GetTextDecorations(runGeometry, textStyle, font, baselineOrigin, out List<Rect> backgroundDecorations, out List<Rect> foregroundDecorations);

Source/SVGImage/SVG/Shapes/TextRenderBase.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@ public abstract class TextRenderBase
77
{
88
public abstract GeometryGroup BuildTextGeometry(TextShape text);
99
public static DependencyProperty TSpanElementProperty = DependencyProperty.RegisterAttached(
10-
"TSpanElement", typeof(ITextNode), typeof(DependencyObject));
11-
public static void SetElement(DependencyObject obj, ITextNode value)
10+
"TSpanElement", typeof(TextShapeBase), typeof(DependencyObject));
11+
public static void SetElement(DependencyObject obj, TextShapeBase value)
1212
{
1313
obj.SetValue(TSpanElementProperty, value);
1414
}
15-
public static ITextNode GetElement(DependencyObject obj)
15+
public static TextShapeBase GetElement(DependencyObject obj)
1616
{
17-
return (ITextNode)obj.GetValue(TSpanElementProperty);
17+
return (TextShapeBase)obj.GetValue(TSpanElementProperty);
1818
}
1919
}
2020

Source/SVGImage/SVG/Shapes/TextShapeBase.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,15 @@ private string GetDebugDisplayText(StringBuilder sb)
4040
return sb.ToString();
4141
}
4242

43-
43+
44+
protected override Fill DefaultFill()
45+
{
46+
return Fill.CreateDefault(Svg, "black");
47+
}
48+
protected override Stroke DefaultStroke()
49+
{
50+
return Stroke.CreateDefault(Svg, 0.1);
51+
}
4452

4553
public LengthPercentageOrNumberList X { get; protected set; }
4654
public LengthPercentageOrNumberList Y { get; protected set; }

Source/SVGImage/SVG/TextRender2.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ static void BuildTextSpan(GeometryGroup gp, TextStyle textStyle,
5151
baseline -= tspan.TextStyle.FontSize + (textString.TextStyle.FontSize * 0.25)/*font.CapsHeight * fontSize*/;
5252

5353
Geometry gm = BuildGlyphRun(textString.TextStyle, txt, x, baseline, ref totalwidth);
54-
TextRender2.SetElement(gm, textString);
54+
TextRender2.SetElement(gm, (TextShapeBase)textString.Parent);
5555
gp.Children.Add(gm);
5656
x += totalwidth;
5757
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
using SVGImage.SVG.Shapes;
2+
using System;
3+
4+
namespace SVGImage.SVG.Utils
5+
{
6+
internal static class BaselineHelper
7+
{
8+
public static LengthPercentageOrNumber EstimateBaselineShift(Shape shape)
9+
{
10+
return EstimateBaselineShift(shape.TextStyle, shape);
11+
}
12+
/// <summary>
13+
/// The purpose of this method is to allow TextStrings which are not shapes themselves to use the same logic as TextShapes to estimate the baseline shift.
14+
/// They can use this method to estimate the baseline shift based on the TextStyle of the TextString's parent Shape.
15+
/// </summary>
16+
/// <param name="textStyle"></param>
17+
/// <param name="shape"></param>
18+
/// <returns></returns>
19+
public static LengthPercentageOrNumber EstimateBaselineShift(TextStyle textStyle, Shape shape)
20+
{
21+
if (String.IsNullOrEmpty( textStyle.BaseLineShift) || textStyle.BaseLineShift == "baseline")
22+
{
23+
return new LengthPercentageOrNumber(0d, new LengthContext(shape, LengthUnit.Number));
24+
}
25+
else if (textStyle.BaseLineShift == "sub")
26+
{
27+
//Based on previous estimation
28+
return new LengthPercentageOrNumber( textStyle.FontSize * 0.5, new LengthContext(shape, LengthUnit.Number));
29+
}
30+
else if (textStyle.BaseLineShift == "super")
31+
{
32+
//Based on previous estimation
33+
return new LengthPercentageOrNumber((-1) * (textStyle.FontSize + (textStyle.FontSize * 0.25)), new LengthContext(shape, LengthUnit.Number));
34+
}
35+
else if(textStyle.BaseLineShift.EndsWith("%") && Double.TryParse(textStyle.BaseLineShift.Substring(0, textStyle.BaseLineShift.Length - 1), out double d))
36+
{
37+
try
38+
{
39+
//The computed value of the property is this percentage multiplied by the computed "line-height" of the ‘text’ element.
40+
//for the purposes of processing the ‘font’ property in SVG, 'line-height' is assumed to be equal the value for property ‘font-size’
41+
return new LengthPercentageOrNumber(d, new LengthContext(shape, LengthUnit.rem));
42+
}
43+
catch
44+
{
45+
//Continue
46+
}
47+
}
48+
try
49+
{
50+
return LengthPercentageOrNumber.Parse(shape, textStyle.BaseLineShift, LengthOrientation.Vertical);
51+
}
52+
catch
53+
{
54+
return new LengthPercentageOrNumber(0d, new LengthContext(shape, LengthUnit.Number));
55+
}
56+
}
57+
public static double EstimateBaselineShiftValue(Shape shape)
58+
{
59+
return EstimateBaselineShift(shape).Value;
60+
}
61+
public static double EstimateBaselineShiftValue(TextStyle textStyle, Shape shape)
62+
{
63+
return EstimateBaselineShift(textStyle, shape).Value;
64+
}
65+
}
66+
}

Source/SVGImage/SVG/Utils/MathUtils.cs

Lines changed: 10 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -18,65 +18,23 @@ public static bool IsNearlyEqual(this double a, double b, double epsilon = Doubl
1818
{
1919
return Math.Abs(a - b) < epsilon;
2020
}
21-
}
22-
internal static class BaselineHelper
23-
{
24-
public static LengthPercentageOrNumber EstimateBaselineShift(Shape shape)
25-
{
26-
return EstimateBaselineShift(shape.TextStyle, shape);
27-
}
28-
/// <summary>
29-
/// The purpose of this method is to allow TextStrings which are not shapes themselves to use the same logic as TextShapes to estimate the baseline shift.
30-
/// They can use this method to estimate the baseline shift based on the TextStyle of the TextString's parent Shape.
31-
/// </summary>
32-
/// <param name="textStyle"></param>
33-
/// <param name="shape"></param>
34-
/// <returns></returns>
35-
public static LengthPercentageOrNumber EstimateBaselineShift(TextStyle textStyle, Shape shape)
21+
public static int Clamp(int value, int min, int max)
3622
{
37-
if (String.IsNullOrEmpty( textStyle.BaseLineShift) || textStyle.BaseLineShift == "baseline")
38-
{
39-
return new LengthPercentageOrNumber(0d, new LengthContext(shape, LengthUnit.Number));
40-
}
41-
else if (textStyle.BaseLineShift == "sub")
42-
{
43-
//Based on previous estimation
44-
return new LengthPercentageOrNumber( textStyle.FontSize * 0.5, new LengthContext(shape, LengthUnit.Number));
45-
}
46-
else if (textStyle.BaseLineShift == "super")
23+
if (min > max)
4724
{
48-
//Based on previous estimation
49-
return new LengthPercentageOrNumber((-1) * (textStyle.FontSize + (textStyle.FontSize * 0.25)), new LengthContext(shape, LengthUnit.Number));
25+
throw new ArgumentException("min must be less than or equal to max", nameof(min));
5026
}
51-
else if(textStyle.BaseLineShift.EndsWith("%") && Double.TryParse(textStyle.BaseLineShift.Substring(0, textStyle.BaseLineShift.Length - 1), out double d))
52-
{
53-
try
54-
{
55-
//The computed value of the property is this percentage multiplied by the computed "line-height" of the ‘text’ element.
56-
//for the purposes of processing the ‘font’ property in SVG, 'line-height' is assumed to be equal the value for property ‘font-size’
57-
return new LengthPercentageOrNumber(d, new LengthContext(shape, LengthUnit.rem));
58-
}
59-
catch
60-
{
61-
//Continue
62-
}
63-
}
64-
try
27+
28+
if (value < min)
6529
{
66-
return LengthPercentageOrNumber.Parse(shape, textStyle.BaseLineShift, LengthOrientation.Vertical);
30+
return min;
6731
}
68-
catch
32+
else if (value > max)
6933
{
70-
return new LengthPercentageOrNumber(0d, new LengthContext(shape, LengthUnit.Number));
34+
return max;
7135
}
72-
}
73-
public static double EstimateBaselineShiftValue(Shape shape)
74-
{
75-
return EstimateBaselineShift(shape).Value;
76-
}
77-
public static double EstimateBaselineShiftValue(TextStyle textStyle, Shape shape)
78-
{
79-
return EstimateBaselineShift(textStyle, shape).Value;
36+
37+
return value;
8038
}
8139
}
8240
}

0 commit comments

Comments
 (0)