Skip to content

DemchaAV/GraphCompose

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1,238 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

GraphCompose

GraphCompose logo

Declarative Java DSL for structured business PDFs.
Describe what the document says; the engine resolves layout, pagination, themes, and PDFBox rendering. Cinematic by default.

CI Latest release Maven Central Java 17+ PDFBox 3.0 MIT License

Release status — 🟢 Latest stable: v2.0.0 — the module-first release: the engine is now a lean graph-compose-core with opt-in render-pdf / render-docx backends, while graph-compose stays a drop-in for PDF. Migrating to 2.0 ↓

 ·  ⬆️ Upgrading from 1.x? graph-compose stays a drop-in for PDF with no code change; see the 2.0 modules migration guide  ·  See API stability policy for tier definitions.

Live Showcase  ·  Examples Gallery  ·  Docs  ·  Changelog

GraphCompose render preview

☝ This banner is itself a GraphCompose document — view the full module-first deck (PDF), rendered by EngineDeckV2Example: the 2.0 module graph, native vector charts, and real comparative benchmarks, all drawn by the engine. It renders its own marketing.

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. Soft panels, accent strips, transforms, native vector charts, and gradients are first-class primitives, not workarounds.
  • Lean core, pluggable backends. The graph-compose-core engine carries no PDFBox or POI; render backends are separate modules discovered via ServiceLoader — PDF is one dependency away (or already included in graph-compose), DOCX/PPTX are opt-in — see support matrix.

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 2.0

The module-first release — the single jar becomes a family of per-concern artifacts, so you install exactly what you render.

  • Lean enginegraph-compose-core is the document model, DSL, themes, and deterministic layout with no PDFBox, POI, or template code on its dependency tree. Backends plug in through a ServiceLoader seam; a core-only classpath asked to render throws MissingBackendException naming the artifact to add.
  • Opt-in render backendsgraph-compose-render-pdf (PDFBox 3.0, full DSL coverage), graph-compose-render-docx and graph-compose-render-pptx (Apache POI, semantic export).
  • graph-compose stays a drop-in — the 1.x coordinate is now a thin wrapper over core + the PDF backend, so existing callers upgrade with no code and no dependency change.
  • Templates are their own artifact — the CV / cover-letter / invoice / proposal preset families moved to graph-compose-templates (imports unchanged). This is the one dependency-level break of the split.
  • graph-compose-bundle — one batteries-included coordinate: PDF stack + templates + fonts + colour emoji.
  • Retired surface — the APIs deprecated across 1.6–1.9 are removed, the layered template packages dropped their .v2 suffix, and BusinessTheme plus the classic pre-layered presets are gone — each removal has a named replacement in the migration guide.

Everything the 1.9 line added — in-document navigation, native TOC and page references, bookmarks, multi-section documents, inline chips / SVG icons / colour emoji, render-to-image — ships unchanged in 2.0. Full history in CHANGELOG.md.

Installation

Requires Java 17+ (enforced by the build).

<dependency>
    <groupId>io.github.demchaav</groupId>
    <artifactId>graph-compose</artifactId>
    <version>2.0.0</version>
</dependency>
dependencies { implementation("io.github.demchaav:graph-compose:2.0.0") }

Which artifact? (2.0 module split). graph-compose above is the drop-in default — it renders PDF out of the box because it aggregates the lean graph-compose-core engine plus the graph-compose-render-pdf backend, so existing 1.x callers upgrade with no code change. Reach for a different coordinate only to take less or more:

Goal Depend on
PDF — the 1.x default graph-compose
Batteries-included (PDF + templates + fonts + emoji) graph-compose-bundle
Lean core, bring your own backend graph-compose-core
Built-in CV / cover-letter / invoice / proposal templates add graph-compose-templates
DOCX / PPTX export add graph-compose-render-docx / graph-compose-render-pptx

Every 2.0 coordinate shares the graph-compose version (the fonts and emoji companions keep their own lines). A bare graph-compose-core renders nothing until a backend is on the classpath — asking it to build a PDF throws MissingBackendException, which names the artifact to add (graph-compose-render-pdf, already included in graph-compose).

Companion artifacts: fonts & colour emoji. Two opt-in companions carry their own version lines (they change on their own cadence, so an engine upgrade never re-downloads them): graph-compose-fonts:1.0.0 — the curated Google font families (~18 MB; pure-text and standard-14 documents need nothing extra; details in the fonts migration note) — and graph-compose-emoji:1.0.0 — inline colour emoji for RichText.emoji(":star:", size) (an unknown shortcode falls back to its literal text, so documents without emoji render unchanged). Both are already included in graph-compose-bundle.

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 1.x? Rendering PDF through graph-compose needs no change at all. If you reached the built-in templates through the single 1.x jar, add graph-compose-templates (imports are unchanged) — the 2.0 migration guide walks every case, including the removed deprecated APIs and their replacements.

Hello world

import com.demcha.compose.GraphCompose;
import com.demcha.compose.document.api.DocumentPageSize;
import com.demcha.compose.document.api.DocumentSession;
import com.demcha.compose.document.style.DocumentColor;
import com.demcha.compose.document.style.DocumentTextDecoration;
import com.demcha.compose.document.style.DocumentTextStyle;
import com.demcha.compose.font.FontName;

import java.nio.file.Path;

