dotnet OpenXML 读取 PPT 形状边框定义在 Style 的颜色画刷
本文来和大家聊聊在 PPT 形状使用了 Style 样式的颜色画刷读取方法
在开始之前,期望大家已了解如何在 dotnet 应用里面读取 PPT 文件,如果还不了解读取方法,请参阅 C# dotnet 使用 OpenXml 解析 PPT 文件
本文核心是来和大家聊聊 ECMA 376 文档里面,第 20.1.4.2.19 章的 lnRef (Line Reference) 内容里面没有提到的知识
在 Office 的 PowerPoint 添加默认的形状,在没有更改形状的填充和轮廓,形状使用的是默认的样式,如以下的默认矩形定义
<p:sp><p:nvSpPr><p:cNvPr id="6" name="矩形 1" /><p:cNvSpPr /><p:nvPr /></p:nvSpPr><p:spPr><a:xfrm><a:off x="3640346" y="1595887" /><a:ext cx="3804249" cy="3071004" /></a:xfrm><a:prstGeom prst="rect"><a:avLst /></a:prstGeom><a:ln w="76200" /></p:spPr><p:style><a:lnRef idx="2"><a:schemeClr val="accent1"><a:shade val="50000" /></a:schemeClr></a:lnRef><a:fillRef idx="1"><a:schemeClr val="accent1" /></a:fillRef><a:effectRef idx="0"><a:schemeClr val="accent1" /></a:effectRef><a:fontRef idx="minor"><a:schemeClr val="lt1" /></a:fontRef></p:style><p:txBody/>
</p:sp>
在 OpenXML 里面,通过 a:ln
表示 Outline 轮廓,也就是咱 WPF 形状元素的边框。包括定义了边框粗细和颜色画刷等
但是从上面文档内容可以看到,只是定义了边框的粗细,没有定义颜色。这就需要从 <p:style>
样式里面读取线条的样式。从 <a:lnRef idx="2">
可以读取到采用的是序号为 2 的线条样式,这里有一个细节是给定的序号也许会超过定义,解决方法请看 dotnet OpenXML 读取形状轮廓线条样式序号超过主题样式列表数
接着读取 <a:schemeClr val="accent1">
的内容,用来覆盖作为实际的颜色
下面我将给大家演示如何在 WPF 中读取 PPT 的形状 Style 边框颜色和在界面里面将此显示出来
先加上基础的库引用,以下代码写在 csproj 上,可在本文末尾找到全部源代码
<ItemGroup><PackageReference Include="dotnetCampus.OpenXmlUnitConverter" Version="1.4.1"/><PackageReference Include="DocumentFormat.OpenXml" Version="2.13.1" /></ItemGroup>
接着读取包含上文的形状的 PPT 文档
var file = new FileInfo("Test.pptx");using var presentationDocument = PresentationDocument.Open(file.FullName, false);
获取页面里面的形状,如以下代码
var slide = presentationDocument.PresentationPart!.SlideParts.First().Slide;var shape = slide.CommonSlideData!.ShapeTree!.GetFirstChild<Shape>()!;
先从 ShapeProperties 里面获取形状的边框粗细,如下面代码
ShapeProperties shapeProperties = shape.ShapeProperties!;// 虽然这个形状有轮廓,但是定义是 `<a:ln w="76200" />` 只有宽度,没有颜色Outline outline = shapeProperties.GetFirstChild<Outline>()!;Debug.Assert(outline.GetFirstChild<SchemeColor>() is null);var outlineWidth = new Emu(outline.Width!);
以上代码拿到的 outlineWidth
就是形状的边框粗细。此形状有轮廓,但是定义是 <a:ln w="76200" />
只有宽度,没有颜色。颜色需要在 Style 里面读取。在 PPTX 文件里面的定义如下
<a:lnRef idx="2"><a:schemeClr val="accent1"><a:shade val="50000" /></a:schemeClr></a:lnRef>
获取方法是先读取形状的样式,接着读取线条引用,请看代码
// 实际的颜色应该从 `<a:lnRef idx="2">` 拿到var shapeStyle = shape.ShapeStyle!;var lineReference = shapeStyle.LineReference!;
拿到 LineReference 就可以读取里层的颜色,如下面代码
// 读取里层的颜色var schemeColor = lineReference.GetFirstChild<SchemeColor>()!;
此颜色是 SchemeColor 颜色,按照 dotnet OpenXML 如何获取 schemeClr 颜色 文档的方法进行读取,读取时用到的辅助方法本文就不列出,还请参阅以上引用博客。当然,本文所有源代码都可以获取到,还请不用担心细节
以下是将 SchemeColor 转换为 System.Windows.Media.Color 的方法
var colorMap = slide.GetColorMap()!;var colorScheme = slide.GetColorScheme()!;var value = schemeColor.Val!.Value; // accent1value = ColorHelper.SchemeColorMap(value, colorMap);var actualColor = ColorHelper.FindSchemeColor(value, colorScheme)!; // <a:srgbClr val="5B9BD5"/>RgbColorModelHex rgbColorModelHex = actualColor.RgbColorModelHex!;var color = (Color) ColorConverter.ConvertFromString($"#{rgbColorModelHex.Val!.Value}");
接下来按照其他形状的解析方法,读取坐标和宽度高度,在界面显示出来
// 获取坐标var offset = shapeProperties.Transform2D!.Offset!;var x = new Emu(offset.X!);var y = new Emu(offset.Y!);var extents = shapeProperties.Transform2D.Extents!;var width = new Emu(extents.Cx!);var height = new Emu(extents.Cy!);// 创建元素var rectangle = new Rectangle(){Margin = new Thickness(x.ToPixel().Value, y.ToPixel().Value, 0, 0),Width = width.ToPixel().Value,Height = height.ToPixel().Value,StrokeThickness = outlineWidth.ToPixel().Value,Stroke = new SolidColorBrush(color)};Canvas.Children.Add(rectangle);
以上代码的 Canvas 是在 XAML 定义的,代码如下
<Grid><Canvas x:Name="Canvas"></Canvas></Grid>
运行之后的效果如下
可以看到颜色其实有些差距,原因是以上使用的 SchemeColor 没有加上颜色特效,在 PPTX 文件定义的颜色代码如下
<a:schemeClr val="accent1"><a:shade val="50000" /></a:schemeClr>
通过 dotnet OpenXML 颜色变换 文档可以了解到 Shade 是让颜色变暗,使用如下代码加上特效
var shade = schemeColor.GetFirstChild<Shade>()!;// 让颜色变暗color = ColorTransform.HandleShade(color, shade);
此时的效果如下
本文以上所有测试文件和代码放在github 和 gitee 欢迎访问
可以通过如下方式获取本文的源代码,先创建一个空文件夹,接着使用命令行 cd 命令进入此空文件夹,在命令行里面输入以下代码,即可获取到本文的代码
git init
git remote add origin https://gitee.com/lindexi/lindexi_gd.git
git pull origin d06378705fcc1a1ff19ea7d1f2544757fb0777c7
以上使用的是 gitee 的源,如果 gitee 不能访问,请替换为 github 的源
git remote remove origin
git remote add origin https://github.com/lindexi/lindexi_gd.git
获取代码之后,进入 Pptx 文件夹
虽然可以看到在 WPF 上的形状的边框颜色和在 PPT 上的形状颜色是相同的,然而以上逻辑却有漏洞在于以上是重新被定义了颜色。其实在 OpenXML 里面,按照的寻找属性的规则和 WPF 的资源是相同的逻辑,按照最近原则读取。也就是说读取顺序如下
- 形状的
a:ln
定义的颜色 - 形状的样式的
a:lnRef
引用的主题的颜色 - 形状继承的样式
以上的测试文档是属于在形状的 a:ln
没有定义的颜色,而在形状的样式的 a:lnRef
里面定义的颜色,而且形状引用样式里面使用的是 <a:schemeClr val="phClr" />
占位符颜色
如果在形状的 a:ln
和形状的样式的 a:lnRef
没有定义的颜色,只有在形状的样式的 a:lnRef
引用的主题的颜色,那么以上逻辑是不符合 OpenXML 定义的。或者说在形状的 a:ln
没有定义的颜色,而在形状的样式的 a:lnRef
里面有定义颜色,但是形状的样式的 a:lnRef
引用的主题的颜色不是 phClr (PlaceholderColor, a color used in theme definitions which means "use the color of the style")的颜色
如以下的文档内容
Slide1.xml:<p:sp><p:style><a:lnRef idx="2"><a:schemeClr val="accent1" /></a:lnRef></p:style>
</p:sp>Theme1:<a:lnStyleLst><a:ln w="6350" cap="flat" cmpd="sng" algn="ctr"></a:ln><a:ln w="12700" cap="flat" cmpd="sng" algn="ctr"><a:solidFill><a:srgbClr val="999999" /></a:solidFill><a:prstDash val="solid" /><a:miter lim="800000" /></a:ln><a:ln w="19050" cap="flat" cmpd="sng" algn="ctr"></a:ln></a:lnStyleLst>
通过 <a:lnRef idx="2">
可以了解到应该读取的是 LineStyleList 的第二项(从1开始)的颜色
和第一份文档不同的是,以上文档定义的是 <a:srgbClr val="999999" />
而不是 <a:schemeClr val="phClr" />
颜色。也就是说在 Slide1.xml 定义的 <a:schemeClr val="accent1" />
需要被忽略
变更之后的逻辑如下,先读取引用,参阅 dotnet OpenXML 读取形状轮廓线条样式序号超过主题样式列表数 文档的写法
var lineStyle = lineReference.Index!.Value;// idx="2"lineStyle--;// 获取主题var slidePart = slide.SlidePart!;var themeOverride = slidePart.ThemeOverridePart?.ThemeOverride?? slidePart.SlideLayoutPart!.ThemeOverridePart?.ThemeOverride;FormatScheme? formatScheme = themeOverride?.FormatScheme;if (formatScheme is null){formatScheme = slidePart.SlideLayoutPart!.SlideMasterPart!.ThemePart!.Theme!.ThemeElements!.FormatScheme;}var lineStyleList = formatScheme!.LineStyleList;var outlineList = lineStyleList!.Elements<Outline>().ToList(); // 其实,别用 ToList 的好,这里只是简化逻辑Outline themeOutline;if (lineStyle > outlineList.Count){themeOutline = outlineList[^1];}else{themeOutline = outlineList[(int)lineStyle];}
此时读取到的 themeOutline 就是如下的 OpenXML 文档内容
<a:ln w="12700" cap="flat" cmpd="sng" algn="ctr"><a:solidFill><a:srgbClr val="999999" /></a:solidFill><a:prstDash val="solid" /><a:miter lim="800000" /></a:ln>
先获取是否有定义 solidFill
的内容,如果有,那么继续获取里层颜色
var solidFill = themeOutline.GetFirstChild<SolidFill>()!;
在以上的文档里面,是存在 SolidFill 内容的,因此上面代码就不判断空了
获取里层的颜色,如果是 srgbClr (对应 OpenXML 的 RgbColorModelHex 类型)的话,那么计算颜色即可
var solidFill = themeOutline.GetFirstChild<SolidFill>()!;var colorModelHex = solidFill.GetFirstChild<RgbColorModelHex>();if (colorModelHex is not null){// <a:srgbClr val="999999" />color = (Color)ColorConverter.ConvertFromString($"#{colorModelHex.Val!.Value}");}
而如果是读取到 SchemeColor 而且是 PhColor 方式的颜色,那么依然按照上文的方式读取形状样式里面的 LineReference 的颜色
<a:lnRef idx="2"><a:schemeClr val="accent1"><a:shade val="50000" /></a:schemeClr></a:lnRef>
读取的逻辑如下
var solidFill = themeOutline.GetFirstChild<SolidFill>()!;var colorModelHex = solidFill.GetFirstChild<RgbColorModelHex>();if (colorModelHex is not null){}else{var themeSchemeColor = solidFill.GetFirstChild<SchemeColor>()!;if (themeSchemeColor.Val!.Value == SchemeColorValues.PhColor){// 读取里层的颜色var schemeColor = lineReference.GetFirstChild<SchemeColor>()!;// 读取 SchemeColor 方法请参阅如下文档// [dotnet OpenXML 如何获取 schemeClr 颜色](https://blog.lindexi.com/post/dotnet-OpenXML-%E5%A6%82%E4%BD%95%E8%8E%B7%E5%8F%96-schemeClr-%E9%A2%9C%E8%89%B2.html )var colorMap = slide.GetColorMap()!;var colorScheme = slide.GetColorScheme()!;var value = schemeColor.Val!.Value; // accent1value = ColorHelper.SchemeColorMap(value, colorMap);var actualColor = ColorHelper.FindSchemeColor(value, colorScheme)!; // <a:srgbClr val="5B9BD5"/>RgbColorModelHex rgbColorModelHex = actualColor.RgbColorModelHex!;color = (Color)ColorConverter.ConvertFromString($"#{rgbColorModelHex.Val!.Value}");// 根据 [dotnet OpenXML 颜色变换](https://blog.lindexi.com/post/dotnet-OpenXML-%E9%A2%9C%E8%89%B2%E5%8F%98%E6%8D%A2.html ) 进行修改颜色var shade = schemeColor.GetFirstChild<Shade>()!;// 让颜色变暗color = ColorTransform.HandleShade(color, shade);}}
此时更换文档,执行的界面如下
本文以上更新的测试文件和代码放在github 和 gitee 欢迎访问
可以通过如下方式获取本文的源代码,先创建一个空文件夹,接着使用命令行 cd 命令进入此空文件夹,在命令行里面输入以下代码,即可获取到本文的代码
git init
git remote add origin https://gitee.com/lindexi/lindexi_gd.git
git pull origin 868ad6c1a39853764167053e319b68a6db0a2c6b
以上使用的是 gitee 的源,如果 gitee 不能访问,请替换为 github 的源
git remote remove origin
git remote add origin https://github.com/lindexi/lindexi_gd.git
获取代码之后,进入 Pptx 文件夹
更多的特殊逻辑:
如果在 Theme 里面定义的 LineStyleList 里面定义的轮廓没有设置颜色,如下面的 OpenXML 文档
<a:lnStyleLst><a:ln w="6350" cap="flat" cmpd="sng" algn="ctr"><a:solidFill><a:schemeClr val="phClr" /></a:solidFill><a:prstDash val="solid" /><a:miter lim="800000" /></a:ln><a:ln w="12700" cap="flat" cmpd="sng" algn="ctr"><a:prstDash val="solid" /><a:miter lim="800000" /></a:ln><a:ln w="19050" cap="flat" cmpd="sng" algn="ctr"><a:solidFill><a:schemeClr val="phClr" /></a:solidFill><a:prstDash val="solid" /><a:miter lim="800000" /></a:ln></a:lnStyleLst>
在 Slide1.xml 里面的形状定义和上文的相同,引用了第二项的主题,如下面的 OpenXML 文档
<a:lnRef idx="2"><a:schemeClr val="accent1"><a:shade val="50000" /></a:schemeClr></a:lnRef>
此时在 PPT 的运行效果就是没有边框,也就是说在 a:lnRef
定义的 <a:schemeClr val="accent1">
颜色仅仅只是用来作为 PhColor 的替换
更多请看 Office 使用 OpenXML SDK 解析文档博客目录
我搭建了自己的博客 https://blog.lindexi.com/ 欢迎大家访问,里面有很多新的博客。只有在我看到博客写成熟之后才会放在csdn或博客园,但是一旦发布了就不再更新
如果在博客看到有任何不懂的,欢迎交流,我搭建了 dotnet 职业技术学院 欢迎大家加入
如有不方便在博客评论的问题,可以加我 QQ 2844808902 交流
本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。欢迎转载、使用、重新发布,但务必保留文章署名林德熙(包含链接:http://blog.csdn.net/lindexi_gd ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我联系。
dotnet OpenXML 读取 PPT 形状边框定义在 Style 的颜色画刷相关推荐
- dotnet OpenXML 读取 PPT 主序列进入退出强调动画
本文告诉大家如何读取 PPT 文件里面,放在主动画序列 MainSequence 的进入和退出和强调的动画,和在 OpenXML 里面的存放方式 如以下的课件内容,给一个元素添加了进入强调退出的动画, ...
- dotnet OpenXML 读取 PPT 内嵌 ole 格式 Excel 表格的信息
在 Office 中,可以在 PPT 里面插入表格,插入表格有好多不同的方法,对应 OpenXML 文档存储的更多不同的方式.本文来介绍如何读取 PPT 内嵌 ole 格式的 xls+ 表格的方法 在 ...
- C# dotnet 使用 OpenXml 解析 PPT 元素的坐标和宽度高度
在阅读本文之前,我期望你能了解基础的 PPT 解析内容,或看我的入门级博客.本文将告诉大家如何从 PPT 里面解析出通用元素的 x 和 y 的值,以及元素的宽度和高度的值 在开始之前请看 C# dot ...
- C# dotnet 使用 OpenXml 解析 PPT 里面的视频
本文告诉大家如何从 PPTX 文件里面解析出视频 我期望看到本文的小伙伴是了解 OpenXML 的,如果想要解析 Office 的文档,我推荐使用使用 OpenXML SDK 这个开源的库,更多入门级 ...
- php ppt read_PHP读取PPT文件的方法
本文实例讲述了PHP读取PPT文件的方法.分享给大家供大家参考,具体如下: 最近做一个和FLASH有关的东西,其中就要用到在网站上看PPT就像百度,豆丁网那样可以直接在网站上读,在网上搜了半天没搜到, ...
- 读取PPT模板替换数据生成PDF报表
一.项目背景 因本人的公司是做短信通信服务的,所以客户需要将短信的发送量,按照他们给定的PPT样例模板,来生成PDF报表数据,即PPT的样式,数据如何展示都是规定好了的,而我需要做的就是将真实的数据, ...
- php ppt read_php怎么读取ppt文字内容并在浏览器中显示出来?
具体代码麻烦我就不写了,可以提供给你一个思路:首先要求服务器上安装wps或者microsoft powerpoint软件,然后通过api接口来访问并读取ppt,最后将其发送到页面.当然你不能每次等别人 ...
- java 创建ppt文件怎么打开文件,JAVA读取PPT文件
JAVA读取PPT文件 import java.io.InputStream; import org.apache.lucene.document.Document; import org.apach ...
- java 读取ppt_Java 读取PPT文本和图片
本篇文章将介绍通过Java程序来读取PPT幻灯片中的文本及图片的方法.读取图片时,可读取文档中的所有图片,也可以读取指定幻灯片当中的图片. 工具:Free Spire.Presentation for ...
最新文章
- java wed登录面 代码_java web 登录界面
- ‘numpy.float64‘ object cannot be interpreted as an integer
- Linux 打开/关闭CPU命令
- 2017年 第08届 蓝桥杯 Java B组 决赛真题详解及小结
- vs.net 2003 错误:无法生成项目输出组“内容文件来自stuschool(活动)”
- NetworkX系列教程(1)-创建graph
- 图解elasticsearch原理转载自
- linux查看正在运行的窗口,获取linux中打开的应用程序窗口的数量
- 【OpenCV学习笔记】【函数学习】十七(imread()函数)
- java代码生成UUID以及在线UUID生成器
- Android 开发神器系列(工具篇)之 Android 屏幕共享工具
- 机器学习基础(二)——训练集和测试集的划分
- R Shiny module学习笔记
- [转]Linux面试题(2020最新版)
- eclipse hana xs 开发环境搭建
- 如何导入和导出Maven项目(分享给别人源码)
- 滑雪(广搜+记忆数组+STL)
- 网络篇 网络设备的基本配置09
- 基于FPGA的高空坠物跟踪和预警系统
- c语言ATM机文件储存账号密码,C语言ATM(有文件输入输出).doc