Skip to content

Commit f9c0eb0

Browse files
committed
Merge branch 'feature/svg_chart_and_shape' into develop9
# Conflicts: # src/EPPlus.Export.ImageRenderer.Test/Chart/LineChartToSvgTests.cs # src/EPPlus.Export.ImageRenderer.Test/TextRenderTests.cs # src/EPPlus.Export.ImageRenderer/EPPlus.Export.ImageRenderer.csproj # src/EPPlus.Export.ImageRenderer/ImageRenderer.cs # src/EPPlus.Export.ImageRenderer/RenderItems/Shared/TextBodyItem.cs # src/EPPlus.Export.ImageRenderer/Svg/Chart/Axis/DateAxisScaleCalculator.cs # src/EPPlus.Export.ImageRenderer/Svg/Chart/Axis/ValueAxisScaleCalculator.cs # src/EPPlus.Export.ImageRenderer/Svg/Chart/ChartTypeDrawers/BarColumnChartTypeDrawer.cs # src/EPPlus.Export.ImageRenderer/Svg/Chart/ChartTypeDrawers/ChartTypeDrawer.cs # src/EPPlus.Export.ImageRenderer/Svg/Chart/SvgChart.cs # src/EPPlus.Export.ImageRenderer/Svg/Chart/SvgChartAxis.cs # src/EPPlus.Export.ImageRenderer/Svg/Chart/SvgChartLegend.cs # src/EPPlus.Export.ImageRenderer/Svg/Chart/SvgChartPlotarea.cs # src/EPPlus.Export.ImageRenderer/Svg/SvgShape.cs # src/EPPlus.Fonts.OpenType.Tests/TextFragmentCollectionTests.cs # src/EPPlus.sln # src/EPPlusTest/Issues/WorksheetIssues.cs
2 parents c77bfd8 + 1ecf3e1 commit f9c0eb0

29 files changed

+707
-149
lines changed

src/EPPlus.Export.ImageRenderer.Test/Chart/LineChartToSvgTests.cs

Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,17 @@ public void GenerateSvgForLineCharts_sheet1()
2020
var ws = p.Workbook.Worksheets[0];
2121
var renderer = new EPPlusImageRenderer.ImageRenderer();
2222

23-
//var ix = 2;
24-
//var c = ws.Drawings[ix];
25-
//var svg = renderer.RenderDrawingToSvg(c);
26-
//SaveTextFileToWorkbook($"svg\\ChartForSvg_ind{ix++}.svg", svg);
23+
var ix = 1;
24+
var c = ws.Drawings[ix];
25+
var svg = renderer.RenderDrawingToSvg(c);
26+
SaveTextFileToWorkbook($"svg\\ChartForSvg_ind{ix++}.svg", svg);
2727

28-
var ix = 0;
29-
foreach (ExcelChart c in ws.Drawings)
30-
{
31-
var svg = renderer.RenderDrawingToSvg(c);
32-
SaveTextFileToWorkbook($"svg\\ChartForSvg{ix++}.svg", svg);
33-
}
28+
//var ix = 0;
29+
//foreach (ExcelChart c in ws.Drawings)
30+
//{
31+
// var svg = renderer.RenderDrawingToSvg(c);
32+
// SaveTextFileToWorkbook($"svg\\ChartForSvg{ix++}.svg", svg);
33+
//}
3434
}
3535
}
3636

@@ -75,25 +75,45 @@ public void GenerateSvgForLineCharts_sheet3()
7575
}
7676
}
7777
[TestMethod]
78-
public void GenerateSvgForLineCharts()
78+
public void GenerateSvgForComboCharts_sheet4()
7979
{
8080
ExcelPackage.License.SetNonCommercialOrganization("EPPlus Project");
81-
using (var p = OpenTemplatePackage("LineChartRenderTest.xlsx"))
81+
using (var p = OpenTemplatePackage("ChartForSvg.xlsx"))
8282
{
83-
var ws = p.Workbook.Worksheets[0];
83+
var ws = p.Workbook.Worksheets[3];
8484
var renderer = new EPPlusImageRenderer.ImageRenderer();
8585
//var ix = 1;
8686
//var c = ws.Drawings[ix];
8787
//var svg = renderer.RenderDrawingToSvg(c);
88-
//SaveTextFileToWorkbook($"svg\\LineChartForSvg_Single{ix++}.svg", svg);
88+
//SaveTextFileToWorkbook($"svg\\ChartForSvg_sheet2_{ix++}.svg", svg);
8989
var ix = 1;
9090
foreach (ExcelChart c in ws.Drawings)
9191
{
9292
var svg = renderer.RenderDrawingToSvg(c);
93-
SaveTextFileToWorkbook($"svg\\LineChartForSvg{ix++}.svg", svg);
93+
SaveTextFileToWorkbook($"svg\\ChartForSvg_Combo_Sheet4{ix++}.svg", svg);
9494
}
9595
}
9696
}
97+
[TestMethod]
98+
public void GenerateSvgForLineCharts()
99+
{
100+
ExcelPackage.License.SetNonCommercialOrganization("EPPlus Project");
101+
using (var p = OpenTemplatePackage("LineChartRenderTest.xlsx"))
102+
{
103+
var ws = p.Workbook.Worksheets[0];
104+
var renderer = new EPPlusImageRenderer.ImageRenderer();
105+
var ix = 1;
106+
var c = ws.Drawings[ix];
107+
var svg = renderer.RenderDrawingToSvg(c);
108+
SaveTextFileToWorkbook($"svg\\LineChartForSvg_Single{ix++}.svg", svg);
109+
//var ix = 1;
110+
//foreach (ExcelChart c in ws.Drawings)
111+
//{
112+
// var svg = renderer.RenderDrawingToSvg(c);
113+
// SaveTextFileToWorkbook($"svg\\LineChartForSvg{ix++}.svg", svg);
114+
//}
115+
}
116+
}
97117

98118
[TestMethod]
99119
public void GenerateSvgForCharts_SecondaryAxis()
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using OfficeOpenXml;
2+
using OfficeOpenXml.Drawing.Chart;
3+
using System;
4+
using System.Collections.Generic;
5+
using System.Linq;
6+
using System.Text;
7+
8+
namespace EPPlus.Export.ImageRenderer.Tests.Chart
9+
{
10+
[TestClass]
11+
public class PieChartTests : TestBase
12+
{
13+
[TestMethod]
14+
public void GenerateSvgForPieChart()
15+
{
16+
ExcelPackage.License.SetNonCommercialOrganization("EPPlus Project");
17+
using (var p = OpenTemplatePackage("BasicPieChart.xlsx"))
18+
{
19+
var ws = p.Workbook.Worksheets[0];
20+
var renderer = new EPPlusImageRenderer.ImageRenderer();
21+
22+
var ix = 0;
23+
foreach (ExcelChart c in ws.Drawings)
24+
{
25+
var svg = renderer.RenderDrawingToSvg(c);
26+
SaveTextFileToWorkbook($"svg\\PieChartForSvg2{ix++}.svg", svg);
27+
}
28+
}
29+
}
30+
}
31+
}

src/EPPlus.Export.ImageRenderer.Test/TextRenderTests.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,8 @@ public void VerifyVerticalAlignCenter()
325325
var svgShape = new SvgShape(shape);
326326
SvgTextBodyItem tbItem = svgShape.TextBodySvg;
327327

328+
//EPPlusImageRenderer.ImageRenderer.RenderDrawingToSvg(shape);
329+
328330
//Appears off by 1-2 px bc of border width
329331
Assert.AreEqual(190d, tbItem.Bounds.GlobalTop.PointToPixel(),1.0);
330332
}
@@ -345,7 +347,8 @@ public void VerifyVerticalAlignBottom()
345347

346348
var ir = new EPPlusImageRenderer.ImageRenderer();
347349
var svg = ir.RenderDrawingToSvg(shape);
348-
350+
SaveTextFileToWorkbook("bottom.svg", svg);
351+
SaveWorkbook("vaBottom.xlsx", p);
349352
//Appears off by ~2 px because of border width
350353
Assert.AreEqual(278d, tbItem.Bounds.GlobalTop.PointToPixel(), 1.0);
351354
}

src/EPPlus.Export.ImageRenderer/EPPlus.Export.ImageRenderer.csproj

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -57,21 +57,17 @@
5757
<Reference Include="System.Security" />
5858
<Reference Include="System.Xml" />
5959
<Reference Include="System.Threading.Tasks" />
60-
<PackageReference Include="System.ComponentModel.Annotations" />
6160
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" />
62-
<PackageReference Include="System.Security.Cryptography.Xml" />
6361
</ItemGroup>
6462

6563
<ItemGroup Condition="'$(TargetFramework)' != 'net35' and '$(TargetFramework)' != 'net462' and '$(TargetFramework)' != 'net9.0'">
6664
<PackageReference Include="Microsoft.Extensions.Configuration.Json" />
6765
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" />
68-
<PackageReference Include="System.Security.Cryptography.Pkcs" />
6966
<PackageReference Include="System.ComponentModel.Annotations" />
70-
<PackageReference Include="System.Text.Encoding.CodePages" />
71-
<PackageReference Include="System.Security.Cryptography.Xml" />
7267
</ItemGroup>
7368

7469
<ItemGroup Condition="'$(TargetFramework)' == 'net9.0'">
70+
<PackageReference Include="Microsoft.Extensions.Configuration.Json" VersionOverride="9.0.15" />
7571
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" />
7672
<PackageReference Include="System.ComponentModel.Annotations" />
7773
</ItemGroup>

src/EPPlus.Export.ImageRenderer/ImageRenderer.cs

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ Date Author Change
2525
using EPPlusImageRenderer.Svg;
2626
using OfficeOpenXml.Drawing;
2727
using OfficeOpenXml.Drawing.Chart;
28+
using OfficeOpenXml.FormulaParsing.Excel.Functions.MathFunctions;
2829
using OfficeOpenXml.Utils;
2930
using OfficeOpenXml.Utils.EnumUtils;
3031
using System;
@@ -61,6 +62,7 @@ public enum RenderItemClasses
6162
Rect,
6263
TextBox,
6364
Shape,
65+
CircleSegment
6466
}
6567

6668
public Dictionary<string, object> GetItemProperties(RenderItemClasses item)
@@ -69,12 +71,74 @@ public Dictionary<string, object> GetItemProperties(RenderItemClasses item)
6971
{
7072
case RenderItemClasses.Rect:
7173
return new Dictionary<string, object> { { "Top", 10d }, { "Left", 10d }, { "Width", 10d }, { "Height", 10d }, {"Opacity", 0.8 }, {"Fill", Color.Goldenrod } };
74+
case RenderItemClasses.CircleSegment:
75+
return new Dictionary<string, object> { { "angle", 25d }, { "radius", 10d }, { "cx", 20d }, { "cy", 20d } };
7276
case RenderItemClasses.TextBox:
7377
default:
7478
throw new NotImplementedException("This class has not been implemented as an option yet");
79+
7580
}
7681
}
7782

83+
private string RenderCircleSegment(DrawingBase baseItem, Dictionary<string, object> itemProperties)
84+
{
85+
return RenderCircleSegment((double)itemProperties["angle"], (double)itemProperties["radius"], (double)itemProperties["cx"], (double)itemProperties["cy"]);
86+
}
87+
88+
string RenderCircleSegment(double angle, double radius, double cx, double cy)
89+
{
90+
var angleRadians = angle * (Math.PI / 180.0d);
91+
92+
var xPoint = cx + (radius * Math.Cos(angleRadians));
93+
var yPoint = cy + (radius * Math.Sin(angleRadians));
94+
95+
Coordinate endPoint = new Coordinate(xPoint, yPoint);
96+
97+
var baseBB = new BoundingBox();
98+
99+
//96x96 px
100+
baseBB.Width = 72;
101+
baseBB.Height = 72;
102+
103+
var baseItem = new DrawingItemForTesting(baseBB);
104+
105+
BoundingBox parent = new BoundingBox();
106+
107+
var slice = new SvgRenderPathItem(baseItem, baseItem.Bounds);
108+
109+
var startPoint = new Coordinate(cx, 0);
110+
111+
var moveCenter = new PathCommands(PathCommandType.Move, slice, cx / baseItem.Bounds.Width, cy / baseItem.Bounds.Height);
112+
var lineToStart = new PathCommands(PathCommandType.Line, slice, startPoint.X / baseItem.Bounds.Width, startPoint.Y / baseItem.Bounds.Height);
113+
114+
115+
116+
var w = baseItem.Bounds.Width.PointToPixel();
117+
var h = baseItem.Bounds.Height.PointToPixel();
118+
119+
var radX = radius.PointToPixel() / w;
120+
var radY = radius.PointToPixel() / h;
121+
122+
var arcCommand = new PathCommands(PathCommandType.Arc, slice, new double[] { radX, radY, 0, 0, 1, endPoint.X / baseItem.Bounds.Width, endPoint.Y / baseItem.Bounds.Height });
123+
124+
slice.Commands.Add(moveCenter);
125+
slice.Commands.Add(lineToStart);
126+
slice.Commands.Add(arcCommand);
127+
128+
slice.FillColor = "red";
129+
slice.BorderColor = "green";
130+
131+
baseItem.RenderItems.Add(slice);
132+
133+
var sb = new StringBuilder();
134+
135+
baseItem.Render(sb);
136+
137+
return sb.ToString();
138+
139+
//return baseItem;
140+
}
141+
78142
/// <summary>
79143
/// For Testing the specific renderItem class
80144
/// </summary>
@@ -325,12 +389,19 @@ private RenderItem GenerateRect(DrawingBase baseItem, Dictionary<string, object>
325389
return rectItem;
326390
}
327391

