Pptx的形状转为WPF的Geometry

  • A+
所属分类:.NET技术
摘要

本文是将演示如何解析pptx文件的形状到WPF当中,并且绘制显示出来首先,我们先安装nuget的openxml sdk,下面两种方式都可以安装:

本文是将演示如何解析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;         }     } 

效果如下:

Pptx的形状转为WPF的Geometry

源码

BlogCodeSample/PptPolygonToWPFGeometry at main · ZhengDaoWang/BlogCodeSample

参考

C# dontet Office Open XML Unit Converter

C# dotnet 使用 OpenXml 解析 PPT 元素的坐标和宽度高度

C# dotnet 使用 OpenXml 解析 PPT 文件