Skip to content

Latest commit

 

History

1,602 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

GraphCompose

GraphCompose logo

Build production PDF documents in Java without calculating coordinates.
Compose content in reading order, let GraphCompose handle layout and pagination, then protect important templates with layout snapshots and visual diffs.

CI Latest release Maven Central Java 17+ MIT License

Release status — 🟢 Latest stable: v2.4.0a much larger template line-up: two new families, receipt and rota, new invoice, proposal and CV presets, and every CV preset marked ATS-friendly or design-first after three resume parsers read it; plus real letter spacing that keeps tracked caps searchable, one continuous timeline rail, and list items with hanging indents and drawn markers. See CHANGELOG.md.  ·  🟡 In development: v2.4.1 on develop — see CHANGELOG.md.

Documents rendered with GraphCompose

Live showcase  ·  Examples gallery

What it is

GraphCompose is a code-first document layout library for Java. You describe the document — paragraphs, sections, lists, tables, images — and the engine measures, wraps, places, and paginates it.

  • Higher-level than PDFBox: no manual x/y calculations for normal document flow.
  • Lighter than a reporting platform: typed Java, no XML templates or datasource language.
  • Built for change: deterministic geometry snapshots and pixel-level PDF diffs can catch an invoice, CV, or report drifting before the change reaches production.

Use it for server-side invoices, proposals, CVs, reports, statements, schedules, and other documents assembled from application data.

Outputs and templates

  • PDF — the main production output, included in graph-compose.
  • PPTX — editable fixed-layout export, currently beta, provided by the separate graph-compose-render-pptx module.
  • DOCX — semantic export with partial capability coverage, not full PDF parity, provided by the separate graph-compose-render-docx module.
  • Templates — 58 maintained designs across six document families in the separate graph-compose-templates module: invoice, proposal, receipt and rota for business documents, CV and cover letter for profiles. Start with invoice and proposal, CV and cover letter, or the templates overview for all six families.

Choose a starting point

Create your first PDF

You need one dependency and one Java file. You do not need to understand the engine, backends, templates, or repository modules first.

1. Add GraphCompose

Maven:

<dependency>
    <groupId>io.github.demchaav</groupId>
    <artifactId>graph-compose</artifactId>
    <version>2.4.0</version>
</dependency>

Gradle:

dependencies { implementation("io.github.demchaav:graph-compose:2.4.0") }

The graph-compose artifact already includes PDF output.

2. Copy this complete file

import com.demcha.compose.GraphCompose;
import com.demcha.compose.document.api.DocumentSession;

import java.nio.file.Path;

class Hello {
    public static void main(String[] args) throws Exception {
        try (DocumentSession document = GraphCompose.document(Path.of("hello.pdf"))
                .margin(48, 48, 48, 48)
                .create()) {

            document.pageFlow(page -> page
                    .addParagraph("Hello GraphCompose")
                    .addParagraph("This PDF was created without manual coordinates."));

            document.buildPdf();
        }
    }
}

Run Hello.main(). The file hello.pdf appears in the working directory.

That program contains the whole basic model:

GraphCompose.document(...) → pageFlow(...) → content blocks → buildPdf()
  • GraphCompose.document(...) chooses the output and page settings.
  • pageFlow(...) is ordinary top-to-bottom content.
  • Block methods add content in reading order; the engine handles wrapping and page breaks.
  • buildPdf() writes the result.

Styling is optional. Introduce DocumentTextStyle after the document structure says what it needs to say.

Grow it into a real document

A larger document uses the same flow. Group related content into named content modulesmodule(...), a titled block of the document, not a Maven module — and feed them your application data; coordinates still do not enter the authoring code.

document.pageFlow(page -> page
        .module("Summary", module -> module.paragraph(summary))
        .module("Skills", module -> module.bullets(skills))
        .module("Projects", module -> module.rows(projects)));

The same flow accepts the common building blocks directly. You do not need a new document model for each feature — a labelled bar chart is one more block in pageFlow:

import com.demcha.compose.GraphCompose;
import com.demcha.compose.document.api.DocumentSession;
import com.demcha.compose.document.chart.ChartData;
import com.demcha.compose.document.chart.ChartSpec;
import com.demcha.compose.document.chart.ValueLabelMode;

import java.nio.file.Path;

ChartData revenue = ChartData.builder()
        .categories("Q1", "Q2", "Q3", "Q4")
        .series("Revenue", 12.4, 15.1, 9.8, 14.2)
        .build();

try (DocumentSession document = GraphCompose.document(Path.of("revenue.pdf")).create()) {
    document.pageFlow(page -> page
            .addParagraph("Quarterly revenue")
            .chart(ChartSpec.bar()
                    .data(revenue)
                    .valueLabels(ValueLabelMode.OUTSIDE)
                    .build()));
    document.buildPdf();
}

From there, the chart recipe shows the next questions in order: value formatting, legends, bar/line shape, colours, grid, labels, background, and snapshot coverage.

Keep production documents from drifting

Rendering successfully is the first check. Important documents should also prove that their layout did not change unexpectedly after a library upgrade or a template edit.

Add the testing artifact at test scope:

