feat(pptx): complete the fragment matrix — images, barcodes, paths, transforms#411
Merged
Conversation
…ransforms Every payload the layout compiler emits now has a PPTX handler. Images render with the PDF fit modes — STRETCH fills the box, CONTAIN letter-boxes the centered bitmap, COVER crops through the picture's source rectangle (DrawingML's native crop, no clipping needed) — with source dimensions decoded from the real bitmap, because POI's header sniffing mis-reports some images and would break the aspect math the PDF backend computes from decoded pixels. Barcodes reuse the PDF handler's ZXing raster byte for byte. Polygons and free paths render as freeform geometry with the engine's y-up normalization flipped into slide space; gradient fills and gradient strokes stamp native DrawingML gradFill (linear angles convert from the engine's counter-clockwise convention to DrawingML's clockwise sixtieths; radial centres and explicit axes approximate with a one-time note), and a gradient stroke clears the noFill POI writes for a null line color — PowerPoint would otherwise honour noFill and drop the stroke entirely. Transform markers become containment: handlers draw on PptxRenderEnvironment.surface(page) — the innermost open group or the slide — and the begin marker opens a group whose interior anchor is the fragment box while the exterior anchor scales about the centre and carries the clockwise rotation, PPTX's equivalent of the PDF backend's graphics-state matrix. Clip markers degrade to a one-time warning (DrawingML has no graphics-state clipping; exact clips belong to the PDF backend or raster-slide mode). Anchor and bookmark markers record their destinations for the navigation pass. Tests (39 in render-pptx): fit-mode anchors and the COVER crop against the captured graph, barcode anchor, synthetic polygon and gradient-path freeforms asserting the CT gradFill (stop count, 90°→270° angle conversion, stroke gradFill present with no leftover noFill and the EMU width), and transform groups (rotation, interior/exterior anchors, centre pivot); a vector parity demo writes the PDF/PPTX pair and PNGs. Full 10-module gate green.
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
The fixed PPTX backend rendered text, tables, and basic vector shapes, but images, barcodes, polygons, free paths, gradients, and transform markers still threw
UnsupportedNodeCapabilityException— the last gaps between "renders some documents" and "renders any resolvedLayoutGraph".What changed
PptxRenderEnvironment.surface(page)— the innermost open transform group or the page's slide. Transform begin/end markers become containment: the begin marker opens anXSLFGroupShapewhose interior anchor is the fragment box while the exterior anchor scales about the centre and carries the clockwise rotation — PPTX's equivalent of the PDF backend's ambient graphics-state matrix, and it applies to every fragment kind between the markers because they all draw through the surface.PptxImageFragmentRenderHandler): the PDF fit modes — STRETCH fills the box, CONTAIN letter-boxes the centered bitmap, COVER crops through the picture's source rectangle (DrawingML's native crop). Source dimensions decode from the real bitmap with a per-fingerprint cache: POI's header sniffing mis-reports some images and would break the aspect math the PDF backend computes from decoded pixels.PptxBarcodeFragmentRenderHandler): a byte-mirror of the PDF handler's ZXing raster — same writers, hints, oversampling, and pixel mapping — so both formats carry the same bitmap.PptxInlineGeometryreuse), with the engine's y-up normalization flipped into slide space.PptxGradientFill): linear gradients stamp nativegradFill(engine's counter-clockwise angle converts to DrawingML's clockwise sixtieths — 90° becomes 270°); gradient strokes useln/gradFillnatively, clearing thenoFillPOI writes for a null line color (PowerPoint would otherwise honournoFilland drop the stroke). Radial centres and explicit linear axes approximate with a one-time note. The rectangle shape handler now stamps real gradients instead of the primary-color fallback.Verification
./mvnw -B -ntp clean verify(full 10-module reactor gate) → BUILD SUCCESS; render-pptx suite 34 → 39 tests.PptxVectorFragmentsTest— fit-mode anchors and the COVER crop against the captured graph; barcode picture on the fragment box; synthetic polygon and gradient-path freeforms asserting the raw CT: stop count, the 90°→270°×60000 angle conversion,ln/gradFillpresent with no leftovernoFilland the exact EMU width; transform groups: rotation, interior anchor = fragment box, exterior scaled about the unchanged centre.PptxVectorParityDemoTest— the reviewable pair + PNGs underrender-pptx/target/visual-tests/pptx-parity/vector-fragments/: images and the QR are visually identical; the rotated badge shows the documented clip degradation (PDF clips the layer to the container outline, PPTX renders it unclipped with the warning).Notes
IllegalStateExceptioninstead of an empty-stack error.Lane: canonical (document.backend.fixed.pptx) — backend surface; engine, layout, and the PDF paint path untouched.