Theme color for dotnet OpenXml SDK shape fill gradients

Keywords: Attribute SDK xml

In some interesting designs of Office documents, colors and brushes are inheritable, and this inheritance includes inheritance of attributes.Gradient colors used in shape filling are properties that can be put into a theme. The brush inside the theme is mainly found, replacing the content defined by the shape itself, which is the brush of the shape.

I get an interesting courseware from which I can see that ShapeProperties inside a Shape element define the GradientFill attribute

// OpenXmlElementList element
var gradientFill = element.First<GradientFill>();

The GradientStopList value for this gradientFill is empty

if (gradientFill.GradientStopList != null)
{

}

adopt Office Open XML - DrawingML - Shapes - Gradient Fill As you know, this GradientStopList is used to define the color of a gradient, that is, the value is empty then the gradient will lose color, that is, the shape filling will lose the gradient color

From the document, there is no value for gsLst in the shape attribute definition

<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>

That is, a:gradFill does not contain a:gsLst value, that is, no a:gs defined color

The problem is that there is no GradientStopList value in the OpenXML a:gradFill without a:gsLst gradient

The ShapeStyle value is normally visible in this shape, and one of the attributes within this value is the FillReference representation style fill

<p:style>
	<a:fillRef idx="2">
		<a:schemeClr val="accent3"/>
	</a:fillRef>
</p:style>

The attribute required for this style is the idx attribute, indicating which style belongs to the theme

Then how to get themes in the OpenXML SDK, if an element on the Slide page can get themes from the code below

// Slide slide
var slidePart = slide.SlidePart;
FormatScheme formatScheme = slidePart?.ThemeOverridePart?.ThemeOverride?.FormatScheme;

Currently, if Slide cannot be taken from SlideLayoutPart, then SlideMasterPart

Then you get the specified element from the FillStyleList of FormatScheme via the idx of the FillReference, noting that idx here uses the subscript from 1.But the array of FillStyleList is C#and the subscript starts with 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);
        }
    }

The GetThemeElement method is implemented as follows

        private static OpenXmlElement GetThemeElement(int index, OpenXmlElementList elements)
        {
            if (index > 0 && elements != null && elements.Count >= index)
            {
                //GetItem is an array of 0 base, so you need to subtract 1
                var xmlElement = elements.GetItem(index - 1);

                return xmlElement;
            }

            return null;
        }

Now you have the OpenXmlElement return value, which is a fill color.There is no base class for fill colors in the OpenXML SDK, which is not well designed

The PPT document corresponds to ppt\theme\Themex.xmlThe value of a:fillStyleLst inside the file

<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>
		<!-- Ignore Code -->

The document above uses idx as the second corresponding to a:fillStyleLst, which is the value of a:gradFill gradient

The a:gsLst of a:gradFill for the theme at this time will be used for shape filling, if the fill color of the shape is also a gradient color, if the gradient color does not set a:gsLst value, then the value of a:gsLst within the theme will be used.Use shape-defined if the shape itself is defined

See the picture below to see how to get it

Most of the inheritance and relationships that exist are written out in the OpenXML SDK, and only those functions that compare corners need to be implemented by themselves

For the behavior of each property of a gradient, see Office Open XML - DrawingML - Shapes - Gradient Fill

See the official documents GradientFill Class (DocumentFormat.OpenXml.Drawing)

Posted by phpstuck on Thu, 21 May 2020 20:28:00 -0700