使用 wpf 做個 powerpoint 系列 基於 openxml 解析實現 ppt 文本描邊效果

使用 wpf 做個 powerpoint 系列 基於 openxml 解析實現 ppt 文本描邊效果

本文是使用 wpf 做個 powerpoint 系列的博客,本文來告訴大家如何解析 ppt 裡面的文本描邊效果,在 wpf 應用中繪製出來,實現像素級相同

最后更新 2021/12/18 下午6:24
lindexi
预计阅读 6 分钟
分类
WPF
标签
.NET WPF OpenXML

本文是使用 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 一樣的界面

代碼

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

可以通過如下方式獲取本文的原始碼,先創建一個空文件夾,接著使用命令行 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 文件夾

參考

  1. WPF 文字描边
  2. 更多请看 Office 使用 OpenXML SDK 解析文档博客目录

博客園博客只做備份,博客發布就不再更新,如果想看最新博客,請到https://blog.lindexi.com/

知識共享許可協議

本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名林德熙(包含链接:http://blog.csdn.net/lindexi_gd ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我联系

Keep Exploring

延伸阅读

更多文章
同分类 / 同标签 2025/1/26

wpf 藉助自定義 xml 文件實現國際化

本文詳細居間了在wpf程式中使用自定義xml文件實現國際化的方法,包括安裝必備nuget包、動態獲取語言列表、動態切換語言、在代碼和xaml界面中使用翻譯字符串等內容,同時提供了源碼連結,幫助開發者輕鬆實現wpf應用的國際化。

继续阅读