本文是使用 WPF 做个 PowerPoint 系列的博客,本文来告诉大家如何解析 PPT 里面的文本描边效果,在 WPF 应用中绘制出来,实现像素级相同

背景知识

在开始之前,期望你了解了 PPT 解析的入门知识。如对 PPT 解析了解很少,请参阅 C# dotnet 使用 OpenXml 解析 PPT 文件

在 PPT 里面可以给文本的某些文字设置描边效果,描边效果从 OpenXML 层上是不属于特效的,只是属于边框属性。在 PPT 里面,可以给文本加上 Outline 边框属性,从而让文字描边

效果

开始之前,先让大家看一下效果

解析

开始之前,先进行读取文档,代码如下。以下代码和测试文件,都可以在本文末尾获取

            var file = new FileInfo("Test.pptx");

            using var presentationDocument = PresentationDocument.Open(file.FullName, false);
var slide = presentationDocument.PresentationPart!.SlideParts.First().Slide;

本文以下代码,为了方便告诉大家核心部分逻辑,将根据 Test.pptx 文档进行忽略很多参数的判断。在实际项目中,还请大家自行进行参数判断逻辑

此测试文档在第一页只有一个元素,就是本文的加文本描边的元素,获取的代码如下

            var shape = slide.CommonSlideData!.ShapeTree!.GetFirstChild<Shape>()!;

此 Shape 的 OpenXML 内容大概如下

 <p:sp>
<p:spPr>
<a:prstGeom prst="rect">
</a:prstGeom>
<a:noFill />
</p:spPr>
<p:txBody>
<a:bodyPr wrap="square" rtlCol="0">
<a:spAutoFit />
</a:bodyPr>
<a:lstStyle />
<a:p>
<a:r>
<a:rPr lang="zh-CN" altLang="en-US" sz="10000">
<a:ln w="9525">
<a:solidFill>
<a:srgbClr val="00FF00" />
</a:solidFill>
</a:ln>
</a:rPr>
<a:t>一行文本</a:t>
</a:r>
<a:endParaRPr lang="en-US" sz="10000" dirty="0" />
</a:p>
</p:txBody>
</p:sp>

在 PPT 里面的文本框也是形状,是默认的矩形

            var shapeProperties = shape.ShapeProperties!;
var presetGeometry = shapeProperties.GetFirstChild<PresetGeometry>()!;
// 这是一个文本框
Debug.Assert(presetGeometry.Preset?.Value == ShapeTypeValues.Rectangle);
Debug.Assert(shapeProperties.GetFirstChild<NoFill>() is not null);

以上只是告诉大家可以如何获取形状,需要在自己的业务代码里面,进行判断

获取文本框的文本,可以使用如下代码

            var textBody = shape.TextBody!;
Debug.Assert(textBody != null);

一个文本里面有很多段落,段落里面,文本有不同的样式,如一段可以有不同加粗的文本。相同的样式的文本放在一个 TextRun 里面。不同的样式的文本放在不同的 TextRun 里面

因此解析需要先遍历段落,再遍历 TextRun 元素

            foreach (var paragraph in textBody.Elements<DocumentFormat.OpenXml.Drawing.Paragraph>())
{
// 这个文本段落是没有属性的,为了方便样式,就不写代码
//if (paragraph.ParagraphProperties != null) foreach (var run in paragraph.Elements<DocumentFormat.OpenXml.Drawing.Run>())
{
}
}

获取 TextRun 的属性如下

   var runProperties = run.RunProperties!;

此属性上可以拿到当前文本的字号等信息,代码如下

   var fontSize = new PoundHundredfold(runProperties.FontSize!.Value).ToPound();

接下来是本文的核心,获取 Outline 属性,代码如下

      var outline = runProperties.Outline!;

对应的 OpenXML 代码如下

 <a:ln w="9525">
<a:solidFill>
<a:srgbClr val="00FF00" />
</a:solidFill>
</a:ln>

咱所关注基本只有粗细和颜色,获取方法分别如下

     var outlineWidth = new Emu(outline.Width!.Value);

