使用 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 ),不得用於商業目的,基於本文修改後的作品務必以相同的許可發佈。如有任何疑問,請與我聯繫

繼續探索

延伸閱讀

更多文章
同分類 / 同標籤 2025/1/26

WPF 藉助自訂 XML 檔案實現國際化

本文詳細介紹了在WPF程式中使用自訂XML檔案實現國際化的方法,包括安裝必備NuGet套件、動態獲取語言清單、動態切換語言、在程式碼和XAML介面中使用翻譯字串等內容,同時提供了原始碼連結,幫助開發者輕鬆實現WPF應用程式的國際化。

繼續閱讀