fix(decompile): honour <a:alpha> on fills via pre-blend on white#22
Closed
marsmike wants to merge 1 commit into
Closed
fix(decompile): honour <a:alpha> on fills via pre-blend on white#22marsmike wants to merge 1 commit into
marsmike wants to merge 1 commit into
Conversation
PPTX colour elements can carry `<a:alpha val="N"/>` where N is 0..100000 encoding 0..100% opacity. Source decks use this for Venn diagrams, overlay panels, glass-effect cards, and any composition where shapes sit on top of each other and the overlap region should mix. The previous `_resolve_solid` and `_resolve_fill` paths ignored the alpha element entirely — semi-transparent fills decompiled at full opacity, so Venn circles render as solid blobs instead of the expected lighter-on-white standalone + darker overlap regions. Threading true alpha through the build pipeline would require the expander, emitter, and python-pptx fill APIs to learn about transparency. As a contained first pass, we pre-multiply the source alpha against a white slide background: blended_c = c * alpha + 255 * (1 - alpha) For typical white-canvas slides this reproduces the perceived colour of standalone (non-overlapping) semi-transparent fills exactly. For overlapping regions (Venn intersections) the result is still wrong — real alpha compositing would darken the intersection — but the standalone fills now match source pixels, which is the dominant contribution to the diff. On the showcase deck slide-61 (the Venn diagram example) went from 18.05% struct_diff to 5.8% in a single change. Two new helpers: - `_alpha_for_color(color_el)` — read `<a:alpha>` child, returns 0..1 - `_blend_on_white(rgb, alpha)` — apply the pre-multiply formula Both `_resolve_solid` (used by line strokes, table cells, chart series) and `_resolve_fill` (shape fills, including the grpFill walk) now apply the blend on srgb AND scheme colour paths. Theme-scheme colours also pick up `<a:alpha>` when the source layers it onto an inherited brand accent. Signed-off-by: Mike Mueller <mike@objektarium.de>
This was referenced May 20, 2026
Owner
Author
marsmike
added a commit
that referenced
this pull request
May 21, 2026
`_text_runs` defaulted any paragraph whose run/`<a:pPr>`/`<a:lstStyle>` all omitted explicit `sz` to a hardcoded 18pt. PowerPoint's actual cascade reaches into the slide layout and slide master: 1. slide-level run `<a:rPr sz="...">` (already honoured) 2. paragraph `<a:pPr><a:defRPr sz="...">` (already honoured) 3. slide's `<a:txBody><a:lstStyle>...defRPr sz` (already honoured) 4. **layout's placeholder `<p:txBody><a:lstStyle>...defRPr sz`** ← new 5. **master's `<p:txStyles><p:titleStyle|bodyStyle>...defRPr sz`** ← new 6. hardcoded 18pt fallback Steps 4 and 5 are the layout-inheritance cascade. On a typical chapter- divider layout the slide-level placeholder writes only `<a:t>Chapter title</a:t>` and inherits the 60pt+ headline size from the layout's matching placeholder. Without the lookup we render at 18pt — visibly too small. New helper `_layout_placeholder_default_sz(slide, ph_type, ph_idx)` walks the layout (then the master's `<p:txStyles>`) for the matching placeholder. `_text_runs` gains an `inherited_default_sz` kwarg fed by `_emit_sp` whenever the shape carries `ph_type`/`ph_idx`. The cascade priority remains correct: slide-level lstStyle still wins over inherited; inherited only fires when no slide-level default exists. End-to-end on the 99-slide showcase, plus stacks cleanly with the chart-axis (PR #21) and alpha-fills (PR #22) improvements: mean struct_diff: 8.21% → 6.71% (91.79% → 93.29% quality) slides above 15% threshold: 13 → 5 Signed-off-by: Mike Mueller <mike@objektarium.de>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
PPTX colour elements carry
<a:alpha val=\"N\"/>(N is 0..100000 = 0..100% opacity) for Venn diagrams, overlay panels, glass-effect cards. The previous_resolve_solidand_resolve_fillpaths ignored alpha entirely — semi-transparent fills decompiled at full opacity.Threading true alpha through the build pipeline (expander → emitter → python-pptx fill APIs) is a larger change. As a contained first pass this PR pre-multiplies the source alpha against a white slide background:
For typical white-canvas slides this reproduces the perceived colour of non-overlapping semi-transparent fills exactly. Overlapping regions (Venn intersections) are still off — real alpha compositing would darken the intersection — but the standalone fills now match source pixels, which is the dominant contribution to diff.
Result
Measured on the 99-slide showcase deck:
Test plan
🤖 Generated with Claude Code