Skip to content

feat(dml): add transparency support for solid fills and colors (closes #17)#30

Merged
MHoroszowski merged 1 commit intomasterfrom
feature/transparency-opacity
May 6, 2026
Merged

feat(dml): add transparency support for solid fills and colors (closes #17)#30
MHoroszowski merged 1 commit intomasterfrom
feature/transparency-opacity

Conversation

@MHoroszowski
Copy link
Copy Markdown
Owner

Closes #17

Implements transparency / opacity support across ColorFormat, FillFormat, and _SolidFill — the longest-standing user request in upstream history (open since scanny/python-pptx#62, 2014).

Surface

shape.fill.solid()
shape.fill.fore_color.rgb = RGBColor(0xFF, 0x00, 0x00)
shape.fill.transparency = 0.5  # 50% transparent
shape.fill.fore_color.transparency = 0.3  # set via color directly
  • 0.0 = fully opaque (no <a:alpha> element written — optimal XML)
  • 1.0 = fully transparent (<a:alpha val="0"/>)
  • 0.5 = 50% transparent (<a:alpha val="50000"/>)

Provenance

Cherry-picked from upstream PR scanny/python-pptx#1090 (spandan-k @ secondlayerco, last updated April 2026), ported manually to keep the fork's ruff-formatted layout clean.

Files touched

File Change
src/pptx/dml/color.py ColorFormat.transparency + _Color.transparency + _validate_transparency_value
src/pptx/dml/fill.py FillFormat.transparency, base _Fill raises TypeError, _SolidFill delegates to fore-color
src/pptx/oxml/dml/color.py alpha/alphaMod/alphaOff as ZeroOrOne on _BaseColorElement; add_* and clear_alpha helpers; new CT_PositiveFixedPercentage element
src/pptx/oxml/__init__.py Register a:alpha, a:alphaMod, a:alphaOff
tests/dml/test_transparency.py NEW — 31 tests across 4 Describe classes
tests/oxml/unitdata/dml.py a_alpha, a_alphaMod, a_alphaOff builders

Verification

  • pytest tests/3017 passed (was 2986; +31 new transparency tests)
  • behave features/981 scenarios passed, 0 failed
  • ruff check src tests — clean
  • ruff format --check src tests — clean

Errors

color.transparency = 1.5     # ValueError: transparency must be number in range 0.0 to 1.0
color.transparency = -0.1    # ValueError
none_color.transparency = 0.5  # ValueError: can't set transparency when color.type is None
shape.fill.transparency      # TypeError: fill type _NoFill has no transparency, call .solid() first  (when fill not solid)

Out of scope (filed as follow-ups)

  • _GradientFill.gradient_stops[i].transparency (per-stop alpha)
  • LineFormat.transparency
  • _BlipFill.transparency — coordinate with Pictures epic
  • _PatternFill.transparency
  • alphaMod / alphaOff Python API (XML elements registered, no public surface yet)

Round-trip safety

Existing <a:alpha> elements in unrelated read paths (effects, theme.xml) are preserved — these were already serialized verbatim through lxml since the elements weren't registered with custom classes; registering them with CT_PositiveFixedPercentage does not change the bytes written for unmodified parts.

Implements ColorFormat.transparency, FillFormat.transparency, and
_SolidFill.transparency as a 0.0-1.0 float, backed by <a:alpha> in
the underlying srgbClr/schemeClr/etc. element.

- 0.0 = fully opaque (no <a:alpha> element written)
- 1.0 = fully transparent (<a:alpha val="0"/>)
- 0.5 = 50% transparent (<a:alpha val="50000"/>)

Cherry-picked and adapted from upstream PR scanny#1090
(spandan-k, secondlayerco/python-pptx@feat/opacity-support), ported
manually to keep the fork's ruff-formatted layout clean. Closes #17.

Surface:
- src/pptx/dml/color.py: ColorFormat.transparency, _Color.transparency,
  _validate_transparency_value (raises ValueError for out-of-range and
  for NoneColor)
- src/pptx/dml/fill.py: FillFormat.transparency delegates to inner
  _Fill; base _Fill raises TypeError; _SolidFill delegates to fore_color
- src/pptx/oxml/dml/color.py: alpha/alphaMod/alphaOff added as
  ZeroOrOne on _BaseColorElement with add_*/clear_alpha helpers; new
  CT_PositiveFixedPercentage element class
- src/pptx/oxml/__init__.py: register a:alpha, a:alphaMod, a:alphaOff
- tests/dml/test_transparency.py: 31 new tests across 4 describe
  classes (ColorFormat, FillFormat, _SolidFill, integration)
- tests/oxml/unitdata/dml.py: a_alpha, a_alphaMod, a_alphaOff builders

Tests: 3017 unit (+31 new) + 981 behave scenarios all passing.
Lint: ruff check + ruff format clean.

Out of scope (file as follow-ups): _GradientFill stop-level alpha,
LineFormat.transparency, _BlipFill.transparency (Pictures epic),
_PatternFill.transparency, alphaMod/alphaOff Python API surface.
@MHoroszowski MHoroszowski merged commit ef8ee6a into master May 6, 2026
12 checks passed
@MHoroszowski MHoroszowski deleted the feature/transparency-opacity branch May 6, 2026 01:15
MHoroszowski added a commit that referenced this pull request May 6, 2026
Documents project-level rules that apply to every contributor — human or
AI — working in this fork:

  • Editable-install gotcha with git worktree (use PYTHONPATH=src or work
    in the main checkout)
  • Manual port over git cherry-pick for upstream PRs (this fork has a
    repo-wide ruff format pass that upstream master lacks)
  • Test discipline expectations (pytest + behave + ruff baselines and
    TDD ordering)
  • Branch / PR workflow with approval-gated UAT step
  • Reporting contract for AI agents — verbatim verification output
    required, no self-attestation

Claude Code auto-merges project-root CLAUDE.md into any session opened
in the repo, so the rules are enforced without any additional setup.

Refs PR #30 as canonical feature example, PR #31 as the run that
surfaced most of these rules in practice.

Co-authored-by: Matthew Horoszowski <mhoroszowski@Winton.lan>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Epic] Transparency & Opacity (Fills, Lines, Pictures)

1 participant