feat(pptx): pixel-exact clipping via a rasterized composite fallback#412
Merged
Conversation
DrawingML has no graphics-state clipping, so clipped composites rendered unclipped — visibly different from the PDF (the parity demo's badge showed a whole circle where the PDF clips it to the container outline). The backend now consumes the whole clip region (the fragments between a clip-begin marker and its matching end, found by owner path), renders it through the PDF backend at up to 4 px/pt with a transparent background, crops the raster to the clip bounds, and places it as one picture — the clip is applied by the PDF engine itself, so the result is pixel-exact, and because the picture is created on the active drawing surface an enclosing transform group still rotates and scales it. The picture anchors on the crop's pixel bounds converted back to points, so the floor/ceil snap never shifts content. Fragment-level links, bookmarks, and anchors inside the region are still recorded; the raster is capped at 2048 px on the longest side. The fallback is on by default; Builder.clipRasterFallback(false) restores the previous unclipped vector rendering with its one-time warning, and the clip-begin handler now documents that it only dispatches on that path. PptxClipRasterFallbackTest pins both modes: one transparent composite picture on the clip bounds with an opaque centre and a fully transparent corner outside the outline (the clip really cut the layer), no vector leak of the clipped content, and the disabled path rendering the unclipped vector again. Full 10-module gate green; the vector parity demo's badge now matches the PDF.
…tom handlers The clip fallback rasterized the whole page at a scale keyed to the clip box, so a small badge on a large canvas allocated a full-page raster per region (hundreds of megabytes on poster-sized canvases). The region's fragments now translate into a clip-sized canvas and only the clip box renders — the raster is bounded by the capped clip size regardless of the page, and the crop step disappears; the picture anchors directly on the clip fragment box. A zero-size clip box skips drawing but still records the region's navigation, and the interception respects Builder.addHandler: a custom clip-begin handler keeps normal dispatch. Tests sharpen to actually prove the cut: the sampled pixel lies inside the layer circle but outside the container outline, so it is opaque in an unclipped render and transparent only when the clip really cut the layer (the old corner sample was transparent either way). New tests pin the two headline behaviours: a clip inside a rotated container renders its composite inside the rotated group, and a nested clip of a different owner is consumed into one composite with both clips applied by the PDF sub-render.
DemchaAV
force-pushed
the
feature/pptx-clip-raster
branch
from
July 17, 2026 14:12
fb8f96c to
64dc3c2
Compare
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.
Why
DrawingML has no graphics-state clipping, so clipped composites rendered unclipped — visibly different from the PDF: the vector parity demo's badge showed a whole circle where the PDF clips it to the rotated container outline.
What changed
PptxFixedLayoutBackendconsumes the whole clip region (fragments between a clip-begin marker and its matching end, matched by owner path) and renders it through the PDF backend at up to 4 px/pt with a transparent background, crops the raster to the clip bounds, and places it as one picture. The clip is applied by the PDF engine itself — pixel-exact, including nested clips and transforms inside the region — and because the picture lands on the active drawing surface, an enclosing transform group still rotates and scales it.Builder.clipRasterFallback(false)restores the previous unclipped vector rendering with its one-time warning (the clip-begin handler documents it now only dispatches on that path). Capability matrix flips the clip cell to supported-with-tradeoff; CHANGELOG entry added.Verification
./mvnw -B -ntp clean verify(full 10-module reactor gate) → BUILD SUCCESS; render-pptx suite 39 → 41 tests.PptxClipRasterFallbackTestpins both modes: exactly one transparent composite picture on the clip bounds whose centre pixel is opaque and whose corner outside the outline is fully transparent (the clip really cut the layer), no vector leak of the clipped content; and the disabled path rendering the unclipped vector with no composite picture. The vector parity demo's badge now matches the PDF page.Lane: canonical (document.backend.fixed.pptx).
Stacked on #411 (fragment matrix) — merge #411 first.