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:\Users\Ryzen\Desktop\测验\五边形.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 文件
Pptx的形状转为WPF的Geometry的更多相关文章
- Pptx的多路径形状转为WPF的Path
本文是将演示如何解析pptx文件的多路径的形状转换到WPF,绘制多个Shape的Path Shape Path 这是Pptx的[标注:弯曲曲线(无边框)]形状的OpenXml定义部分: <cal ...
- 【OpenXml】Pptx的边框虚线转为WPF的边框虚线
安装Openxml sdk 首先,我们先安装nuget的需要的有关的Openxml sdk,我们开源了解析pptx的Openxml拍平层,下面两种方式都可以安装: nuget包管理器控制台: Inst ...
- 使用不安全代码将 Bitmap 位图转为 WPF 的 ImageSource 以获得高性能和持续小的内存占用
在 WPF 中将一个现成的 Bitmap 位图转换成 ImageSource 用于显示一个麻烦的事儿,因为 WPF 并没有提供多少可以转过来的方法.不过产生 Bitmap 来源却非常多,比如屏幕截图. ...
- 【Openxml】将Openxml的椭圆弧线arcTo转为Svg的椭圆弧线
本文将介绍如何将OpenXml的actTo转为Svg的弧线(a) OpenXml的artTo 首先下面是一段OpenXml的arcTo弧线 <arcTo wR="152403" ...
- WPF 中的形状和基本绘图概述
本主题概述如何使用 Shape 对象绘图. Shape 是一种允许您在屏幕中绘制形状的 UIElement 类型. 由于它们是 UI 元素,因此 Shape 对象可以在 Panel 元素和大多数控件中 ...
- WPF 动画(形状、画刷)
一:形状 在WPF用户界面中,可以通过形状(Shape)来绘制直线.椭圆.矩形及一些多边形的类.通过这些基本的图像,组合成为复杂的图形. Shape类中,主要的形状有Rectangle(),Ellip ...
- 使用 WPF 做个 PowerPoint 系列 基于 OpenXML 解析实现 PPT 文本描边效果
本文是使用 WPF 做个 PowerPoint 系列的博客,本文来告诉大家如何解析 PPT 里面的文本描边效果,在 WPF 应用中绘制出来,实现像素级相同 背景知识 在开始之前,期望你了解了 PPT ...
- 【WPF学习】第四十三章 路径和几何图形
前面四章介绍了继承自Shape的类,包括Rectangle.Ellipse.Polygon以及Polyline.但还有一个继承自Shape的类尚未介绍,而且该类是到现在为止功能最强大的形状类,即Pat ...
- Three.js基础探寻六——文字形状与自定义形状
1.文字形状 说起3d文字想起了早年word里的一些艺术字: 时间真快. 那么TextGeometry可以用来创建三维的文字形状. 使用文字形状需要下载和引用额外的字体库.这里,我们以 helveti ...
随机推荐
- 模拟退火算法Python编程(2)约束条件的处理
1.最优化与线性规划 最优化问题的三要素是决策变量.目标函数和约束条件. 线性规划(Linear programming),是研究线性约束条件下线性目标函数的极值问题的优化方法,常用于解决利用现有的资 ...
- 1. Robot Framework入门
RF定义: 通用型的 自动测试框架, 绝大部分的软件的的自动化系统都可以采用它. 特点: 测试数据文件(Test Data)对应一个个的测试用例.测试数据文件里面使用的功能小模块叫关键字,由测试库(T ...
- Thinkphp树形菜单相关方法
1 <?php 2 3 /** 4 * Menu(菜单管理) 5 */ 6 namespace Admin\Controller; 7 use Common\Controller\Adminba ...
- Win64 驱动内核编程-7.内核里操作进程
在内核里操作进程 在内核里操作进程,相信是很多对 WINDOWS 内核编程感兴趣的朋友第一个学习的知识点.但在这里,我要让大家失望了,在内核里操作进程没什么特别的,就标准方法而言,还是调用那几个和进程 ...
- Win64 驱动内核编程-31.枚举与删除映像回调
枚举与删除映像回调 映像回调可以拦截 RING3 和 RING0 的映像加载.某些游戏保护会用此来拦截黑名单中的驱动加载,比如 XUETR.WIN64AST 的驱动.同理,在反游戏保护的过程中,也可以 ...
- 【JavaScript】Leetcode每日一题-移除元素
[JavaScript]Leetcode每日一题-移除元素 [题目描述] 给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度. 不要使用 ...
- 【python】Leetcode每日一题-螺旋矩阵
Leetcode每日一题-螺旋矩阵 [题目描述] 给你一个 m 行 n 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素. 示例1: 输入:matrix = [[1,2,3], ...
- 码农飞升记-02-OracleJDK是什么?OracleJDK的版本怎么选择?
目录 1.Oracle JDK 是什么? 2.Oracle JDK 版本如何选择? 1.Java SE 发布节奏以及不同版本的差距 1.Java SE 8 以及之前版本的发布节奏和不同版本的差距 1. ...
- PHP基础—PHP的数据类型与常量使用
- Spring Cloud Alibaba(8)---Feign服务调用
Feign服务调用 有关Spring Cloud Alibaba之前写过五篇文章,这篇也是在上面项目的基础上进行开发. Spring Cloud Alibaba(1)---入门篇 Spring Clo ...