在 Office 檔案的一些有趣的設計,顏色和畫刷是可以繼承的,這個繼承包括了屬性的繼承,在形狀填充里面使用的漸變色是可以一部分屬性放在主題里面,主要找到主題里面的畫刷,替換掉形狀自己定義的內容,才是形狀的畫刷
我拿到一份有趣的課件,從這份課件的表現上,可以找到在一個 Shape 元素里面的 ShapeProperties 定義了 GradientFill 屬性
// OpenXmlElementList element
var gradientFill = element.First<GradientFill>();
而這個 gradientFill 的 GradientStopList 的值是空
if (gradientFill.GradientStopList != null)
{
}
通過 Office Open XML - DrawingML - Shapes - Gradient Fill 可以知道,這個 GradientStopList 是用來定義漸變的顏色的,也就是這個值是空那么就是漸變將會丟失顏色,也就是形狀填充丟失漸變色
從檔案上看,形狀屬性定義里面沒有 gsLst 的值
<p:spPr>
<a:xfrm>
<a:off x="611560" y="1059582"/>
<a:ext cx="2120518" cy="645160"/>
</a:xfrm>
<a:prstGeom prst="rect">
<a:avLst/>
</a:prstGeom>
<a:gradFill flip="none" rotWithShape="1">
<a:lin ang="10800000" scaled="1"/>
<a:tileRect/>
</a:gradFill>
</p:spPr>
也就是 a:gradFill 里面不包含 a:gsLst 的值,也就是沒有 a:gs 定義顏色
這個問題是 OpenXML a:gradFill without a:gsLst 漸變色里面沒有 GradientStopList 的值
而在這個形狀一般都可以看到 ShapeStyle 的值,這個值里面有一個屬性是 FillReference 表示樣式里面的填充
<p:style>
<a:fillRef idx="2">
<a:schemeClr val="accent3"/>
</a:fillRef>
</p:style>
而這個樣式要的屬性是 idx 屬性,表示屬于主題的哪個樣式
那么在 OpenXML SDK 里面如何獲取主題,如果是在 Slide 頁面的元素可以通過下面的代碼獲取主題
// Slide slide
var slidePart = slide.SlidePart;
FormatScheme formatScheme = slidePart?.ThemeOverridePart?.ThemeOverride?.FormatScheme;
當前,如果 Slide 拿不到就從 SlideLayoutPart 拿,再拿不到就從 SlideMasterPart 拿
然后是通過 FillReference 的 idx 從 FormatScheme 的 FillStyleList 拿到指定的元素,注意這里的 idx 使用的是從 1 開始的下標,但是 FillStyleList 的陣列是 C# 的陣列,下標是從 0 開始
// FillReference reference, FormatScheme formatScheme
if (reference.Index != null && formatScheme != null)
{
var index = (int) reference.Index.Value;
var openXmlElementList = formatScheme.FillStyleList?.ChildElements;
if (openXmlElementList != null)
{
return GetThemeElement(index, openXmlElementList);
}
}
而 GetThemeElement 方法的實作如下
private static OpenXmlElement GetThemeElement(int index, OpenXmlElementList elements)
{
if (index > 0 && elements != null && elements.Count >= index)
{
//GetItem是0 base的陣列,所以需要減去1
var xmlElement = elements.GetItem(index - 1);
return xmlElement;
}
return null;
}
此時就能拿到 OpenXmlElement 回傳值了,這個 OpenXmlElement 是某個填充顏色,在 OpenXML SDK 里面沒有給填充顏色一個基類,這部分的設計不是很好
在 PPT 檔案里面對應的是 ppt\theme\themex.xml 檔案里面的 a:fillStyleLst 的值
<a:fmtScheme name="Office">
<a:fillStyleLst>
<a:solidFill>
<a:schemeClr val="phClr"/>
</a:solidFill>
<a:gradFill rotWithShape="1">
<a:gsLst>
<a:gs pos="0">
<a:schemeClr val="phClr">
<a:tint val="50000"/>
<a:satMod val="300000"/>
</a:schemeClr>
</a:gs>
<a:gs pos="35000">
<a:schemeClr val="phClr">
<a:tint val="37000"/>
<a:satMod val="300000"/>
</a:schemeClr>
</a:gs>
<a:gs pos="100000">
<a:schemeClr val="phClr">
<a:tint val="15000"/>
<a:satMod val="350000"/>
</a:schemeClr>
</a:gs>
</a:gsLst>
<a:lin ang="16200000" scaled="1"/>
</a:gradFill>
<!-- 忽略代碼 -->
上面檔案里面用的是 idx 是 2 也就是對應 a:fillStyleLst 的第二項,也就是 a:gradFill 漸變的值
此時的主題的 a:gradFill 的 a:gsLst 將會被形狀的填充用到,如果形狀的填充的顏色也是漸變色,如果這個漸變色沒有設定 a:gsLst 的值,那么將會采用主題里面的 a:gsLst 的值,如果形狀自己定義了就使用形狀定義的

請看下圖就知道如何獲取

大部分的存在繼承關系和聯系的都在 OpenXML SDK 里面寫出來關系了,只有這些比較邊角的功能需要自己實作
而漸變色的各個屬性的行為請看 Office Open XML - DrawingML - Shapes - Gradient Fill
官方檔案請看 GradientFill Class (DocumentFormat.OpenXml.Drawing)
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/27078.html
標籤:.NET Core
