Shadow¶
Shadow is inherited, and a shape often appears with a shadow without explicitly applying a shadow format.
The only difference in a shape with shadow turned off is the presence of an empty <a:effectLst/> child in its <p:spPr> element. Inherited shadow is turned off when p:spPr/a:effectLst is present with no a:outerShdw child element. Other effect child elements may be present.
A shadow is one type of “effect”. The others are glow/soft-edges and reflection.
Shadow may be of type outer (perhaps most common), inner, or perspective.
Scope¶
Shape.shadow is a ShadowFormat object (all shape types)
shape.shadow.inherit = True removes any explicitly applied effects (including glow/soft-edge and reflection, not just shadow). This restores the “inherit” state for effects and makes the shape sensitive to changes in theme.
shape.shadow.inherit = False overrides any default (theme) effects. Any inherited shadow, glow, and/or reflection will no longer appear. This operation adds an empty effects element, which causes no effects to be applied, regardless of theme settings.
Out-of-scope
Minimum for specifying a basic shadow
ShadowFormat.visible - applies a reasonable standard shadow override.
ShadowFormat.shadow_type (inner, outer, perspective)
ShadowFormat.alignment (shadow anchor, automatic based on angle)
ShadowFormat.angle (0-degrees is to the right, increasing CCW)
ShadowFormat.blur_radius (generally a few points, maybe 3-5)
ShadowFormat.color (theme or RGB color)
ColorFormat.transparency (needed for proper shadow rendering)
ShadowFormat.distance (generally a couple points, maybe 1-3)
shape.shadow.style (MSO_SHADOW_STYLE) indicates whether shadow is inner, outer, or perspective (or None).
Nice to have for finer tuning
ShadowFormat.rotate_with_shape (boolean)
ShadowFormat.scale (shadow bigger/smaller than shape, default 100%)
Retaining non-shadow effects when turning off shadow. This requires the ability to “clone” the currently enabled defaults. Effects are not inherited separately; making explicit the currently active default is how PowerPoint works around the “all-or-nothing” inheritance behavior.
Clone effective shadow, glow, and/or reflection.
Protocol¶
The .shadow property on a shape always returns the ShadowFormat object for that shape, regardless of whether its shadow is explicit or inherited:
>>> shape = prs.slides[0].shapes[0]
>>> shadow = shape.shadow
>>> shadow
<pptx.dml.effect.ShadowFormat object at 0x108080490>
The .shadow property is idempotent, meaning the same ShadowFormat object (verified by comparing ID) is returned on every call, for the lifetime of the shape object:
>>> shape.shadow
<pptx.dml.effect.ShadowFormat object at 0x108080490>
>>> shape.shadow
<pptx.dml.effect.ShadowFormat object at 0x108080490>
The ShadowFormat.inherit property indicates whether the shape inherits its shadow effect or overrides it with an explicitly defined setting. The default setting for a new shape is True:
>>> shadow.inherit
True
Assigning False breaks the inheritance link by explicitly defining a “no-shadow” setting for the shape. This causes the shape to appear without a shadow, regardless of the applied theme:
>>> shadow.inherit = False
>>> shadow.inherit
False
Note that this has the side-effect of disabling inheritance of all effects for that shape.
PowerPoint behaviors¶
All 5 shape-types can display a shadow, but graphics-frame objects like chart and table use a different mechanism than the other shapes. Those won’t be supported initially.
AutoShape
Connector
Picture
Group Shape (parent is p:grpSpPr rather than p:spPr)
Graphics Frame (UI allows, but uses a different mechanism)
Adding shadow to a group shape adds that shadow to each component shape in the group.
There is a “new-shape format” concept. This format determines what a new shape looks like, but does not change the appearance of shapes already in place. It’s basically a template imprinted on new shapes when they are added.
Theme Effects are a thing here. They are Subtle, Moderate, and Intense.
There are 40 built-in theme effects. Each of these have …
Setting visible off (Format Shape > Shadow > Clear Shadow checkbox) for a customized shadow removes all customized settings and they are not recoverable by setting the shadow visible again (clicking the shadow checkbox).
MS API¶
ShadowFormat object¶
ShadowFormat.Visible
Specimen XML¶
Shape inheriting shadow. Note the absence of p:spPr/a:effectLst, causing all effects to be inherited:
<p:sp>
<p:nvSpPr>
<p:cNvPr id="4" name="Rounded Rectangle 3"/>
<p:cNvSpPr/>
<p:nvPr/>
</p:nvSpPr>
<p:spPr>
<a:xfrm>
<a:off x="4114800" y="2971800"/>
<a:ext cx="914400" cy="914400"/>
</a:xfrm>
<a:prstGeom prst="roundRect">
<a:avLst/>
</a:prstGeom>
</p:spPr>
<p:style>
<a:lnRef idx="1">
<a:schemeClr val="accent1"/>
</a:lnRef>
<a:fillRef idx="3">
<a:schemeClr val="accent1"/>
</a:fillRef>
<a:effectRef idx="2">
<a:schemeClr val="accent1"/>
</a:effectRef>
<a:fontRef idx="minor">
<a:schemeClr val="lt1"/>
</a:fontRef>
</p:style>
<p:txBody>
<a:bodyPr rtlCol="0" anchor="ctr"/>
<a:lstStyle/>
<a:p>
<a:pPr algn="ctr"/>
<a:endParaRPr lang="en-US"/>
</a:p>
</p:txBody>
</p:sp>
Shape with inherited shadow turned off:
<p:sp>
<p:nvSpPr>
<p:cNvPr id="4" name="Rounded Rectangle 3"/>
<p:cNvSpPr/>
<p:nvPr/>
</p:nvSpPr>
<p:spPr>
<a:xfrm>
<a:off x="4114800" y="2971800"/>
<a:ext cx="914400" cy="914400"/>
</a:xfrm>
<a:prstGeom prst="roundRect">
<a:avLst/>
</a:prstGeom>
<a:effectLst/>
</p:spPr>
<p:style>
<a:lnRef idx="1">
<a:schemeClr val="accent1"/>
</a:lnRef>
<a:fillRef idx="3">
<a:schemeClr val="accent1"/>
</a:fillRef>
<a:effectRef idx="2">
<a:schemeClr val="accent1"/>
</a:effectRef>
<a:fontRef idx="minor">
<a:schemeClr val="lt1"/>
</a:fontRef>
</p:style>
<p:txBody>
<a:bodyPr rtlCol="0" anchor="ctr"/>
<a:lstStyle/>
<a:p>
<a:pPr algn="ctr"/>
<a:endParaRPr lang="en-US"/>
</a:p>
</p:txBody>
</p:sp>
XML Semantics¶
Effect inheritance is “all-or-nothing”
If p:spPr/a:effectLst is present, all desired effects must be specified explicitly as its children; a missing child, such as a:outerShdw, will cause that effect to be turned off. PowerPoint automatically adds those populated with inherited values when one of the effects is customized, necessitating that addition of an a:effectLst element.
Theme sub-tree a:theme/a:objectDefaults/a:spDef/a:style/a:effectRef/idx=2 specifies that new objects will get the second effect in a:theme/a:themeElements/a:fmtScheme/a:effectStyleLst. That effect looks like this:
<a:effectStyle> <a:effectLst> <a:outerShdw blurRad="40000" dist="23000" dir="5400000" rotWithShape="0"> <a:srgbClr val="000000"> <a:alpha val="35000"/> </a:srgbClr> </a:outerShdw> </a:effectLst> </a:effectStyle>
Schema excerpt¶
<xsd:complexType name="CT_Shape"> <!-- p:sp element -->
<xsd:sequence>
<xsd:element name="nvSpPr" type="CT_ShapeNonVisual"/>
<xsd:element name="spPr" type="a:CT_ShapeProperties"/>
<xsd:element name="style" type="a:CT_ShapeStyle" minOccurs="0"/>
<xsd:element name="txBody" type="a:CT_TextBody" minOccurs="0"/>
<xsd:element name="extLst" type="CT_ExtensionListModify" minOccurs="0"/>
</xsd:sequence>
<xsd:attribute name="useBgFill" type="xsd:boolean" default="false"/>
</xsd:complexType>
<xsd:complexType name="CT_ShapeProperties"> <!--denormalized-->
<xsd:sequence>
<xsd:element name="xfrm" type="CT_Transform2D" minOccurs="0"/>
<xsd:group ref ="EG_Geometry" minOccurs="0"/>
<xsd:group ref ="EG_FillProperties" minOccurs="0"/>
<xsd:element name="ln" type="CT_LineProperties" minOccurs="0"/>
<xsd:choice minOccurs="0"/> <!--EG_EffectProperties-->
<xsd:element name="effectLst" type="CT_EffectList"/>
<xsd:element name="effectDag" type="CT_EffectContainer"/>
</xsd:choice>
<xsd:element name="scene3d" type="CT_Scene3D" minOccurs="0"/>
<xsd:element name="sp3d" type="CT_Shape3D" minOccurs="0"/>
<xsd:element name="extLst" type="CT_OfficeArtExtensionList" minOccurs="0"/>
</xsd:sequence>
<xsd:attribute name="bwMode" type="ST_BlackWhiteMode"/>
</xsd:complexType>
<xsd:complexType name="CT_EffectList">
<xsd:sequence>
<xsd:element name="blur" type="CT_BlurEffect" minOccurs="0"/>
<xsd:element name="fillOverlay" type="CT_FillOverlayEffect" minOccurs="0"/>
<xsd:element name="glow" type="CT_GlowEffect" minOccurs="0"/>
<xsd:element name="innerShdw" type="CT_InnerShadowEffect" minOccurs="0"/>
<xsd:element name="outerShdw" type="CT_OuterShadowEffect" minOccurs="0"/>
<xsd:element name="prstShdw" type="CT_PresetShadowEffect" minOccurs="0"/>
<xsd:element name="reflection" type="CT_ReflectionEffect" minOccurs="0"/>
<xsd:element name="softEdge" type="CT_SoftEdgesEffect" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="CT_OuterShadowEffect">
<xsd:sequence>
<xsd:group ref="EG_ColorChoice" minOccurs="1" maxOccurs="1"/>
</xsd:sequence>
<xsd:attribute name="blurRad" type="ST_PositiveCoordinate" default="0"/>
<xsd:attribute name="dist" type="ST_PositiveCoordinate" default="0"/>
<xsd:attribute name="dir" type="ST_PositiveFixedAngle" default="0"/>
<xsd:attribute name="sx" type="ST_Percentage" default="100%"/>
<xsd:attribute name="sy" type="ST_Percentage" default="100%"/>
<xsd:attribute name="kx" type="ST_FixedAngle" default="0"/>
<xsd:attribute name="ky" type="ST_FixedAngle" default="0"/>
<xsd:attribute name="algn" type="ST_RectAlignment" default="b"/>
<xsd:attribute name="rotWithShape" type="xsd:boolean" default="true"/>
</xsd:complexType>
<xsd:simpleType name="ST_RectAlignment">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="tl"/>
<xsd:enumeration value="t"/>
<xsd:enumeration value="tr"/>
<xsd:enumeration value="l"/>
<xsd:enumeration value="ctr"/>
<xsd:enumeration value="r"/>
<xsd:enumeration value="bl"/>
<xsd:enumeration value="b"/>
<xsd:enumeration value="br"/>
</xsd:restriction>
</xsd:simpleType>