renderToPdf
The primary entry point for PDF generation. Four overloads: auto-paginating and manual multi-page, each with ByteArray and OutputStream variants.
Auto-paginating (default)
fun renderToPdf(
config: PdfPageConfig = PdfPageConfig.A4,
density: Density = Density(2f),
mode: RenderMode = RenderMode.VECTOR,
defaultFontFamily: FontFamily? = InterFontFamily,
pagination: PdfPagination = PdfPagination.AUTO,
content: @Composable () -> Unit,
): ByteArray
Renders Compose content to a PDF, automatically splitting across pages when content overflows.
With PdfPagination.AUTO (the default), direct children of content are treated as “keep-together” units — if a child would straddle a page boundary, it is pushed to the next page. A single child taller than a page flows continuously across pages.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
config | PdfPageConfig | PdfPageConfig.A4 | Page size and margins |
density | Density | Density(2f) | Pixel resolution for Compose layout. Each PDF point maps to density x density pixels. Higher values improve anti-aliasing (especially for raster mode) at the cost of memory |
mode | RenderMode | RenderMode.VECTOR | Vector (SVG-based) or raster rendering |
defaultFontFamily | FontFamily? | InterFontFamily | Font family for the default text style. When non-null, content is wrapped so both Compose and PDFBox use the same font. Pass null for system fonts |
pagination | PdfPagination | PdfPagination.AUTO | Controls page splitting. AUTO automatically paginates. SINGLE_PAGE clips to one page |
content | @Composable () -> Unit | – | The composable content to render |
Returns
ByteArray – a valid PDF document (one or more pages).
Throws
| Exception | When |
|---|---|
Compose2PdfException | Rendering fails (wraps the underlying cause) |
IllegalArgumentException | Precondition failures (not wrapped) |
Example
val pdfBytes = renderToPdf(
config = PdfPageConfig.LetterWithMargins,
mode = RenderMode.VECTOR,
) {
// Direct children are "keep-together" units
ReportHeader()
DataTable(items) // kept together on one page
SummarySection() // pushed to next page if needed
}
File("report.pdf").writeBytes(pdfBytes)
Auto-paginating (OutputStream)
fun renderToPdf(
outputStream: OutputStream,
config: PdfPageConfig = PdfPageConfig.A4,
density: Density = Density(2f),
mode: RenderMode = RenderMode.VECTOR,
defaultFontFamily: FontFamily? = InterFontFamily,
pagination: PdfPagination = PdfPagination.AUTO,
content: @Composable () -> Unit,
)
Streaming variant – writes the PDF directly to outputStream without creating an intermediate ByteArray. The stream is not closed by this function.
Parameters and behavior are identical to the ByteArray variant above.
Example
// Ktor
call.respondOutputStream(ContentType.Application.Pdf) {
renderToPdf(this, config = PdfPageConfig.A4WithMargins) {
ReportContent(data)
}
}
// File
FileOutputStream("report.pdf").use { out ->
renderToPdf(out) { ReportContent(data) }
}
Multi-page
fun renderToPdf(
pages: Int,
config: PdfPageConfig = PdfPageConfig.A4,
density: Density = Density(2f),
mode: RenderMode = RenderMode.VECTOR,
defaultFontFamily: FontFamily? = InterFontFamily,
content: @Composable (pageIndex: Int) -> Unit,
): ByteArray
Renders multiple pages of Compose content to a single PDF. The page count must be known upfront.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
pages | Int | – | Number of pages to render (must be positive) |
config | PdfPageConfig | PdfPageConfig.A4 | Page size and margins (applied uniformly to all pages) |
density | Density | Density(2f) | Pixel resolution for Compose layout |
mode | RenderMode | RenderMode.VECTOR | Vector or raster rendering |
defaultFontFamily | FontFamily? | InterFontFamily | Default font family |
content | @Composable (pageIndex: Int) -> Unit | – | Content for each page. Receives the zero-based page index |
Returns
ByteArray – a valid multi-page PDF document.
Throws
| Exception | When |
|---|---|
Compose2PdfException | Rendering fails |
IllegalArgumentException | pages is not positive |
Example
val totalPages = 3
val pdfBytes = renderToPdf(
pages = totalPages,
config = PdfPageConfig.A4WithMargins,
) { pageIndex ->
Column(Modifier.fillMaxSize()) {
Text("Page ${pageIndex + 1} of $totalPages")
when (pageIndex) {
0 -> CoverPage()
1 -> DataPage()
2 -> SummaryPage()
}
}
}
Multi-page (OutputStream)
fun renderToPdf(
outputStream: OutputStream,
pages: Int,
config: PdfPageConfig = PdfPageConfig.A4,
density: Density = Density(2f),
mode: RenderMode = RenderMode.VECTOR,
defaultFontFamily: FontFamily? = InterFontFamily,
content: @Composable (pageIndex: Int) -> Unit,
)
Streaming variant of the multi-page API. Writes the PDF directly to outputStream. The stream is not closed by this function.
Parameters and behavior are identical to the ByteArray multi-page variant above.
Example
call.respondOutputStream(ContentType.Application.Pdf) {
renderToPdf(this, pages = 3, config = PdfPageConfig.A4WithMargins) { pageIndex ->
PageContent(pageIndex)
}
}
Thread safety
Both overloads are not thread-safe. Concurrent calls should be serialized externally (e.g., via a Mutex or single-threaded Dispatchers).