zoukankan      html  css  js  c++  java
  • 【OpenXml】Pptx的形状转为WPF的Geometry

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

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

    C# dotnet 使用 OpenXml 解析 PPT 文件

  • 相关阅读:
    微信小程序---app.json中设置背景色不生效解决办法
    给网站设置ICO图标
    ajax事件(五)
    ajax关于主流中的异类:应对Opera(四)
    dashboard
    tomcat 清理日志
    jQuery datatable
    php wampserver 80 端口无法开启的解决方法
    mysql 行列转换
    jQuery-2.1.4.min.js:4 Uncaught TypeError: Illegal invocation
  • 原文地址:https://www.cnblogs.com/ryzen/p/14864302.html
Copyright © 2011-2022 走看看