获取颜色的代码如下

                    var solidFill = outline.GetFirstChild<SolidFill>()!;
var rgbColorModelHex = solidFill.GetFirstChild<RgbColorModelHex>()!;
var colorText = rgbColorModelHex.Val!;

通过 win10 uwp 颜色转换 的方法可以将 colorText 转换为 SolidColorBrush 对象

再获取文本内容,大概就完成了

                    // 默认字体前景色是黑色

                    var text = run.Text!.Text;

接下来就是在界面绘制

绘制

如 WPF 文字描边 博客,先通过 FormattedText 构建出 Geometry 对象,再通过 Geometry 对象进行绘制

代码如下

                    var formattedText = new FormattedText(text, CultureInfo.CurrentCulture,
FlowDirection.LeftToRight,
new Typeface
(
// 默认是宋体
new FontFamily("宋体"),
FontStyles.Normal,
FontWeights.Normal,
FontStretches.Normal
),
// 在 WPF 里面,采用的是 EM 单位,约等于像素单位
fontSize.ToPixel().Value,
Brushes.Black, 96);

通过 FormattedText 构建出 Geometry 对象代码如下

                    var geometry = formattedText.BuildGeometry(new ());

接着通过 System.Windows.Shapes.Path 将 Geometry 绘制到界面上

                    var path = new System.Windows.Shapes.Path
{
Data = geometry,
Fill = Brushes.Black,
Stroke = BrushCreator.CreateSolidColorBrush(colorText),
StrokeThickness = outlineWidth.ToPixel().Value, HorizontalAlignment = HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Center,
}; Root.Children.Add(path);

通过以上代码,即可在界面画出和 PPT 一样的界面

代码

本文所有代码和测试文件放在github 和 gitee 欢迎访问

可以通过如下方式获取本文的源代码,先创建一个空文件夹,接着使用命令行 cd 命令进入此空文件夹,在命令行里面输入以下代码,即可获取到本文的代码

git init
git remote add origin https://gitee.com/lindexi/lindexi_gd.git
git pull origin 71af5b0e47493ff7f5f43be33583265805da9d84

以上使用的是 gitee 的源,如果 gitee 不能访问,请替换为 github 的源

git remote remove origin
git remote add origin https://github.com/lindexi/lindexi_gd.git

获取代码之后,进入 Pptx 文件夹

参考

WPF 文字描边

更多请看 Office 使用 OpenXML SDK 解析文档博客目录

使用 WPF 做个 PowerPoint 系列 基于 OpenXML 解析实现 PPT 文本描边效果的更多相关文章

  1. 重复造轮子系列——基于FastReport设计打印模板实现桌面端WPF套打和商超POS高度自适应小票打印

    重复造轮子系列——基于FastReport设计打印模板实现桌面端WPF套打和商超POS高度自适应小票打印 一.引言 桌面端系统经常需要对接各种硬件设备,比如扫描器.读卡器.打印机等. 这里介绍下桌面端 ...

  2. WPF Step By Step 系列-Prism框架在项目中使用

    WPF Step By Step 系列-Prism框架在项目中使用 回顾 上一篇,我们介绍了关于控件模板的用法,本节我们将继续说明WPF更加实用的内容,在大型的项目中如何使用Prism框架,并给予Pr ...

  3. WPF Step By Step 系列 - 开篇 ·

    WPF Step By Step 系列 - 开篇 公司最近要去我去整理出一个完整的WPF培训的教程,我刚好将自己学习WPF的过程和经验总结整理成笔记的方式来讲述,这里就不按照书上面的东西来说了,书本上 ...

  4. .NET Core 3 WPF MVVM框架 Prism系列之命令

    本文将介绍如何在.NET Core3环境下使用MVVM框架Prism的命令的用法 一.创建DelegateCommand命令 我们在上一篇.NET Core 3 WPF MVVM框架 Prism系列之 ...

  5. WPF快速入门系列(4)——深入解析WPF绑定

    一.引言 WPF绑定使得原本需要多行代码实现的功能,现在只需要简单的XAML代码就可以完成之前多行后台代码实现的功能.WPF绑定可以理解为一种关系,该关系告诉WPF从一个源对象提取一些信息,并将这些信 ...

  6. JS组件系列——基于Bootstrap Ace模板的菜单Tab页效果优化

    前言:之前发表过一篇  JS组件系列——基于Bootstrap Ace模板的菜单和Tab页效果分享(你值得拥有) ,收到很多园友的反馈,当然也包括很多诟病,因为上篇只是将功能实现了,很多细节都没有处理 ...

  7. 通通WPF随笔(1)——基于lucene.NET让ComboBox拥有强大的下拉联想功能

    原文:通通WPF随笔(1)--基于lucene.NET让ComboBox拥有强大的下拉联想功能 我一直很疑惑百度.谷哥搜索框的下拉联想功能是怎么实现的?是不断地查询数据库吗?其实到现在我也不知道,他们 ...

  8. 重复造轮子系列——基于Ocelot实现类似支付宝接口模式的网关

    重复造轮子系列——基于Ocelot实现类似支付宝接口模式的网关 引言 重复造轮子系列是自己平时的一些总结.有的轮子依赖社区提供的轮子为基础,这里把使用过程的一些觉得有意思的做个分享.有些思路或者方法在 ...

  9. .NET Core 3 WPF MVVM框架 Prism系列之事件聚合器

    本文将介绍如何在.NET Core3环境下使用MVVM框架Prism的使用事件聚合器实现模块间的通信 一.事件聚合器  在上一篇 .NET Core 3 WPF MVVM框架 Prism系列之模块化 ...