class Hello {
    public static void main(String[] args) throws Exception {
        // A small inline palette — swap these for your own brand colours.
        DocumentColor cream = DocumentColor.rgb(252, 248, 240);
        DocumentColor panel = DocumentColor.rgb(244, 238, 228);
        DocumentColor accent = DocumentColor.rgb(196, 153, 76);
        DocumentTextStyle h1 = DocumentTextStyle.builder()
                .fontName(FontName.HELVETICA_BOLD).size(28)
                .decoration(DocumentTextDecoration.BOLD)
                .color(DocumentColor.rgb(20, 60, 75)).build();
        DocumentTextStyle body = DocumentTextStyle.builder()
                .fontName(FontName.HELVETICA).size(11)
                .color(DocumentColor.rgb(34, 38, 50)).build();

        try (DocumentSession document = GraphCompose.document(Path.of("hello.pdf"))
                .pageSize(DocumentPageSize.A4)
                .pageBackground(cream)
                .margin(28, 28, 28, 28)
                .create()) {

            document.pageFlow(page -> page
                    .addSection("Hero", section -> section
                            .softPanel(panel, 10, 14)
                            .accentLeft(accent, 4)
                            .addParagraph(p -> p.text("GraphCompose").textStyle(h1))
                            .addParagraph(p -> p.text("A cinematic hero, no manual coordinates.")
                                    .textStyle(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
PDF 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.

Text & internationalization

  • Text is laid out left-to-right. Bidirectional (RTL) reordering and complex-script shaping — Arabic contextual joining, Indic reordering — are not performed, so Arabic / Hebrew text renders in logical order without correct visual ordering. Full RTL / bidi support is tracked in #140.
  • A glyph the active font does not cover renders as ? (with a warning logged); load a font that covers the script you need.

When to use GraphCompose

  • Server-side PDF generation in Java — invoices, CVs, reports, proposals, statements, schedules.
  • Templated documents from data — themed presets (ModernProfessional, ModernInvoice, …) you parameterise instead of re-styling every time.
  • Regression-tested layoutsDocumentSession#layoutSnapshot() makes layout changes visible in PRs before any byte ships; PdfVisualRegression adds a pixel-level gate for font and colour fidelity.
  • Streaming PDFs from web backends — Spring Boot @RestController writing 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 .jasper files.
  • 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()&hellip;assertMatchesBaseline(...) — see visual regression testing
See the live gallery Static showcase site Showcase — source under web/, deployed to GitHub Pages via the Pages workflow

Templates in 2.0 — there is one template surface: the layered preset families in graph-compose-templates, themed through BrandTheme. Arriving from a pre-2.0 surface (classic presets, the built-in *Template classes)? Which template system should I use? maps every retired name to its layered replacement.

Vector primitives in 30 lines

Three snippets from the vector surfaces. Full runnable versions live in the examples gallery.

Native chart — categories + series in, native vector bars out (no rasterization).

ChartData 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.

section.chart(ChartSpec.line().data(series)
    .interpolation(LineInterpolation.MONOTONE)
    .build());

SVG import + alignment — parse SVG to native geometry, seat any fixed node across the width.

SvgIcon 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. Since 2.0 that boundary is also a packaging boundary: the surface and engine ship in graph-compose-core, and each render backend is a separate module that registers through a ServiceLoader seam. You author intent; the engine resolves the rest.

flowchart 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{ServiceLoader}
    E -->|render-pdf| F["PdfFixedLayoutBackend<br/>PDFBox"]
    E -->|render-docx| G["DocxSemanticBackend<br/>POI"]
    D -.->|layoutSnapshot| H["Deterministic snapshot<br/>(regression tests)"]
Loading

Full detail: architecture overview · package map · lifecycle.

Modules

The repository is a Maven multi-module reactor: the root pom.xml is the build aggregator, so ./mvnw clean verify at the root builds and tests every module (scope to one with -pl :<artifactId>; the lean engine lives in core/).

  • Published to Maven Central
    • graph-compose-core (core/) — the lean document engine
    • graph-compose-render-pdf · -render-docx · -render-pptx — render backends
    • graph-compose-templates — built-in CV / cover-letter / invoice / proposal presets
    • graph-compose-testing — snapshot & visual-regression test helpers
    • graph-compose — the drop-in wrapper (core + PDF); graph-compose-bundle — batteries-included (adds templates + fonts + emoji)
  • Companion artifacts (independent version lines) — graph-compose-fonts, graph-compose-emoji
  • Development only (never published) — qa (architecture guards + visual regression), coverage (aggregate JaCoCo), examples, benchmarks

See CONTRIBUTING for the branch-routing table and the full build / verify flow.

Documentation

📚 Full docs index — categorised map of every doc, ADR, and recipe. Start there to navigate the documentation.

Templates

Architecture & operations

Recipes & examples

Contributing & releases

Companion projects

  • graph-compose-markdown — a Markdown → PDF path built on the GraphCompose engine. Hand it a Markdown document and it renders through the same layout, theme, and PDFBox pipeline as the Java DSL — a companion input surface for teams who would rather author in Markdown than call the DSL directly. Published on Maven Central as io.github.demchaav:graph-compose-markdown; independent lifecycle, consumes the engine as a dependency.
  • 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

Star History Chart

About

Declarative Java PDF engine for structured business documents — semantic layout, atomic pagination, theme tokens, native charts, SVG & gradients, deterministic, PDFBox-backed

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

99 stars

Watchers

1 watching

Forks

Packages

 
 
 

Contributors