Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions src/pptx/dml/color.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,20 @@ def brightness(self, value):
self._validate_brightness_value(value)
self._color.brightness = value

@property
def transparency(self):
"""Read/write float value between 0.0 and 1.0 indicating color transparency.

0.0 is completely opaque and 1.0 is completely transparent. 0.5 is 50%
transparent. Returns 0.0 when the color is undefined (i.e. of type None).
"""
return self._color.transparency

@transparency.setter
def transparency(self, value):
self._validate_transparency_value(value)
self._color.transparency = value

@classmethod
def from_colorchoice_parent(cls, eg_colorChoice_parent):
xClr = eg_colorChoice_parent.eg_colorChoice
Expand Down Expand Up @@ -105,6 +119,16 @@ def _validate_brightness_value(self, value):
)
raise ValueError(msg)

def _validate_transparency_value(self, value):
if value < 0.0 or value > 1.0:
raise ValueError("transparency must be number in range 0.0 to 1.0")
if isinstance(self._color, _NoneColor):
msg = (
"can't set transparency when color.type is None. "
"Set color.rgb or .theme_color first."
)
raise ValueError(msg)


class _Color(object):
"""
Expand Down Expand Up @@ -152,6 +176,35 @@ def brightness(self, value):
else:
self._xClr.clear_lum()

@property
def transparency(self):
"""Read/write float value between 0.0 and 1.0 indicating color transparency.

Returns 0.0 (fully opaque) when no <a:alpha> child is present, or for the
None-color sentinel.
"""
if self._xClr is None:
return 0.0
alpha = self._xClr.alpha
if alpha is not None:
return 1.0 - alpha.val
return 0.0

@transparency.setter
def transparency(self, value):
if self._xClr is None:
msg = (
"can't set transparency when color.type is None. "
"Set color.rgb or .theme_color first."
)
raise ValueError(msg)
if value == 0.0:
self._xClr.clear_alpha()
else:
alpha_val = 1.0 - value
self._xClr.clear_alpha()
self._xClr.add_alpha(alpha_val)

@property
def color_type(self): # pragma: no cover
tmpl = ".color_type property must be implemented on %s"
Expand Down
37 changes: 37 additions & 0 deletions src/pptx/dml/fill.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,20 @@ def fore_color(self):
"""
return self._fill.fore_color

@property
def transparency(self):
"""Read/write float value between 0.0 and 1.0 indicating fill transparency.

0.0 is completely opaque and 1.0 is completely transparent. 0.5 is 50%
transparent. Only applicable to solid fills; raises |TypeError| for
gradient, pattern, blip, group, or no-fill types.
"""
return self._fill.transparency

@transparency.setter
def transparency(self, value):
self._fill.transparency = value

def gradient(self):
"""Sets the fill type to gradient.

Expand Down Expand Up @@ -205,6 +219,17 @@ def pattern(self):
tmpl = "fill type %s has no pattern, call .patterned() first"
raise TypeError(tmpl % self.__class__.__name__)

@property
def transparency(self):
"""Raise TypeError for fills that do not override this property."""
tmpl = "fill type %s has no transparency, call .solid() first"
raise TypeError(tmpl % self.__class__.__name__)

@transparency.setter
def transparency(self, value):
tmpl = "fill type %s has no transparency, call .solid() first"
raise TypeError(tmpl % self.__class__.__name__)

@property
def type(self) -> MSO_FILL_TYPE: # pragma: no cover
raise NotImplementedError(
Expand Down Expand Up @@ -343,6 +368,18 @@ def fore_color(self):
"""Return |ColorFormat| object controlling fill color."""
return ColorFormat.from_colorchoice_parent(self._solidFill)

@property
def transparency(self):
"""Read/write float value between 0.0 and 1.0 indicating solid-fill transparency.

Delegates to the |ColorFormat| of `fore_color`.
"""
return self.fore_color.transparency

@transparency.setter
def transparency(self, value):
self.fore_color.transparency = value

@property
def type(self):
return MSO_FILL.SOLID
Expand Down
4 changes: 4 additions & 0 deletions src/pptx/oxml/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -251,13 +251,17 @@ def register_element_cls(nsptagname: str, cls: Type[BaseOxmlElement]):
CT_Color,
CT_HslColor,
CT_Percentage,
CT_PositiveFixedPercentage,
CT_PresetColor,
CT_SchemeColor,
CT_ScRgbColor,
CT_SRgbColor,
CT_SystemColor,
)

register_element_cls("a:alpha", CT_PositiveFixedPercentage)
register_element_cls("a:alphaMod", CT_PositiveFixedPercentage)
register_element_cls("a:alphaOff", CT_PositiveFixedPercentage)
register_element_cls("a:bgClr", CT_Color)
register_element_cls("a:fgClr", CT_Color)
register_element_cls("a:hslClr", CT_HslColor)
Expand Down
36 changes: 35 additions & 1 deletion src/pptx/oxml/dml/color.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from __future__ import annotations

from pptx.enum.dml import MSO_THEME_COLOR
from pptx.oxml.simpletypes import ST_HexColorRGB, ST_Percentage
from pptx.oxml.simpletypes import ST_HexColorRGB, ST_Percentage, ST_PositiveFixedPercentage
from pptx.oxml.xmlchemy import (
BaseOxmlElement,
Choice,
Expand All @@ -20,6 +20,9 @@ class _BaseColorElement(BaseOxmlElement):

lumMod = ZeroOrOne("a:lumMod")
lumOff = ZeroOrOne("a:lumOff")
alpha = ZeroOrOne("a:alpha")
alphaMod = ZeroOrOne("a:alphaMod")
alphaOff = ZeroOrOne("a:alphaOff")

def add_lumMod(self, value):
"""
Expand All @@ -37,6 +40,24 @@ def add_lumOff(self, value):
lumOff.val = value
return lumOff

def add_alpha(self, value):
"""Return a newly added <a:alpha> child element."""
alpha = self._add_alpha()
alpha.val = value
return alpha

def add_alphaMod(self, value):
"""Return a newly added <a:alphaMod> child element."""
alphaMod = self._add_alphaMod()
alphaMod.val = value
return alphaMod

def add_alphaOff(self, value):
"""Return a newly added <a:alphaOff> child element."""
alphaOff = self._add_alphaOff()
alphaOff.val = value
return alphaOff

def clear_lum(self):
"""
Return self after removing any <a:lumMod> and <a:lumOff> child
Expand All @@ -46,6 +67,13 @@ def clear_lum(self):
self._remove_lumOff()
return self

def clear_alpha(self):
"""Return self after removing any <a:alpha>, <a:alphaMod>, <a:alphaOff> children."""
self._remove_alpha()
self._remove_alphaMod()
self._remove_alphaOff()
return self


class CT_Color(BaseOxmlElement):
"""Custom element class for `a:fgClr`, `a:bgClr` and perhaps others."""
Expand Down Expand Up @@ -77,6 +105,12 @@ class CT_Percentage(BaseOxmlElement):
val = RequiredAttribute("val", ST_Percentage)


class CT_PositiveFixedPercentage(BaseOxmlElement):
"""Custom element class for <a:alpha>, <a:alphaMod>, and <a:alphaOff> elements."""

val = RequiredAttribute("val", ST_PositiveFixedPercentage)


class CT_PresetColor(_BaseColorElement):
"""
Custom element class for <a:prstClr> element.
Expand Down
Loading
Loading