随机推荐

  1. [atARC101F]Robots and Exits

    每一个点一定匹配其左边/右边的第一个出口(在最左/右边的出口左/右边的点直接删除即可),否则记到左右出口的距离分别为$x_{i}$和$y_{i}$ 令$p_{i}$表示$i$匹配的出口(左0右1),结 ...

  2. 第05章 MySQL排序与分页

    第05章 MySQL排序与分页 1. 排序数据 1.1 排序规则 使用 ORDER BY 子句排序 ASC(ascend): 升序 DESC(descend):降序 ORDER BY 子句在SELEC ...

  3. 查询多个count展示结果

    <select id="getCountByDISC" resultType="com.rm.algo.entity.AlgoResult"> SE ...

  4. Maven pom常用plugins配置说明

    maven-compiler-plugin 编译Java源码,一般只需设置编译的jdk版本 <plugin> <groupId>org.apache.maven.plugins ...

  5. Codeforces 840E - In a Trap(树分块+trie)

    Codeforces 题面传送门 & 洛谷题面传送门 一道非常精彩,同时也很经典的题目.和这场的 C 一样经典 首先看到这个数据范围先猜正解复杂度:\(n\) 级别大于 \(q\),所以大概是 ...

  6. 洛谷 P6672 - [清华集训2016] 你的生命已如风中残烛(组合数学)

    洛谷题面传送门 题解里一堆密密麻麻的 Raney 引理--蒟蒻表示看不懂,因此决定写一篇题解提供一个像我这样的蒟蒻能理解的思路,或者说,理解方式. 首先我们考虑什么样的牌堆顺序符合条件.显然,在摸牌任 ...

  7. Python三元表达式,列表推导式,字典生成式

    目录 1. 三元表达式 2. 列表推导式 3. 字典生成式 3.1 字典生成式 3.2 zip()方法 1. 三元表达式 """ 条件成立时的返回值 if 条件 else ...

  8. rsync实现windows和windows之间的数据同步

    一:环境 1.同步对象:测试数据 2.服务端:Windows Server 2008 R2 3.客户端:Windows7 旗舰版64位 4.服务端rsync版本:cwRsyncServer_4.1.0 ...

  9. 使用C语言来扩展PHP,写PHP扩展dll

    转自http://www.cnblogs.com/myths/archive/2011/11/28/2266593.html 以前写过一次PHP扩展DLL,那个是利用调用系统的COM口实现的扩展,与P ...

  10. android studio Please configure Android SDK / please select Android SDK

    有可能是sdk文件损坏造成的. file->settings->appearance&behavior->system settings->android sdk-&g ...