1. 程式人生 > 其它 >使用 WPF 做個 PowerPoint 系列 基於 OpenXML 解析實現 PPT 文字描邊效果

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

本文是使用 WPF 做個 PowerPoint 系列的部落格,本文來告訴大家如何解析 PPT 裡面的文字描邊效果,在 WPF 應用中繪製出來,實現畫素級相同

本文是使用 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 解析文件部落格目錄

部落格園部落格只做備份,部落格釋出就不再更新,如果想看最新部落格,請到 https://blog.lindexi.com/


本作品採用知識共享署名-非商業性使用-相同方式共享 4.0 國際許可協議進行許可。歡迎轉載、使用、重新發布,但務必保留文章署名[林德熙](http://blog.csdn.net/lindexi_gd)(包含連結:http://blog.csdn.net/lindexi_gd ),不得用於商業目的,基於本文修改後的作品務必以相同的許可釋出。如有任何疑問,請與我[聯絡](mailto:[email protected])。