- A+
所属分类:.NET技术
本文是将演示如何解析pptx文件的形状到WPF当中,并且绘制显示出来
安装Openxml sdk
首先,我们先安装nuget的openxml sdk,下面两种方式都可以安装:
- nuget包管理器控制台:
Install-Package DocumentFormat.OpenXml -Version 2.13.0
- csproj引用:
<PackageReference Include="DocumentFormat.OpenXml" Version="2.13.0" />
解析Pptx
我打算解析pptx中的五边形来作为演示效果,直接上代码:
MainWindow.xaml:
<Grid> <Grid.RowDefinitions> <RowDefinition /> <RowDefinition Height="2*"/> </Grid.RowDefinitions> <StackPanel Orientation="Horizontal" VerticalAlignment="Center" HorizontalAlignment="Center"> <TextBlock Text="pptx的文件路径:" VerticalAlignment="Center" FontSize="15" Margin="10"/> <TextBox x:Name="FilePathText" Height="50" Width="300" Margin="0,0,10,0" TextWrapping="Wrap"/> <Button x:Name="Button" Content="解析PPT" Click="Button_OnClick" Width="120" Height="40"/> </StackPanel> <Path x:Name="Path" Grid.Row="1" HorizontalAlignment="Center" VerticalAlignment="Center" Stroke="Blue"/> </Grid>
MainWindow.xaml.cs:
private void PptxToGeometry(string filePath) { if (!File.Exists(filePath) || !filePath.EndsWith(".pptx", StringComparison.OrdinalIgnoreCase)) { return; } using (var presentationDocument = PresentationDocument.Open(filePath, false)) { var presentationPart = presentationDocument.PresentationPart; var presentation = presentationPart?.Presentation; var slideIdList = presentation?.SlideIdList; if (slideIdList == null) { return; } foreach (var slideId in slideIdList.ChildElements.OfType<SlideId>()) { var slidePart = (SlidePart)presentationPart.GetPartById(slideId.RelationshipId); var slide = slidePart.Slide; foreach (var shapeProperties in slide.Descendants<ShapeProperties>()) { var presetGeometry = shapeProperties.GetFirstChild<PresetGeometry>(); if (presetGeometry != null && presetGeometry.Preset.HasValue) { if (presetGeometry.Preset == ShapeTypeValues.Pentagon) { var transform2D = shapeProperties.GetFirstChild<Transform2D>(); var extents = transform2D?.GetFirstChild<Extents>(); if (extents != null) { var width = extents.Cx; var height = extents.Cy; if (width.HasValue && height.HasValue) { var points = GetPentagonPoints(width.Value.EmuToPixel(), height.Value.EmuToPixel()); RenderGeometry(points); } } } } } } } } /// <summary> /// 获取五边形顶点坐标 /// </summary> /// <param name="width"></param> /// <param name="height"></param> /// <returns></returns> /// 该五边形定义出自ECMA-376-Fifth-Edition-Part-1-Fundamentals-And-Markup-Language-Reference /// OfficeOpenXML-DrawingMLGeometries文档的presetShapeDefinitions.xml private List<Point> GetPentagonPoints(double width, double height) { var properties = new FormulaProperties(width, height); //<avLst xmlns="http://schemas.openxmlformats.org/drawingml/2006/main"> // <gd name="hf" fmla="val 105146" /> // <gd name="vf" fmla="val 110557" /> //</avLst> var hf = 105146d; var vf = 110557d; //<gdLst xmlns="http://schemas.openxmlformats.org/drawingml/2006/main"> // <gd name="swd2" fmla="*/ wd2 hf 100000" /> // <gd name="shd2" fmla="*/ hd2 vf 100000" /> // <gd name="svc" fmla="*/ vc vf 100000" /> // <gd name="dx1" fmla="cos swd2 1080000" /> // <gd name="dx2" fmla="cos swd2 18360000" /> // <gd name="dy1" fmla="sin shd2 1080000" /> // <gd name="dy2" fmla="sin shd2 18360000" /> // <gd name="x1" fmla="+- hc 0 dx1" /> // <gd name="x2" fmla="+- hc 0 dx2" /> // <gd name="x3" fmla="+- hc dx2 0" /> // <gd name="x4" fmla="+- hc dx1 0" /> // <gd name="y1" fmla="+- svc 0 dy1" /> // <gd name="y2" fmla="+- svc 0 dy2" /> // <gd name="it" fmla="*/ y1 dx2 dx1" /> //</gdLst> // <gd name="swd2" fmla="*/ wd2 hf 100000" /> var swd2 = properties.wd2 * hf / 100000; // <gd name="shd2" fmla="*/ hd2 vf 100000" /> var shd2 = properties.hd2 * vf / 100000; // <gd name="svc" fmla="*/ vc vf 100000" /> var svc = properties.vc * vf / 100000; // <gd name="dx1" fmla="cos swd2 1080000" /> var dx1 = Cos(swd2, 1080000); // <gd name="dx2" fmla="cos swd2 18360000" /> var dx2 = Cos(swd2, 18360000); // <gd name="dy1" fmla="sin shd2 1080000" /> var dy1 = Sin(shd2, 1080000); // <gd name="dy2" fmla="sin shd2 18360000" /> var dy2 = Sin(shd2, 18360000); // <gd name="x1" fmla="+- hc 0 dx1" /> var x1 = properties.hc - dx1; // <gd name="x2" fmla="+- hc 0 dx2" /> var x2 = properties.hc - dx2; // <gd name="x3" fmla="+- hc dx2 0" /> var x3 = properties.hc + dx2; // <gd name="x4" fmla="+- hc dx1 0" /> var x4 = properties.hc + dx1; // <gd name="y1" fmla="+- svc 0 dy1" /> var y1 = svc - dy1; // <gd name="y2" fmla="+- svc 0 dy2" /> var y2 = svc - dy2; // <gd name="it" fmla="*/ y1 dx2 dx1" /> // <pathLst xmlns="http://schemas.openxmlformats.org/drawingml/2006/main"> // <path> // <moveTo> // <pt x="x1" y="y1" /> // </moveTo> // <lnTo> // <pt x="hc" y="t" /> // </lnTo> // <lnTo> // <pt x="x4" y="y1" /> // </lnTo> // <lnTo> // <pt x="x3" y="y2" /> // </lnTo> // <lnTo> // <pt x="x2" y="y2" /> // </lnTo> // <close /> // </path> //</pathLst> var points = new List<Point>(5) { new Point(x1, y1), new Point(properties.hc,properties.t), new Point(x4, y1), new Point(x3, y2), new Point(x2, y2), }; return points; } private void RenderGeometry(List<Point> points) { if (points.Count > 0) { var streamGeometry = new StreamGeometry(); using var context = streamGeometry.Open(); context.BeginFigure(points[0], true, true); context.PolyLineTo(points, true, true); this.Path.Data = streamGeometry; } } private void Button_OnClick(object sender, RoutedEventArgs e) { var filePath = @"C:UsersRyzenDesktop测验五边形.pptx"; if (!string.IsNullOrEmpty(FilePathText.Text)) { filePath = FilePathText.Text.Trim(); } PptxToGeometry(filePath); }
ShapeGeometryHelper.cs:
public static class ShapeGeometryHelper { public readonly struct FormulaProperties { public readonly double t; public readonly double h; public readonly double w; public readonly double hd2; public readonly double wd2; public readonly double vc; public readonly double hc; public FormulaProperties(double width, double height) { t = 0; w = width; h = height; hd2 = h / 2; wd2 = w / 2; vc = height / 2; hc = width / 2; } } public static long EmuToPixel(this long eum) { const long defaultDpi = 96; return eum / 914400 * defaultDpi; } /// <summary> /// OpenXml 三角函数的Sin函数:sin x y = (x * sin( y )) = (x * Math.Sin(y)) /// </summary> /// <param name="x">ppt的数值</param> /// <param name="y">ppt表示角度的值</param> /// <returns></returns> public static double Sin(double x, int y) { var angle = GetAngle(y); return x * Math.Sin(angle); } /// <summary> /// OpenXml 三角函数的Cos函数:cos x y = (x * cos( y )) = (x * Math.Cos(y)) /// </summary> /// <param name="x">ppt的数值</param> /// <param name="y">ppt表示角度的值</param> /// <returns></returns> public static double Cos(double x, int y) { var angle = GetAngle(y); return x * Math.Cos(angle); } /// <summary> /// OpenXml 三角函数的Tan函数:tan x y = (x * tan( y )) = (x * Math.Tan(y)) /// </summary> /// <param name="x">ppt的数值</param> /// <param name="y">ppt表示角度的值</param> /// <returns></returns> public static double Tan(double x, int y) { var angle = GetAngle(y); return x * Math.Tan(angle); } /// <summary> /// ppt的值转为角度 /// </summary> /// <param name="value">ppt表示角度的值</param> /// <returns></returns> private static double GetAngle(int value) { var degree = value / 60000.0; var angle = degree * Math.PI / 180; return angle; } }
效果如下:
源码
BlogCodeSample/PptPolygonToWPFGeometry at main · ZhengDaoWang/BlogCodeSample
参考
C# dontet Office Open XML Unit Converter