From 2655c289559ba04f27ac304d10eeee57308812cd Mon Sep 17 00:00:00 2001 From: DemchaAV Date: Thu, 23 Jul 2026 19:29:35 +0100 Subject: [PATCH 1/3] docs(capabilities): mark the PPTX fixed-layout backend beta, not in development MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The per-capability cells already list the PPTX fixed-layout backend as implemented (✅/⚠️), but the backend descriptor still read "(in development)" — which the legend defines as "not usable yet". That contradicts the README and docs/api-stability.md, where the backend ships as @Beta (Experimental). Restate the descriptor as implemented and shipping @Beta so the capability matrix agrees with the policy and the changelog. --- docs/architecture/backend-capability-matrix.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/docs/architecture/backend-capability-matrix.md b/docs/architecture/backend-capability-matrix.md index fa81b745..d4818f9d 100644 --- a/docs/architecture/backend-capability-matrix.md +++ b/docs/architecture/backend-capability-matrix.md @@ -22,9 +22,12 @@ Backends: `com.demcha.compose.document.backend.fixed.pdf`. Consumes the resolved `LayoutGraph`; the reference implementation. - **PPTX (fixed-layout)** — `graph-compose-render-pptx`, - `com.demcha.compose.document.backend.fixed.pptx` (in development). - Consumes the same resolved `LayoutGraph`; geometry-identical to PDF by - construction, since layout is compiled in core before any backend runs. + `com.demcha.compose.document.backend.fixed.pptx`. Consumes the same + resolved `LayoutGraph`; geometry-identical to PDF by construction, since + layout is compiled in core before any backend runs. Ships as `@Beta` + (Experimental) in its first release — usable, with the per-capability + status in the tables below; the API shape may still change in a minor + while feedback lands (see [../api-stability.md](../api-stability.md)). - **DOCX (semantic)** — `graph-compose-render-docx`, `DocxSemanticBackend`. Walks the semantic node tree, deliberately ignores fixed-layout geometry; Word owns the flow. Geometry rows are From 2bd4fa0229c1e86812ee14ba37b15b0bae2296c2 Mon Sep 17 00:00:00 2001 From: DemchaAV Date: Thu, 23 Jul 2026 19:33:14 +0100 Subject: [PATCH 2/3] docs(roadmap): retarget to the shipped 2.0 line and 2.1 development MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The roadmap still described 2.0 as in flight on the retired `2.0-dev` branch preparing GA, named v1.9.x the current stable, and listed real PPTX export under "Later" as a manifest skeleton — contradicting the code, README and changelog. Retarget it: "Now" is the 2.1 line (the fixed-layout PPTX @Beta backend plus the keep-with-next pagination work), 2.0.0 is the current stable line, and PPTX moves from "manifest skeleton" to a beyond-beta graduation item. Drop the two post-2.0 items that have since shipped — the ArchUnit module-boundary guards and the cross-module coverage aggregator. --- ROADMAP.md | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index 8017ea16..b596bbe3 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -2,41 +2,42 @@ GraphCompose is solo-maintained. This roadmap is a direction, not a contract. Dates are intentionally omitted. Concrete work is tracked in [issues](https://github.com/DemchaAV/GraphCompose/issues) and shipped work is recorded in [CHANGELOG.md](CHANGELOG.md). For v1.6 phase-level detail, see [docs/roadmaps/v1.6-roadmap.md](docs/roadmaps/v1.6-roadmap.md). -## Now — 2.0 line +## Now — 2.1 line -In flight on `2.0-dev`, preparing the 2.0.0 GA. The 2.0 line is about **packaging and internal hygiene**, not new authoring API — binary-breaking by design, with `japicmp` report-only for the cycle. +In development on `develop`, building toward the **2.1.0** minor. The headline is the **fixed-layout PPTX render backend**: the same `DocumentSession` that prints a PDF now also emits an editable PowerPoint deck — one page per slide, identical geometry by construction, native shapes. It ships as `@Beta` (Experimental) while its API shape settles; the geometry identity with the PDF backend is a design invariant, not subject to change. See the [API stability policy](docs/api-stability.md) and the [backend capability matrix](docs/architecture/backend-capability-matrix.md). -**Scope frozen (2026-07).** 2.0.0 ships exactly the set below; no further internal engineering is pulled in before GA — that work is the post-2.0 line (next section). +Alongside it, 2.1 hardens pagination: `keepWithNext()` for headings, orphaned-heading fixes ahead of paragraphs, tables and lists, and the layered CV presets wired to the keep-with-next policy. + +Full detail lands in [CHANGELOG.md](CHANGELOG.md) under `v2.1.0`. + +## Current stable — 2.0 + +The **2.0.0** GA is the current stable line. 2.0 was about **packaging and internal hygiene**, not new authoring API — binary-breaking by design. - **Modular split** — the single jar is split into `graph-compose-core` plus `graph-compose-render-pdf` / `graph-compose-render-docx` / `graph-compose-render-pptx` / `graph-compose-templates` / `graph-compose-testing`, with render backends discovered through a `ServiceLoader` SPI. `graph-compose` stays a drop-in wrapper (core + render-pdf) so existing PDF callers upgrade unchanged. See the [2.0 modules migration guide](docs/migration/v2.0.0-modules.md) and [ADR 0016](docs/adr/0016-multi-module-packaging.md). - **Legacy removal** — the dead Entity-Component-System execution layer and the deprecated (`forRemoval`) public API are gone; the classic template presets are replaced by the layered `templates.*` stack on `BrandTheme`. - **Release & publishing pipeline** — multi-module Maven Central publishing, the `core/`-layout reactor (`./mvnw clean verify` at the root builds everything), and the cut / tag / GA runbook. - **Compatibility tests** — the guard, snapshot, and visual-regression suites that prove the split left rendered output unchanged. -- **Maintenance** — the **v1.9.x** line (current stable) receives critical fixes only. - -Further internal engineering — more layout-class decomposition, abstraction cleanup, streaming, optional performance work — is **deferred to post-2.0** and does not gate GA. -Full detail in [CHANGELOG.md](CHANGELOG.md) under `v2.0.0 — Planned`. +The **v1.9.x** line receives critical fixes only. ## Next — post-2.0 engineering -Committed direction for after the 2.0 GA: internal refactors, scale work, and tooling that do **not** change the public authoring API. Tracked in [docs/roadmaps/post-2.0-engineering.md](docs/roadmaps/post-2.0-engineering.md). +Committed internal direction for the post-2.0 line: refactors, scale work, and tooling that do **not** change the public authoring API. Tracked in [docs/roadmaps/post-2.0-engineering.md](docs/roadmaps/post-2.0-engineering.md). - **Decompose the layout hot files** — split `LayoutCompiler` and `TextFlowSupport` along their natural seams into individually-tested collaborators, with layout output unchanged. -- **ArchUnit module-boundary guards** — enforce the canonical / engine / render layering structurally, replacing the path-based greps that can pass vacuously after a move. -- **Cross-module coverage aggregation** — a dedicated non-published module that compile-depends on the tested modules so JaCoCo sees the `qa` suites; report-only first, thresholds after a baseline read. -- **Per-module binary-compatibility baselines** — once the 2.0 GA artifacts are published, switch `japicmp` to per-module baselines in break-on-incompatible mode. +- **Per-module binary-compatibility baselines** — now that the 2.0 GA artifacts are published, switch `japicmp` from the single-artifact baseline to per-module baselines in break-on-incompatible mode. ## Later (directional) Not committed. Reflects current thinking; priorities may shift based on user feedback and adoption signals. +- **PPTX beyond beta.** Graduate the fixed-layout PPTX backend from `@Beta` to stable and close the remaining fidelity gaps — true vector clipping instead of the raster fallback ([#413](https://github.com/DemchaAV/GraphCompose/issues/413)), exact numeric dash arrays, and distinct per-corner radii. - **DOCX visibility for unsupported nodes.** Make currently-silent skips (`shape`, `line`, `ellipse`, `barcode`) loud — minimum a warn log, ideally a strict-mode flag that fails instead of dropping content silently. - **Block-level alignment for fixed-size flow children.** Paths, images, layer stacks, shape containers and barcodes currently left-align in a flow; centring one means wrapping it in a full-width `ShapeContainer` just to use its CENTER anchor. Add a per-node horizontal align (left / centre / right — the `margin: auto` / `align(center)` analogue) so a fixed box can place itself in the flow directly. Surfaced by the v1.8 SVG icon-gallery and feature-catalog work. - **Backend-neutral layout measurement.** Decouple measurement from PDFBox-specific resources so non-PDF backends do not pull PDFBox into the dependency graph. - **DOCX maturity.** Either expand DOCX coverage toward PDF parity, or move DOCX behind an explicitly experimental flag. -- **Property-based testing.** Random table spans, pagination edge cases, deeply nested layouts. -- **Real PPTX export.** Current state is a manifest skeleton. Will only be built out if there is concrete user demand. +- **Property-based testing.** Expand the `@Property` layout-invariant seed to random table spans, pagination edge cases, and deeply nested layouts. - **Public Javadoc site.** Generated and hosted, kept in sync with releases. ## Not on the roadmap From d36d841b30b889c915b2ea5cd743a00ab91cfccf Mon Sep 17 00:00:00 2001 From: DemchaAV Date: Fri, 24 Jul 2026 23:57:11 +0100 Subject: [PATCH 3/3] docs(pptx): describe the shipped fixed-layout backend MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The module landing page for graph-compose-render-pptx still told readers that `.pptx` emission "is not built out yet" and to depend on the artifact "not for production slide export" — against 37 shipped production classes, a registered SPI, and the headline feature of the release. docs/capabilities.md listed the PPTX methods as Stable while the code marks them `@Beta`, and CONTRIBUTING sent contributors to `2.0-dev`, a branch that no longer exists. Rewrite render-pptx/README.md around the fixed-layout backend: what it produces, a first deck, the limitations worth knowing before shipping (raster fallback for clipped regions, viewer-side glyph rendering, opt-in determinism, unimplemented `renderToImages`, PDF-only chrome options), and the fact that a PPTX consumer also resolves the PDF stack because the backend reuses its font measurement and raster pass. Quantify the capability picture rather than promising blanket native output: of the 38 tracked capabilities, 24 map to a native equivalent, 10 render natively with an approximated styling detail, and 4 are unsupported. Correct the stability tier in docs/capabilities.md to Experimental (`@Beta`) so it agrees with the annotations and with docs/api-stability.md, and add the two `document.backend.fixed.pptx` packages to the §4 tier lookup, which the page's own maintenance rule requires. Refresh the frozen "New in" table to 2.1.0. Give PPTX a path in the docs: an Output backends section in the index and a PowerPoint section in getting-started, whose snippet carries a `doc-example` marker so it is compiled against the live API. Soften the root README's geometry promise to the capability matrix's own wording — frames and positions match, glyphs are rasterised by the viewer. Retarget ROADMAP to the 2.1 line, drop the "manifest skeleton" entry, and replace every `2.0-dev` reference in CONTRIBUTING with the post-GA branch roles. Install snippets are left alone: cut-release.ps1 rewrites the per-module ones in the release commit and VersionConsistencyGuardTest requires them to name the latest published release until then. Verified: full reactor `clean verify` green (1508 tests, 0 failures); core guards 402/402 and the documentation snippet guard green against the final text. --- CONTRIBUTING.md | 34 +++---- README.md | 2 +- docs/README.md | 5 ++ docs/api-stability.md | 2 + docs/architecture/canonical-legacy-parity.md | 2 +- docs/capabilities.md | 15 +++- docs/getting-started.md | 38 ++++++++ render-pptx/README.md | 95 ++++++++++++++++++-- 8 files changed, 161 insertions(+), 32 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a236c309..8968910b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -35,24 +35,23 @@ When writing new code, avoid Java 21+ APIs and language constructs that don't ex ## How to propose changes -GraphCompose follows a fork → feature branch → pull request flow. **Target the branch that matches your change** — GraphCompose is mid-transition to the 2.0 module line, so pick the base branch from this table before you fork: +GraphCompose follows a fork → feature branch → pull request flow. **Target the branch that matches your change** — pick the base branch from this table before you fork: | Change type | Base branch | |---|---| -| **2.0 feature / fix** (almost all current work) | `2.0-dev` | -| **Critical 1.9.x fix** (bug / security backport) | `develop` | +| **Feature / fix** (almost all work) | `develop` | +| **Critical 1.9.x fix** (bug / security backport) | `1.x` | | Stable releases (tags) | `main` | -| After 2.0 GA | `develop` | -Almost all current work is 2.0 and targets **`2.0-dev`**. `develop` and `main` carry the shipping **1.9.x** line and take only critical fixes; `main` is the public stable surface and accepts release merges only. See [Version lines](#version-lines-and-the-1x-maintenance-branch) below for the full transition. +Almost all work targets **`develop`**, the ongoing 2.x line. The `1.x` branch takes critical fixes and security backports only — no features. `main` is the public stable surface and accepts release merges only. See [Version lines](#version-lines-and-the-1x-maintenance-branch) below. ### Contribution flow 1. **Fork** the repository on GitHub and clone your fork locally. -2. **Create a feature branch** from your target base (`2.0-dev` for 2.0 work — substitute `develop` for a critical 1.9.x fix): +2. **Create a feature branch** from your target base (`develop` for feature work — substitute `1.x` for a critical 1.9.x backport): ```bash - git checkout 2.0-dev - git pull --ff-only origin 2.0-dev + git checkout develop + git pull --ff-only origin develop git checkout -b feature/short-description ``` Use `feature/...` for new functionality, `fix/...` for bug fixes, and `docs/...` for documentation-only changes. Issue-prefixed names (`42/fix/short-description`) are also welcome — convenient when the branch closes a specific issue. @@ -62,7 +61,7 @@ Almost all current work is 2.0 and targets **`2.0-dev`**. `develop` and `main` c ./mvnw -B -ntp clean verify ``` This runs the architecture-and-documentation guards plus the full test suite. The same gate runs in CI on every PR. -5. **Push** your feature branch to your fork and open a pull request against the base branch you started from (`2.0-dev` for 2.0 work) on `DemchaAV/GraphCompose`. Reference any related issue and describe the user-visible change in the PR body. +5. **Push** your feature branch to your fork and open a pull request against the base branch you started from (`develop` for feature work) on `DemchaAV/GraphCompose`. Reference any related issue and describe the user-visible change in the PR body. 6. **CI runs automatically.** Active jobs: - `Architecture and Documentation Guards` — fast canonical / engine-boundary guard tests, fail-first gate (always runs) - `Build and run tests (JDK 17)`, `(JDK 21)`, `(JDK 25)` — full `mvnw verify` in parallel matrix across the supported JVMs @@ -71,7 +70,7 @@ Almost all current work is 2.0 and targets **`2.0-dev`**. `develop` and `main` c - `Performance Smoke Check` — PR-only coarse benchmark to catch performance regressions - `CI Gate` — single aggregate status check that is green when every job that ran passed - **Selective on pull requests:** a `dorny/paths-filter` step skips the heavy jobs when a PR touches nothing that affects the build — a **docs-only PR runs the guards only**; `Binary Compatibility` runs only when the core module changed, and the `Performance Smoke Check` only when core / render-pdf / templates changed. Pushes to `2.0-dev` / `main` (and manual dispatch) always run the full gate. Point branch protection at **`CI Gate`** + **`Architecture and Documentation Guards`** rather than the individual matrix legs, so a docs-only PR is not left waiting on a skipped check. + **Selective on pull requests:** a `dorny/paths-filter` step skips the heavy jobs when a PR touches nothing that affects the build — a **docs-only PR runs the guards only**; `Binary Compatibility` runs only when the core module changed, and the `Performance Smoke Check` only when core / render-pdf / templates changed. Pushes to `develop` / `main` (and manual dispatch) always run the full gate. Point branch protection at **`CI Gate`** + **`Architecture and Documentation Guards`** rather than the individual matrix legs, so a docs-only PR is not left waiting on a skipped check. The PR cannot merge into a protected branch until all required checks are green. 7. **Address review comments**, then squash any fixup commits before merge. The maintainer merges through GitHub once review is complete. @@ -85,7 +84,7 @@ Almost all current work is 2.0 and targets **`2.0-dev`**. `develop` and `main` c - linear history is enforced (squash or rebase, no merge commits) - force pushes and branch deletion are disabled -`2.0-dev` (and, for 1.9.x fixes, `develop`) accepts feature-branch PRs from contributors. The maintainer may push directly for solo-driven release-prep work; external contributions still flow through PRs. +`develop` (and, for 1.9.x backports, `1.x`) accepts feature-branch PRs from contributors. The maintainer may push directly for solo-driven release-prep work; external contributions still flow through PRs. ### Release flow @@ -98,16 +97,11 @@ See [docs/contributing/release-process.md](./docs/contributing/release-process.m ### Version lines and the 1.x maintenance branch -GraphCompose is mid-transition to the 2.0 module line. Until 2.0 ships: +The 2.0 GA shipped, so the branches now hold their long-term roles: -- **`2.0-dev`** is the working branch for 2.0 — feature branches for 2.0 work target `2.0-dev`, not `develop`. -- **`develop`** and **`main`** carry the shipping **1.9.x** line; `main` is its stable, tagged surface (latest `v1.9.x`). - -At the **2.0 GA** merge the branches take their long-term roles: - -- **`main`** fast-forwards to 2.0 and becomes the stable 2.0 line. -- **`develop`** becomes the ongoing 2.x working branch (what `2.0-dev` was); `2.0-dev` retires. -- A **`1.x`** maintenance branch is cut from the final 1.9.x commit on `main` at that moment. It receives **critical fixes and security / CVE backports only — no features** — released as `1.9.x` patches from `1.x` via the same `cut-release.ps1` + tag flow. New feature work always targets the 2.x line. +- **`develop`** is the ongoing 2.x working branch — all feature branches target it. +- **`main`** is the stable 2.x line, tagged at each release (latest `v2.x`). +- **`1.x`** is the maintenance branch cut from the final 1.9.x commit. It receives **critical fixes and security / CVE backports only — no features** — released as `1.9.x` patches from `1.x` via the same `cut-release.ps1` + tag flow. New feature work always targets the 2.x line. ## Repository map diff --git a/README.md b/README.md index a3d582d7..735305b5 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ ## One source → a PDF and an editable PowerPoint deck -The same `DocumentSession` emits both. The PDF backend prints the resolved layout; the PPTX backend (**beta**) rebuilds it as slides with identical geometry — text, panels, tables, and vectors arrive in PowerPoint as **native, editable shapes**, not screenshots (the page below lands as 69 native shapes; only its clip-masked logo art is a picture). +The same `DocumentSession` emits both. The PDF backend prints the resolved layout; the PPTX backend (**beta**) rebuilds it as slides. Both consume the same resolved layout graph, so page and slide frames and every positioned element share the same geometry — text, panels, tables, and vectors arrive in PowerPoint as **native, editable shapes**, not screenshots (the page below lands as 69 native shapes; only its clip-masked logo art is a picture). Glyphs are rasterised by the viewer, so the exact text rendering depends on the fonts installed on the viewing machine; see the [backend capability matrix](docs/architecture/backend-capability-matrix.md) for per-feature fidelity. ```java Path deck = Path.of("twin-output.pptx"); diff --git a/docs/README.md b/docs/README.md index 06b92746..3bce26e4 100644 --- a/docs/README.md +++ b/docs/README.md @@ -38,6 +38,11 @@ back here. - **[templates/v2-layered/](templates/v2-layered/)** — the template surface (CV is the reference implementation): `data` / `theme` / `components` / `widgets` / `presets`. - **[templates/v1-classic/](templates/v1-classic/)** — 🗄️ archived: the classic spec/builder/presets surface removed in 2.0; kept for pre-2.0 callers. +### Output backends +- **[architecture/backend-capability-matrix.md](architecture/backend-capability-matrix.md)** — what each render backend supports, per capability. The source of truth for PDF vs PPTX fidelity. +- **[../render-pptx/README.md](../render-pptx/README.md)** — `graph-compose-render-pptx`: editable PowerPoint decks from the same session that prints the PDF (`@Beta`, first shipped in 2.1.0). +- **[api-stability.md](api-stability.md)** — stability tier per package, and what a tier promises. + ### Architecture - **[architecture/overview.md](architecture/overview.md)** — high-level system architecture (engine + DSL + templates + backends). - **[architecture/lifecycle.md](architecture/lifecycle.md)** — the document lifecycle from `GraphCompose.document(...)` through `buildPdf()`. diff --git a/docs/api-stability.md b/docs/api-stability.md index cfebd412..605846e6 100644 --- a/docs/api-stability.md +++ b/docs/api-stability.md @@ -241,6 +241,8 @@ Javadoc per element. | `com.demcha.compose.document.templates.invoice.*` | **Stable** | `graph-compose-templates` | Layered invoice family — `ModernInvoice` on `InvoiceDocumentSpec`. | | `com.demcha.compose.document.templates.proposal.*` | **Stable** | `graph-compose-templates` | Layered proposal family — `ModernProposal` on `ProposalDocumentSpec`. | | `com.demcha.compose.document.templates.data.*` | **Stable** | `graph-compose-templates` | Family-neutral document data records (invoice / proposal / schedule specs). | +| `com.demcha.compose.document.backend.fixed.pptx` | **Experimental** | `graph-compose-render-pptx` | Marked `@Beta` at the package level — `PptxFixedLayoutBackend`, its builder, and `PptxFixedLayoutBackendProvider`. First shipped in 2.1.0. | +| `com.demcha.compose.document.backend.fixed.pptx.handlers` | **Experimental** | `graph-compose-render-pptx` | Marked `@Beta` at the package level — the `PptxFragmentRenderHandler` seam and its built-in handlers. | | `com.demcha.compose.document.layout.*` | **Internal** | `graph-compose-core` | Marked `@Internal` at the package level. Engine surface. | | `com.demcha.compose.engine.*` | **Internal** | `graph-compose-core` | Engine surface; not part of the public contract regardless of `public` keyword. `engine.render.pdf.*` ships in `graph-compose-render-pdf`. | diff --git a/docs/architecture/canonical-legacy-parity.md b/docs/architecture/canonical-legacy-parity.md index 0db4fdfc..247930f4 100644 --- a/docs/architecture/canonical-legacy-parity.md +++ b/docs/architecture/canonical-legacy-parity.md @@ -92,7 +92,7 @@ compatibility concerns. New authoring features should be added through | Guide lines | Done | `guideLines(true)` is available on document builder and session. | | Metadata/protection/watermark/header/footer | Done | Configure on `DocumentSession` (e.g. `metadata(...)`, `watermark(...)`, `protect(...)`, `header(...)`, `footer(...)`); convenience PDF entrypoints (`buildPdf`, `writePdf`, `toPdfBytes`) honour these options without an explicit backend builder. `PdfFixedLayoutBackend.builder()` remains for advanced cases. | | DOCX semantic export | Done | Use `session.export(new DocxSemanticBackend())` for paragraph/table/image-aware Word output. Requires `org.apache.poi:poi-ooxml` on the consumer classpath. | -| PPTX semantic export | Planned for v1.6 (stretch) | Build out `PptxSemanticBackend` from the existing manifest skeleton to a working POI-based exporter — paragraphs as text boxes, tables as PowerPoint tables, sections as slides. See [v1.6 roadmap, Phase D](../roadmaps/v1.6-roadmap.md). | +| PPTX export | Done (fixed-layout, `@Beta` since 2.1.0) | `session.buildPptx(path)` with `graph-compose-render-pptx` on the classpath emits an editable deck from the same resolved layout graph as the PDF — one page per slide, native shapes, matching geometry. See the [backend capability matrix](backend-capability-matrix.md). The older `PptxSemanticBackend` manifest remains in the module but is not what the convenience methods use. | | PDFBox types in session API | Rejected | Keep PDFBox behind the fixed PDF backend. | ## Diagnostics diff --git a/docs/capabilities.md b/docs/capabilities.md index 5b5ddd10..32697c49 100644 --- a/docs/capabilities.md +++ b/docs/capabilities.md @@ -53,7 +53,7 @@ tracks what is `Partial` or `Planned`. | Write a PDF file | `buildPdf()`, `buildPdf(Path)` | Stable | [Getting started](getting-started.md) | | Stream to a caller-owned stream | `writePdf(OutputStream)` | Stable | [Streaming](recipes/streaming.md) | | In-memory bytes | `toPdfBytes()` | Stable | [Getting started](getting-started.md) | -| Geometry-identical PowerPoint deck | `buildPptx()`, `buildPptx(Path)`, `writePptx(OutputStream)`, `toPptxBytes()` — needs `graph-compose-render-pptx` on the classpath | Stable | [Backend capability matrix](architecture/backend-capability-matrix.md) | +| Geometry-identical PowerPoint deck | `buildPptx()`, `buildPptx(Path)`, `writePptx(OutputStream)`, `toPptxBytes()` — needs `graph-compose-render-pptx` on the classpath | Experimental (`@Beta`, first shipped in 2.1.0) | [Backend capability matrix](architecture/backend-capability-matrix.md) | | Editable Word (semantic) | `export(new DocxSemanticBackend())` | Stable (semantic, not PDF parity) | [Troubleshooting](troubleshooting.md) | | PDF chrome (metadata / watermark / header / footer / protection) | `metadata(...)`, `watermark(...)`, `header(...)`, `footer(...)`, `protect(...)` | Stable | [Getting started](getting-started.md) | | Layout snapshot regression | `LayoutSnapshotAssertions.assertMatches(...)` | Stable | [Layout snapshot testing](operations/layout-snapshot-testing.md) | @@ -70,9 +70,20 @@ tracks what is `Partial` or `Planned`. --- +## New in 2.1.0 + +These ship from 2.1.0 onward — confirm your dependency version before relying on them: + +| Capability | Main API | +|---|---| +| Editable PowerPoint deck (`@Beta`) | `buildPptx(Path)`, `writePptx(OutputStream)`, `toPptxBytes()` — add `graph-compose-render-pptx` | +| Slide page-size presets | `DocumentPageSize.SLIDE_16_9`, `DocumentPageSize.SLIDE_4_3` | +| Select a render backend by format | `BackendProviders.fixedLayout("pptx")` | +| Keep a heading with its content | `SectionBuilder.keepWithNext()`, `LineBuilder.keepWithNext()` | + ## New in 1.9.0 -These ship from 1.9.0 onward — confirm your dependency version before relying on them: +These ship from 1.9.0 onward: | Capability | Main API | |---|---| diff --git a/docs/getting-started.md b/docs/getting-started.md index 7c45f3bf..8dd81cf3 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -204,6 +204,44 @@ without the outline frame and logs a one-time capability warning. See [`docs/recipes/shape-as-container.md`](recipes/shape-as-container.md) for the full recipe. +## PowerPoint output + +Add `graph-compose-render-pptx` to the classpath and the same session +also emits an editable `.pptx` deck. The backend registers itself +through `ServiceLoader`, so there is nothing to wire up: + + +```java +import com.demcha.compose.GraphCompose; +import com.demcha.compose.document.api.DocumentPageSize; +import com.demcha.compose.document.api.DocumentSession; + +import java.nio.file.Path; + +try (DocumentSession document = GraphCompose.document() + .pageSize(DocumentPageSize.SLIDE_16_9) + .margin(48, 48, 48, 48) + .create()) { + + document.pageFlow(page -> page + .module("Title", module -> module.paragraph("Quarterly review"))); + + document.buildPptx(Path.of("deck.pptx")); +} +``` + +One resolved page becomes one identically-sized slide, and fragments +land at the same coordinates as in the PDF — both backends consume the +same layout graph, compiled in core before either runs. Glyphs are +still drawn by the viewer, so the rendered text depends on the fonts +installed on the viewing machine. + +The backend ships as `@Beta` (Experimental) in 2.1.0: it is usable for +production decks, but its API shape may change in a minor release. +Per-capability fidelity — what is a native shape, what is approximated, +and the raster fallback used for clipped regions — is documented in the +[backend capability matrix](architecture/backend-capability-matrix.md). + ## Templates Templates compose into the same `DocumentSession`. Data specs live diff --git a/render-pptx/README.md b/render-pptx/README.md index a03edf51..acd64358 100644 --- a/render-pptx/README.md +++ b/render-pptx/README.md @@ -2,20 +2,92 @@ `io.github.demchaav:graph-compose-render-pptx` -The semantic PPTX export backend for GraphCompose. Split out of the DOCX artifact so a DOCX -consumer never pulls the PPTX code (and vice versa). +The fixed-layout PowerPoint render backend for GraphCompose. The same +`DocumentSession` that prints a PDF also emits an editable `.pptx` deck — one +resolved page becomes one identically-sized slide, and every fragment lands at +the same coordinates, because both backends consume the same `LayoutGraph` +compiled in core before either of them runs. ## Status -`PptxSemanticBackend` is a **slide-safe semantic manifest skeleton** — it validates the node -graph against what a slide surface can represent; full `.pptx` file emission is not built out -yet. Depend on it for the semantic manifest / forward-compatibility, not for production slide -export. Track the [ROADMAP](../ROADMAP.md) for real PPTX output. +**Experimental (`@Beta`), first shipped in 2.1.0.** The backend is complete +enough for production decks: text, tables, shapes, images, gradients, links and +navigation, headers/footers/watermarks, and multi-section documents all arrive as +native PowerPoint objects rather than pictures. Across the 38 capabilities the +matrix tracks, 24 map to a native equivalent, 10 render natively with an +approximated styling detail (distinct per-corner radii collapse to one value, +numeric dash arrays map to the nearest preset, some inline SVG layers fall back +to a transparent PNG), and 4 are not supported at all — see the limitations below. + +The `@Beta` marker covers the *API shape* (`PptxFixedLayoutBackend`, its builder, +and the `PptxFragmentRenderHandler` seam), which may still change in a minor +release while feedback lands. Geometry identity with the PDF backend is a design +invariant and is not subject to change. + +The per-capability breakdown lives in one place: +[backend capability matrix](../docs/architecture/backend-capability-matrix.md). +The stability policy is [docs/api-stability.md](../docs/api-stability.md). + +## First deck + +Put `graph-compose-core` and this artifact on the classpath; the backend +registers itself through `ServiceLoader`, so no wiring is needed. + +```java +try (DocumentSession document = GraphCompose.document() + .pageSize(DocumentPageSize.SLIDE_16_9) + .create()) { + compose(document); + document.buildPptx(Path.of("deck.pptx")); +} +``` + +`writePptx(OutputStream)` and `toPptxBytes()` are the streaming and in-memory +counterparts. Rendering the *same* session to both formats gives a PDF and a +deck with matching page/slide geometry. + +`DocumentPageSize.SLIDE_16_9` (960 × 540 pt) and `DocumentPageSize.SLIDE_4_3` +(720 × 540 pt) match the PowerPoint defaults. Any other page size works too — +the slide simply takes that size. + +## Limitations to know before you ship + +- **Clipping falls back to a raster island.** A clipped composite is re-rendered + through the PDF backend and placed as a picture, so that region loses text + editability and any run-level links inside it. It is pixel-accurate and can be + switched off with `PptxFixedLayoutBackend.builder().clipRasterFallback(false)`. + True vector clipping is tracked in + [#413](https://github.com/DemchaAV/GraphCompose/issues/413). +- **Glyphs are drawn by the viewer, not by GraphCompose.** Shape frames, line + boxes and positions are fixed by the layout graph, but the actual glyph + rasterisation depends on the fonts installed on the viewing machine. Fonts are + embedded where the font's licensing bits allow it; otherwise PowerPoint + substitutes, and the backend logs which family was substituted. +- **Byte-for-byte reproducibility is opt-in.** The default path streams the deck + with live timestamps. Pass + `PptxFixedLayoutBackend.builder().deterministic(instant)` to pin the core + properties and normalise the zip entries. +- **PDF-only options do not apply**: document protection, viewer preferences and + the debug guide-line overlays are PDF concepts and are ignored here, each with + a one-time warning. +- **`renderToImages` is not implemented** and throws with a pointer to the PDF + backend — POI's slide rasteriser cannot honour embedded fonts. The session-level + `toImage(...)` / `toImages(...)` are unaffected: they resolve the PDF backend + explicitly. +- **Multi-section documents** render into one deck; the sections must share a + slide size. ## When to depend on it -Opt-in, at compile scope, only if you target the PPTX semantic surface. Not included by any -of `graph-compose`, `graph-compose-core`, or `graph-compose-bundle`. +Opt-in, at compile scope, when you want PowerPoint output. It is not pulled in +by `graph-compose`, `graph-compose-core`, or `graph-compose-bundle`. + +Note that this artifact depends on `graph-compose-render-pdf` at compile scope: +the PDF backend supplies the shared font-measurement library (so glyph widths +stay aligned with the widths that produced the layout graph) and performs the +raster pass behind the clipping fallback. A PPTX-only consumer therefore also +resolves the PDF stack. Extracting a backend-neutral measurement artifact is +tracked on the roadmap. ## Install @@ -35,3 +107,10 @@ dependencies { implementation("io.github.demchaav:graph-compose-render-pptx:2.0. The full "which artifact?" table: [root README → Installation](../README.md#installation). Upgrading from 1.x: [modules migration guide](../docs/migration/v2.0.0-modules.md). + +--- + +The module also carries `PptxSemanticBackend`, a slide-safe semantic +manifest that validates a node graph against what a slide surface can represent. +It predates the fixed-layout backend, is outside the scope of the capability +matrix, and is not what `buildPptx(...)` uses.