GraphCompose
Declarative Java PDF engine for structured business documents — semantic layout, atomic pagination, theme tokens, native charts, SVG & gradients, deterministic, PDFBox-backed
Declarative Java DSL for structured business PDFs. Describe what the document says; the engine resolves layout, pagination, themes, and PDFBox rendering. Cinematic by default. The project is written primarily in Java, distributed under the MIT License license, first published in 2025. Key topics include: business-documents, cv-templates, declarative-api, document-generation, invoice-template.
GraphCompose
<p align="center"> <img src="./assets/GraphComposeLogo.png" alt="GraphCompose logo" width="300"/> </p> <p align="center"> <b>Declarative Java DSL for structured business PDFs.</b><br/> Describe what the document <i>says</i>; the engine resolves layout, pagination, themes, and PDFBox rendering. <b>Cinematic by default.</b> </p> <p align="center"> <a href="https://github.com/DemchaAV/GraphCompose/actions/workflows/ci.yml?query=branch%3Amain"><img src="https://img.shields.io/github/actions/workflow/status/DemchaAV/GraphCompose/ci.yml?branch=main&style=for-the-badge&label=CI" alt="CI"/></a> <a href="https://github.com/DemchaAV/GraphCompose/releases/latest"><img src="https://img.shields.io/github/v/release/DemchaAV/GraphCompose?style=for-the-badge&label=Release" alt="Latest release"/></a> <a href="https://central.sonatype.com/artifact/io.github.demchaav/graph-compose"><img src="https://img.shields.io/maven-central/v/io.github.demchaav/graph-compose?style=for-the-badge&label=Maven%20Central" alt="Maven Central"/></a> <img src="https://img.shields.io/badge/Java-17%2B-orange?style=for-the-badge&logo=openjdk" alt="Java 17+"/> <img src="https://img.shields.io/badge/PDFBox-3.0-red?style=for-the-badge" alt="PDFBox 3.0"/> <img src="https://img.shields.io/badge/License-MIT-blue?style=for-the-badge" alt="MIT License"/> </p>Release status —
🟢 Latest stable: v1.9.0 — codenamed "navigable": in-document navigation (anchors, internal links, a clickable TOC, page references & bookmarks), multi-section documents, and inline chips / SVG icons / colour emoji. What's new in v1.9 ↓
<p align="center"> <a href="https://demchaav.github.io/GraphCompose/"><b>Live Showcase</b></a> · <a href="./examples/README.md"><b>Examples Gallery</b></a> · <a href="./docs/README.md"><b>Docs</b></a> · <a href="./CHANGELOG.md"><b>Changelog</b></a> </p> <p align="center"> <img src="./assets/readme/repository_showcase_render.png" alt="GraphCompose render preview" width="780"/> </p> <p align="center"> <sub>☝ This banner is itself a GraphCompose document — <a href="./assets/readme/examples/engine-deck.pdf"><b>view the full capability deck (PDF)</b></a>, rendered by <a href="./examples/src/main/java/com/demcha/examples/flagships/EngineDeckExample.java"><code>EngineDeckExample</code></a>: native vector charts and real comparative benchmarks, all drawn by the engine. It renders its own marketing.</sub> </p>· 🟡 In develop: next cycle — open (see CHANGELOG)
· See API stability policy for tier definitions.
Why GraphCompose
- Author intent, not coordinates. Fluent DSL for sections, paragraphs, tables, lists, layer stacks, themes — the engine handles measurement, pagination, and rendering.
- Deterministic by design. Two-pass layout. Snapshots are stable across machines, so layout regressions are catchable in tests before any byte ships.
- Cinematic by default.
BusinessTheme, soft panels, accent strips, transforms, native vector charts, and gradients are first-class primitives, not workarounds. - PDFBox isolated, DOCX optional. Single backend interface. Apache POI–backed DOCX export is available for compatible semantic content — see support matrix for limitations.
Sits between iText (low-level page primitives) and JasperReports (XML-template-driven layout): a Java DSL describes the document semantically, the engine renders.
What's new in v1.9
The "navigable" release — a rendered PDF becomes a document you can move through.
- In-document navigation — named
anchor(...)targets and internallink(...)jumps emitted as native PDFGoToactions: clickable cross-references,[text](#heading)-style links, and bidirectional footnotes (DocumentLinkTargetunifies internal and external links). - Native table of contents & page references —
addTableOfContents(toc -> toc.entry(label, anchor))builds a clickable TOC with dot leaders and auto-resolved page numbers;addPageReference(anchor)prints a native "see page N" cross-reference;DocumentSession.pageIndex()resolves any anchor to its page. - Bookmarks & viewer preferences —
section.bookmark(...)makes any section or container a PDF outline (bookmark-panel) target, andchrome().viewerPreferences(...)opens the reader on the outline panel, a chosen page layout, or the doc title in the window. - Multi-section documents —
GraphCompose.documents()concatenates independently authored sections — each with its own page size, margins, and footer numbering — into one PDF, with anchors, links, and the outline resolving across section boundaries. - Richer row & page layout —
row.columns(auto(), weight(1), fixed(80)), main-axisflexSpacer()/arrangement(...), cross-axisverticalAlign(...), per-pagepageMargins(...), and full-bleedbleed(...). - Inline chips, SVG icons & colour emoji — text on a rounded highlight chip, a parsed
SvgIconon the text baseline, andRichText.emoji(":star:", size)colour emoji via the new independently-versionedgraph-compose-emojimodule. - Render straight to images —
DocumentSessionrenders directly toBufferedImages with no PDF round-trip; plus page-number offset / restart / style and round / dotted line caps.
Core document APIs stay source- and binary-compatible with v1.8 — v1.9 is purely additive (two cover-letter / CV shim types are newly @Deprecated for 2.0). Full notes in CHANGELOG.md.
Installation
Requires Java 17+ (enforced by the build).
xml<dependency> <groupId>io.github.demchaav</groupId> <artifactId>graph-compose</artifactId> <version>1.9.0</version> </dependency>
kotlindependencies { implementation("io.github.demchaav:graph-compose:1.9.0") }
Bundled fonts (from v1.8.0). The curated Google fonts no longer ship
inside the engine jar — they live in an independently-versioned
companion artifact so an engine upgrade never re-downloads ~18 MB of
fonts. Pure-text and standard-14 documents need nothing extra; to use the
bundled families, add:xml<dependency> <groupId>io.github.demchaav</groupId> <artifactId>graph-compose-fonts</artifactId> <version>1.0.0</version> </dependency>Prefer a single "batteries-included" coordinate? Depend on
io.github.demchaav:graph-compose-bundle(same version asgraph-compose
above) to pull the engine + fonts together. Full details and upgrade steps:
the v1.8.0 fonts migration note.
Colour emoji (from v1.9.0).
RichText.emoji(":star:", size)resolves
GitHub-style shortcodes to inline vector glyphs from an independently-versioned
companion artifact (the same split model as the fonts above). Text without
emoji needs nothing extra; to render colour emoji, add:xml<dependency> <groupId>io.github.demchaav</groupId> <artifactId>graph-compose-emoji</artifactId> <version>1.0.0</version> </dependency>An unknown shortcode falls back to its literal text, so a document that uses no
emoji — or runs without the artifact — renders unchanged. The
graph-compose-bundlestays fonts-only; emoji is opt-in.
Distribution — Maven Central is the canonical channel from v1.6.6 onwards
(io.github.demchaav:graph-compose:<version>). Hosted Javadocs auto-publish to
javadoc.io/doc/io.github.demchaav/graph-compose
shortly after each Central release. The legacy JitPack URL
(com.github.DemchaAV:GraphCompose:v<version>) remains resolvable for callers
pinned to v1.6.5 and earlier but is no longer the documented install option.
Upgrading from v1.5? Core document authoring stays source-compatible — engine, DSL, themes, and backend-neutral records carry v1.5 callers unchanged. Templates v2 replaces the legacy CV / cover-letter template classes; legacy classes were deleted, not deprecated. Read the migration guide before upgrading template-heavy code.
Hello world
javaimport com.demcha.compose.GraphCompose; import com.demcha.compose.document.api.DocumentPageSize; import com.demcha.compose.document.api.DocumentSession; import com.demcha.compose.document.theme.BusinessTheme; import java.nio.file.Path; class Hello { public static void main(String[] args) throws Exception { BusinessTheme theme = BusinessTheme.modern(); try (DocumentSession document = GraphCompose.document(Path.of("hello.pdf")) .pageSize(DocumentPageSize.A4) .pageBackground(theme.pageBackground()) .margin(28, 28, 28, 28) .create()) { document.pageFlow(page -> page .addSection("Hero", section -> section .softPanel(theme.palette().surfaceMuted(), 10, 14) .accentLeft(theme.palette().accent(), 4) .addParagraph(p -> p.text("GraphCompose").textStyle(theme.text().h1())) .addParagraph(p -> p.text("A theme-driven hero, no manual coordinates.") .textStyle(theme.text().body())))); document.buildPdf(); } } }
For a Spring Boot @RestController streaming the PDF straight to the response, see HttpStreamingExample.
Scope and comparison
Output support
| Format | Status | Notes |
|---|---|---|
| Production | Fixed-layout backend on PDFBox 3.0. Full DSL coverage. | |
| DOCX | Partial | Semantic export via Apache POI. Unsupported nodes (shape, line, ellipse, barcode) are dropped silently — layout fidelity is best-effort for paragraph / list / table content. |
| PPTX | Skeleton | Validates supported node types and emits a manifest. Not a real PowerPoint export yet — planned only if there is demand. |
When to use GraphCompose
- Server-side PDF generation in Java — invoices, CVs, reports, proposals, statements, schedules.
- Templated documents from data — themed presets (
ModernProfessional,InvoiceTemplateV2, …) you parameterise instead of re-styling every time. - Regression-tested layouts —
DocumentSession#layoutSnapshot()makes layout changes visible in PRs before any byte ships;PdfVisualRegressionadds a pixel-level gate for font and colour fidelity. - Streaming PDFs from web backends — Spring Boot
@RestControllerwriting straight to the response (HttpStreamingExample). - Higher-level than PDFBox, lighter than JasperReports — Java DSL describes semantics; no XML templates, no manual coordinates.
What GraphCompose is not
- Not a hosted PDF rendering service — it is a library you embed.
- Not a WYSIWYG editor — the DSL is code, not drag-and-drop.
- Not a reporting engine like JasperReports — no datasource bindings, no XML templates, no compiled
.jasperfiles. - Not a browser / HTML-to-PDF renderer — the engine has its own layout pipeline; HTML/CSS input is not supported.
Compared with similar Java libraries
| Library | API style | Layout | License | Best for |
|---|---|---|---|---|
| GraphCompose | Java DSL, semantic nodes | Two-pass, deterministic, snapshot-testable | MIT | Code-first business documents with layout regression tests |
| PDFBox | Low-level text / path primitives | Manual coordinates | Apache 2.0 | Direct PDF manipulation, parsing, extraction |
| iText 7 | Object/layout API + low-level canvas | Automatic layout with direct-positioning options | AGPL / commercial | When AGPL is acceptable or you have a commercial licence |
| OpenPDF | iText 4 fork | Manual + helpers | LGPL / MPL | Legacy iText 4 codebases |
| JasperReports | XML templates compiled to .jasper | Template-driven | LGPL | Tabular reports with datasource bindings |
GraphCompose uses PDFBox under the hood as the rendering backend — the comparison is about authoring surface, not the renderer.
Which API should I use?
| You want to… | Surface | Entry point |
|---|---|---|
| Generate a one-off PDF programmatically | DSL | GraphCompose.document(...).pageFlow(...) — see Hello world above |
| Generate a CV / cover letter from data | Layered templates | ModernProfessional.create().compose(session, cvDocument) — see layered templates |
| Add a custom visual primitive | Engine extension | NodeDefinition + PdfFragmentRenderHandler — see extension guide |
| Regression-test generated layouts | Layout snapshots | DocumentSession#layoutSnapshot() — quickstart at Testing your document; full reference at snapshot testing |
| Pixel-test the rendered PDF (fonts, colours, anti-aliasing) | Visual regression | PdfVisualRegression.standard()…assertMatchesBaseline(...) — see visual regression testing |
| See the live gallery | Static showcase site | Showcase — source under web/, deployed to GitHub Pages via the Pages workflow |
Choosing a template surface — layered (
cv.v2), classic (cv.presets), or the built-in*TemplateV2family? See Which template system should I use? for the status matrix, decision tree, andclassic → layeredmigration map.
v1.8 primitives in 30 lines
Three snippets from the new vector surfaces. Full runnable versions live in the examples gallery.
Native chart — categories + series in, native vector bars out (no rasterization).
javaChartData revenue = ChartData.builder() .categories("Q1", "Q2", "Q3", "Q4") .series("2024", 12.4, 15.1, 9.8, 14.2) .series("2025", 14.0, 18.2, 11.3, 16.9) .build(); section.chart(ChartSpec.bar().data(revenue) .legend(LegendPosition.BOTTOM) .size(ChartSize.aspectRatio(16, 7)) .build());
Overshoot-free line — a smooth curve constrained to never overshoot the data range.
javasection.chart(ChartSpec.line().data(series) .interpolation(LineInterpolation.MONOTONE) .build());
SVG import + alignment — parse SVG to native geometry, seat any fixed node across the width.
javaSvgIcon globe = SvgIcon.parse(svgMarkup); flow.addSvgIcon(globe, 48, HorizontalAlign.CENTER); flow.addAligned(HorizontalAlign.RIGHT, anyFixedNode);
Architecture
GraphCompose splits into a public canonical surface you author against (com.demcha.compose.document.*) and an internal shared engine foundation (com.demcha.compose.engine.*, marked @Internal) that resolves geometry, pagination, and rendering behind it. You author intent; the engine resolves the rest.
mermaidflowchart LR A["GraphCompose.document(...)<br/>DocumentSession · DocumentDsl"] --> B["DocumentNode tree<br/>document.node"] B --> C["LayoutCompiler<br/>document.layout"] C --> D["Engine foundation @Internal<br/>measure → paginate → place"] D --> E{Backend} E -->|PDF| F["PdfFixedLayoutBackend"] E -->|DOCX| G["DocxSemanticBackend · POI"] D -.->|layoutSnapshot| H["Deterministic snapshot<br/>(regression tests)"]
Full detail: architecture overview · package map · lifecycle.
Documentation
📚 Full docs index — categorised map of every doc, ADR, and recipe. Start there to navigate the documentation.
Templates
- 🆕 Templates — v2 layered architecture — the canonical going-forward pattern for new template families (CV v2 is the reference implementation). Personas: quickstart · using templates · authoring presets · contributing a new family.
- Templates v1-classic landing — the older
BusinessTheme/CvSpecCV / cover-letter / invoice / proposal preset library (deprecated — CV + cover letter are superseded by v2-layered; invoice / proposal / schedule are not yet ported). Cheat sheet: authoring.
Architecture & operations
- Architecture overview · Lifecycle · Production rendering · Layout snapshot testing · Troubleshooting
Recipes & examples
- Recipes index — shape-as-container · shapes · transforms · page-backgrounds · layered-page-design · absolute-placement · tables · themes · streaming · extending · font-coverage
- Examples gallery — every runnable example with PDF preview
Contributing & releases
- Contributing · Code of conduct · Security policy · Release process
- API stability policy · Which template system? · Migration v1.6 → v1.7 · Migration v1.5 → v1.6
Companion projects
- graphcompose-ai-flow — experimental sister project exploring an AI-assisted authoring flow on top of GraphCompose. Independent codebase, separate lifecycle — nothing in this repo depends on it. Track it if you are interested in agentic document composition driven by the same semantic node model.
License
MIT — see LICENSE.
Star History
<a href="https://www.star-history.com/?repos=DemchaAV%2FGraphCompose&type=date&legend=top-left"> <picture> <source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/chart?repos=DemchaAV/GraphCompose&type=date&theme=dark&legend=top-left" /> <source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/chart?repos=DemchaAV/GraphCompose&type=date&legend=top-left" /> <img alt="Star History Chart" src="https://api.star-history.com/chart?repos=DemchaAV/GraphCompose&type=date&legend=top-left" /> </picture> </a>Contributors
Showing top 3 contributors by commit count.