<dependency>
    <groupId>io.github.demchaav</groupId>
    <artifactId>graph-compose-testing</artifactId>
    <version>2.3.0</version>
    <scope>test</scope>
</dependency>

Then pin the resolved geometry in a normal JUnit test:

import com.demcha.compose.GraphCompose;
import com.demcha.compose.document.api.DocumentSession;
import com.demcha.compose.testing.layout.LayoutSnapshotAssertions;
import org.junit.jupiter.api.Test;

class InvoiceLayoutTest {
    @Test
    void layoutDoesNotDrift() throws Exception {
        try (DocumentSession document = GraphCompose.document().create()) {
            document.pageFlow(page -> page
                    .addParagraph("Invoice")
                    .addParagraph("Total: £125.00"));

            LayoutSnapshotAssertions.assertMatches(document, "invoices/standard");
        }
    }
}

Create the first JSON baseline intentionally, commit it with the test, and run the test normally in CI. If a node moves, a page break changes, or content order drifts, the test fails with a reviewable geometry diff. CI never needs to update the baseline itself.

For flagship templates, add a second, pixel-level gate with PdfVisualRegression. It renders the PDF pages to images and writes .actual.png and .diff.png artifacts on mismatch, catching font, colour, glyph, and renderer changes that geometry alone cannot.

Start with Testing your document. The layout snapshot and visual regression pages are the deeper references when you need custom baseline paths, approval flow, or cross-platform tolerance.

What to read next

Pick the one row that matches what you are doing. Each is a complete route — you do not need the others, and you never need the engine internals to author a document.

I want to… Go to
Understand the model behind the example above Your first document — a guided five-minute build
Add a feature — table, list, chart, timeline, image, header, footer, barcode, page-break rule Recipes — the complete task index
Start from a ready-made design Invoice and proposal · CV and cover letter · receipt, rota, and all 58 presets
Prove an upgrade did not move my document Testing your document — layout snapshots and visual diffs
Render from a server Production rendering — streaming, concurrency, failure handling; the Spring Boot streaming example is a working endpoint

Contributing to GraphCompose itself is a separate path: start at Contributing. The documentation index is a reference catalogue — useful for finding a page, never required reading.

Output formats and optional modules

PDF is the production, fixed-layout output: graph-compose includes the graph-compose-render-pdf backend.

Need Add
Built-in templates, bundled fonts, and emoji together graph-compose-bundle
Built-in document templates — invoice, proposal, receipt, rota, CV, cover letter graph-compose-templates
Editable PowerPoint output (beta) graph-compose-render-pptx
Semantic DOCX output (partial) graph-compose-render-docx
Layout snapshots and PDF visual diffs in tests graph-compose-testing
Only the authoring surface and engine graph-compose-core

graph-compose-bundle includes PDF, templates, fonts, and emoji. PPTX and DOCX are not included in the bundle; add their render modules separately when needed.

Modules use the same GraphCompose version. Bundled fonts and colour emoji have their own release lines. Consult the module guide only when you need to split dependencies, and the backend capability matrix before relying on a feature outside PDF.

Upgrading from 1.x? Read the 2.0 migration guide.

Scope and comparison

GraphCompose uses PDFBox as its PDF renderer. The difference is the authoring layer: GraphCompose provides semantic document flow and automatic pagination, while PDFBox provides low-level PDF primitives and direct document manipulation.

GraphCompose is an embedded Java library, not a hosted rendering service, WYSIWYG editor, HTML/CSS renderer, or datasource-driven reporting engine.

Library Authoring model Best fit
GraphCompose Typed Java document flow with deterministic layout tests Code-first business documents
PDFBox Low-level text and path primitives Direct PDF manipulation, parsing, extraction
iText 7 Object layout API plus low-level canvas Teams comfortable with AGPL or a commercial licence
JasperReports XML templates and datasource bindings Traditional tabular reporting

Architecture for contributors

Application code authors against GraphCompose.document(...), DocumentSession, and the semantic document DSL. Internally, GraphCompose compiles that node tree into a deterministic layout, paginates it, and passes the result to a render backend.

flowchart LR
    A["Java application"] --> B["DocumentSession + semantic DSL"]
    B --> C["Document node tree"]
    C --> D["measure → paginate → place"]
    D --> E["PDF / PPTX backend"]
    C -.-> F["semantic DOCX backend"]
    D -.-> G["layout snapshot"]
Loading

Read the architecture overview, package map, and extension guide before changing engine or backend code. The repository module map and build workflow live in Contributing.

Project links

Documentation · Examples · Roadmap · Changelog · Support · Security · API stability

Companion projects

Sponsorship

GraphCompose is MIT-licensed and solo-maintained. If it saves your team work, GitHub Sponsors helps fund releases, dependency updates, visual-regression coverage, and issue triage. Sponsorship does not gate features or buy support priority; see Support.

License

MIT — see LICENSE.

About

Declarative Java engine for structured documents. Automatic layout, pagination, reusable templates and themes. Render print-ready PDF, export editable PowerPoint, or generate semantic DOCX.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

113 stars

Watchers

2 watching

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages