You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
docs(matrix): separate what DOCX cannot hold from what it does not do (#448)
The preamble said geometry rows were n/a for the semantic backend by
design, while the table marked them with the symbol the legend defines as
"no implementation, no current plan". The column therefore read as almost
nothing supported, and gave no way to tell an inapplicable concept from a
gap someone could close.
Drawing nodes are not inapplicable: shape, line, ellipse, polygon, path
and barcode all reach writeNode and are dropped there with a logged
warning, and Word expresses floating shapes, pictures and gradient fills.
Those stay ❌. What is genuinely n/a is the fixed-layout SPI —
SemanticBackend carries only name() and export(), so renderSections,
renderToImages and the raster-slide builder option are questions it
cannot be asked. Three cells move.
Three more were overstated. Image fit never reads fitMode or scale, so
CONTAIN and COVER behave as STRETCH and an unsized node falls back to
100x100 pt. Tables write cell text but not colSpan, rowSpan, per-cell
style or fill and border paint. Metadata hits the same OPC limitation the
PPTX row already records.
Copy file name to clipboardExpand all lines: README.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -207,7 +207,7 @@ For a Spring Boot `@RestController` streaming the PDF straight to the response,
207
207
| Format | Status | Notes |
208
208
|---|---|---|
209
209
| PDF | Production | Fixed-layout backend on PDFBox 3.0. Full DSL coverage. |
210
-
| DOCX | Partial | Semantic export via Apache POI — paragraphs, block images, tables and metadata. Word owns the flow, so drawing nodes (`shape`, `line`, `ellipse`, `barcode`) are dropped silently. Beyond geometry, **hyperlinks, bookmarks, headers/footers and multi-section documents are not implemented**— see [render-docx](./render-docx/README.md#what-it-maps-and-what-it-does-not). |
210
+
| DOCX | Partial | Semantic export via Apache POI — paragraphs, lists, block images, tables and metadata. Word owns the flow, so drawing nodes (`shape`, `line`, `ellipse`, `barcode`) are dropped, one logged warning per kind. **Hyperlinks, bookmarks and headers/footers are not implemented**, table `colSpan`/`rowSpan` is not applied, and image fit modes are ignored— see [render-docx](./render-docx/README.md#what-it-maps-and-what-it-does-not). |
211
211
| PPTX | Beta | Fixed-layout export via Apache POI from the same resolved layout — one page per editable slide with native shapes and text frames; clipped regions land as pixel-exact pictures. First shipped in 2.1, marked `@Beta` while the API shape settles. |
| Image — STRETCH / CONTAIN / COVER fit (`ImageFragmentPayload`) | ✅ `PdfImageFragmentRenderHandler`| ✅ `PptxImageFragmentRenderHandler` (COVER via the picture source crop) |✅ semantic images (`DocxSemanticBackend`) |
70
+
| Image — STRETCH / CONTAIN / COVER fit (`ImageFragmentPayload`) | ✅ `PdfImageFragmentRenderHandler`| ✅ `PptxImageFragmentRenderHandler` (COVER via the picture source crop) |⚠️ `DocxSemanticBackend.writeImage` (the picture is embedded at the node's width/height; `fitMode` and `scale` are never read, so CONTAIN and COVER behave as STRETCH, a node with neither width nor height falls back to 100×100 pt, and every picture is declared `PICTURE_TYPE_PNG`) |
| Table rows — resolved cells, row/col spans, two-pass fill/border paint (`TableRowFragmentPayload`) | ✅ `PdfTableRowFragmentRenderHandler` + row grouping in `PdfFixedLayoutBackend`| ✅ `PptxTableRowFragmentRenderHandler` + row grouping in `PptxFixedLayoutBackend` (positioned rectangles, edge lines, and text frames — never native PPTX tables, which re-lay-out content) |✅ semantic tables (`DocxSemanticBackend`) |
72
+
| Table rows — resolved cells, row/col spans, two-pass fill/border paint (`TableRowFragmentPayload`) | ✅ `PdfTableRowFragmentRenderHandler` + row grouping in `PdfFixedLayoutBackend`| ✅ `PptxTableRowFragmentRenderHandler` + row grouping in `PptxFixedLayoutBackend` (positioned rectangles, edge lines, and text frames — never native PPTX tables, which re-lay-out content) |⚠️ `DocxSemanticBackend.writeTable` (cell text becomes a real Word table; `colSpan` / `rowSpan`, the per-cell `DocumentTableStyle`, and fill/border paint are not applied, and cell runs carry no text style) |
62
73
| Clip region open/close (`ShapeClipBegin/EndPayload`) | ✅ `PdfShapeClipBegin/EndRenderHandler` (CLIP_BOUNDS + CLIP_PATH) | ✅ `PptxClipSafety` + raster fallback in `PptxFixedLayoutBackend` — a provably no-op clip (padded content that cannot be cut) skips the fallback entirely and stays native, editable shapes; a clip that can cut ink renders through the PDF backend into one transparent picture on the clip bounds (pixel-exact, not editable as shapes; run-level link hotspots are not emitted and custom fragment handlers do not apply inside the picture; `Builder.clipRasterFallback(false)` restores unclipped vectors + warning; the raster targets a 2048px long edge, clamped to between native size and 4x, so a region larger than that is rendered at native resolution rather than downscaled — which also means its transient memory grows with the clip instead of stopping at the target (a 3370pt A0-landscape region costs ~45MB while rendering, against ~17MB for anything up to 2048pt); a true vector clip is tracked in [#413](https://github.com/DemchaAV/GraphCompose/issues/413)) | ⚠️ inline fallback + one-time capability warning |
63
74
| Transform open/close — rotate/scale about fragment centre (`TransformBegin/EndPayload`) | ✅ `PdfTransformBegin/EndRenderHandler`| ✅ `PptxTransformBegin/EndRenderHandler` (group shape; rotation and centre-pivot scaling via the exterior/interior frame ratio) | ⚠️ inline fallback + one-time capability warning |
64
75
| Anchor markers (`AnchorMarkerPayload`) | ✅ `PdfAnchorMarkerRenderHandler` + `PdfInternalLinkWriter`| ✅ `PptxAnchorMarkerRenderHandler` + `PptxNavigationWriter` (slide-jump hyperlinks resolved after all fragments, so forward references work) | ❌ |
@@ -81,7 +92,7 @@ honour an option ignores it (documented contract).
| Metadata (title, author, …) | ✅ `PdfDocumentPostProcessor`| ⚠️ `applyMetadata` in `PptxFixedLayoutBackend` (OPC core properties + extended `Application`; OPC has no producer field, so that value is not representable) |✅ (`DocxSemanticBackend` via `SemanticExportContext`) |
95
+
| Metadata (title, author, …) | ✅ `PdfDocumentPostProcessor`| ⚠️ `applyMetadata` in `PptxFixedLayoutBackend` (OPC core properties + extended `Application`; OPC has no producer field, so that value is not representable) |⚠️ `applyOutputOptions` (OPC core properties — title, author as creator, subject, keywords; OPC has no producer field here either, so that value is not representable) |
85
96
| Watermark (front/back layers) | ✅ `PdfWatermarkRenderer`| ✅ `PptxChromeRenderer` (per-slide shape at the PDF placement math; behind-content applies before fragments, so no z-order surgery) | ❌ |
86
97
| Repeating headers / footers | ✅ `PdfHeaderFooterRenderer`| ✅ `PptxChromeRenderer` (positioned per-slide text boxes; `{page}` / `{pages}` / `{date}` tokens with the numbering window rules) | ❌ |
87
98
| Protection / encryption | ✅ `PdfDocumentPostProcessor`| ❌ (ignored with a one-time warning — no OOXML encryption support planned) | ❌ |
@@ -93,12 +104,12 @@ honour an option ignores it (documented contract).
| Render to images (`renderToImages`) | ✅ PDFBox `PDFRenderer`| ❌ (throws with a pointer to the PDF backend — POI's slide rasterizer cannot honour embedded fonts, and the PDF raster of the same graph is the canonical image output) |❌|
97
-
| Raster-slide mode — every page as one full-slide picture, pixel-exact to the PDF/PNG output (`Builder.rasterSlides(dpi)`) | n/a (the PDF raster is the source) | ✅ `PptxFixedLayoutBackend`|❌|
98
-
| Multi-section documents (`renderSections`, per-section chrome, cross-section links) | ✅ `buildSectionsDocument` in `PdfFixedLayoutBackend`| ⚠️ `renderSections` in `PptxFixedLayoutBackend` (a deck carries one slide size, so every section must share the same page canvas — differing sizes throw) |❌|
107
+
| Render to images (`renderToImages`) | ✅ PDFBox `PDFRenderer`| ❌ (throws with a pointer to the PDF backend — POI's slide rasterizer cannot honour embedded fonts, and the PDF raster of the same graph is the canonical image output) |n/a (a `FixedLayoutRenderer` surface; the semantic SPI has no raster output)|
108
+
| Raster-slide mode — every page as one full-slide picture, pixel-exact to the PDF/PNG output (`Builder.rasterSlides(dpi)`) | n/a (the PDF raster is the source) | ✅ `PptxFixedLayoutBackend`|n/a (a fixed-layout backend builder option)|
109
+
| Multi-section documents (`renderSections`, per-section chrome, cross-section links) | ✅ `buildSectionsDocument` in `PdfFixedLayoutBackend`| ⚠️ `renderSections` in `PptxFixedLayoutBackend` (a deck carries one slide size, so every section must share the same page canvas — differing sizes throw) |n/a (`renderSections` is declared on `FixedLayoutRenderer`; `MultiSectionDocument` drives fixed-layout backends only)|
|`DocumentSession` convenience methods | ✅ `buildPdf` / `writePdf` / `toPdfBytes` / `toImages`| ✅ `buildPptx` / `writePptx` / `toPptxBytes` (resolved via `BackendProviders.fixedLayout("pptx")`; session chrome applies; fails with `MissingBackendException` naming `graph-compose-render-pptx` when the backend is absent) |via`session.export(new DocxSemanticBackend(...))`|
112
+
|`DocumentSession` convenience methods | ✅ `buildPdf` / `writePdf` / `toPdfBytes` / `toImages`| ✅ `buildPptx` / `writePptx` / `toPptxBytes` (resolved via `BackendProviders.fixedLayout("pptx")`; session chrome applies; fails with `MissingBackendException` naming `graph-compose-render-pptx` when the backend is absent) |✅`session.export(new DocxSemanticBackend(...), target)` — the semantic backend is named directly rather than discovered|
0 commit comments