使用 WPF 做個 PowerPoint 系列 基於 OpenXML 解析實現 PPT 文本描邊效果


本文是使用 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 文件夾

參考

WPF 文字描邊

更多請看 Office 使用 OpenXML SDK 解析文檔博客目錄


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM