Skip to content
Open
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
60 changes: 60 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 the transparency
of this color, e.g. 0.0 is completely opaque and 1.0 is completely
transparent. 0.5 is 50% transparent.
"""
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 @@ -106,6 +120,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 @@ -153,6 +177,42 @@ def brightness(self, value):
else:
self._xClr.clear_lum()

@property
def transparency(self):
"""
Read/write float value between 0.0 and 1.0 indicating the transparency
of this color. 0.0 is completely opaque, 1.0 is completely transparent.
"""
if self._xClr is None:
# NoneColor has no transparency
return 0.0
alpha = self._xClr.alpha
if alpha is not None:
# alpha.val is in range 0.0-1.0, where 1.0 = 100% opaque
# transparency is 1.0 - alpha.val
return 1.0 - alpha.val
# no alpha element means fully opaque (0% transparent)
return 0.0

@transparency.setter
def transparency(self, value):
if self._xClr is None:
# NoneColor cannot have transparency set
msg = (
"can't set transparency when color.type is None. Set color.rgb"
" or .theme_color first."
)
raise ValueError(msg)
if value == 0.0:
# fully opaque, remove alpha element
self._xClr.clear_alpha()
else:
# convert transparency (0.0-1.0) to alpha value (1.0-0.0)
# alpha = 1.0 - transparency
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
40 changes: 40 additions & 0 deletions src/pptx/dml/fill.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,22 @@ def fore_color(self):
"""
return self._fill.fore_color

@property
def transparency(self):
"""
Read/write float value between 0.0 and 1.0 indicating the transparency
of this fill, e.g. 0.0 is completely opaque and 1.0 is completely
transparent. 0.5 is 50% transparent.

This property is only applicable to solid fills. For other fill types,
accessing this property will raise a TypeError.
"""
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 +221,18 @@ 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):
"""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__)

@property
def type(self) -> MSO_FILL_TYPE: # pragma: no cover
raise NotImplementedError(
Expand Down Expand Up @@ -343,6 +371,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 the transparency
of this solid fill. 0.0 is completely opaque, 1.0 is completely transparent.
"""
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 @@ -221,13 +221,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:alphaOff", CT_PositiveFixedPercentage)
register_element_cls("a:alphaMod", 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
47 changes: 46 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")
alphaOff = ZeroOrOne("a:alphaOff")
alphaMod = ZeroOrOne("a:alphaMod")

def add_lumMod(self, value):
"""
Expand All @@ -37,6 +40,30 @@ 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_alphaOff(self, value):
"""
Return a newly added <a:alphaOff> child element.
"""
alphaOff = self._add_alphaOff()
alphaOff.val = value
return alphaOff

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

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

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


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


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

val = RequiredAttribute("val", ST_PositiveFixedPercentage)


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