compose2pdf — Kotlin PDF Library for Compose Desktop

Generate production-quality PDFs from Compose Desktop content — vector text, embedded fonts, auto-pagination, and server-side streaming. A Kotlin JVM library that turns your @Composable functions into PDF documents.

Get Started View Examples


Compose in, PDF out — pixel-perfect

Write standard @Composable functions. Get production-quality PDFs.

Compose (reference render) PDF (vector output)
Compose render PDF render

A performance report with KPI cards, bar charts, and data tables — the PDF output is virtually identical to the Compose reference.


Three lines of code

val pdfBytes = renderToPdf {
    Text("Hello, PDF!")
}
File("hello.pdf").writeBytes(pdfBytes)

That’s it. renderToPdf takes a @Composable lambda and returns a ByteArray.


Real-world output

Detailed Invoice Professional Invoice
Invoice comparison Example invoice
Fidelity test fixture (PDF) Example walkthrough

Why compose2pdf?

Use the same Compose layout primitives you already know – Column, Row, Box, Text, Canvas – and get a production-quality PDF.

Vector PDFs

Text is selectable, scales to any zoom level, and produces small files. Powered by Skia’s SVGCanvas and Apache PDFBox.

Raster Fallback

When you need pixel-perfect rendering – complex gradients, visual effects, or exact bitmap output – switch to raster mode with one parameter.

Font Embedding

Ships with bundled Inter fonts (Regular, Bold, Italic, BoldItalic). Fonts are automatically subsetted and embedded so PDFs look the same everywhere.

Compose-Native API

No new DSL to learn. Write @Composable functions, pass them to renderToPdf(), get a ByteArray. Works with all standard Compose layout, text, shape, and drawing APIs.


Features at a Glance

Feature Description
Vector output Selectable text, crisp at any zoom, small file size
Raster fallback Pixel-perfect rendering as an embedded image
Font embedding Bundled Inter fonts or system font resolution with automatic subsetting
Link annotations Clickable URLs in the PDF via PdfLink
Auto-pagination Content automatically flows across pages; elements kept together at boundaries
Multi-page Render multiple pages in a single PDF (automatic or manual)
Streaming output Write PDFs directly to an OutputStream for Ktor, servlets, or files
Page presets A4, Letter, A3 with configurable margins and landscape support
Shapes Backgrounds, borders, clips, rounded corners, Canvas drawing
Images Embed bitmap images with clipping and layout

How it works

compose2pdf renders your Compose content through a Skia SVGCanvas → Apache PDFBox pipeline. Compose Desktop’s layout engine runs your composables, Skia captures the draw calls as SVG, and compose2pdf converts that to vector PDF commands with embedded fonts and link annotations.

Want native PDF output from Skia? Skiko PR #775 proposes adding a direct PDF backend to Skia/Skiko. This would eliminate the SVG intermediary — faster rendering, smaller files, and full gradient/effect support in vector mode. If this matters to you, upvote the PR!


Requirements

  • JDK 17 or later
  • Kotlin 2.x
  • Compose Multiplatform (Desktop) 1.9+