392+
private string GenerateFromCircle(RenderItemClasses preset, DrawingBase baseItem, Dictionary<string, object> itemProperties)
393+
{
394+
return RenderCircleSegment(baseItem, itemProperties);
395+
}
396+
328397
private RenderItem GenerateFromClasses(RenderItemClasses preset, DrawingBase baseItem, Dictionary<string, object> itemProperties)
329398
{
330399
switch (preset)
331400
{
332401
case RenderItemClasses.Rect:
333402
return GenerateRect(baseItem, itemProperties);
403+
case RenderItemClasses.CircleSegment:
404+
//return RenderCircleSegment(baseItem, itemProperties);
334405
case RenderItemClasses.TextBox:
335406

336407

src/EPPlus.Export.ImageRenderer/RenderItems/PathCommandType.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ internal enum PathCommandType : byte
2020
VerticalLine = 3,
2121
CubicBézier = 4,
2222
QuadraticBézier = 5,
23-
Arc=6,
23+
Arc = 6,
2424
End = 0xFF
2525
}
2626

src/EPPlus.Export.ImageRenderer/RenderItems/Shared/TextBodyItem.cs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -152,14 +152,14 @@ internal virtual void ImportTextBody(ExcelTextBody body, ExcelHorizontalAlignmen
152152
VerticalAlignment = body.Anchor;
153153

154154
//We already apply bounds top via the parent Transform
155-
double paragraphStartY = 0;
155+
double currentHeight = 0;
156156
double largestWidth = double.MinValue;
157157

158158
foreach (var paragraph in body.Paragraphs)
159159
{
160-
ImportParagraph(paragraph, paragraphStartY);
160+
ImportParagraph(paragraph, currentHeight);
161161
var addedPara = Paragraphs.Last();
162-
paragraphStartY = addedPara.Bounds.Bottom;
162+
currentHeight = addedPara.Bounds.Bottom;
163163
largestWidth = Math.Max(largestWidth, addedPara.Bounds.Width);
164164
}
165165

@@ -170,7 +170,7 @@ internal virtual void ImportTextBody(ExcelTextBody body, ExcelHorizontalAlignmen
170170

171171
if (Paragraphs != null && Paragraphs.Count() > 0)
172172
{
173-
Bounds.Height = paragraphStartY;
173+
Bounds.Height = currentHeight;
174174
}
175175

176176
Bounds.Top = GetAlignmentVertical();
@@ -243,7 +243,6 @@ private double GetAlignmentVertical()
243243
break;
244244
//Center means center of a Shape's ENTIRE bounding box height.
245245
//Not center of the Inset GetRectangle
246-
//Not center of the Inset GetRectangle
247246
case eTextAnchoringType.Center:
248247
alignmentY = (MaxHeight - Bounds.Height)/2 + Bounds.Top;
249248
break;

src/EPPlus.Export.ImageRenderer/ShapeDefinitions/ShapeDefinition.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ Date Author Change
1717
using System.Diagnostics;
1818
using System.Globalization;
1919
using System.Linq;
20-
using System.Security.Cryptography.Xml;
2120

2221
namespace EPPlusImageRenderer.ShapeDefinitions
2322
{

0 commit comments

Comments
 (0)