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,
header: (@Composable (PdfPageInfo) -> Unit)? = null,
footer: (@Composable (PdfPageInfo) -> Unit)? = null,
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 |
header |
(@Composable (PdfPageInfo) -> Unit)? |
null |
Optional composable stamped at the top of every page, anchored ~18pt (0.25in) from the page edge, inside the page margin. Height is measured once (using a pageCount = 2 sentinel so if (pageCount > 1) footers still reserve space) and is stable on every page; taller content is clipped. Body content keeps the configured margins unless the band (edge inset + height + a 10pt gap) exceeds the margin, in which case the body is pushed to fit. See Headers and footers |
footer |
(@Composable (PdfPageInfo) -> Unit)? |
null |
Optional composable stamped at the bottom of every page. Same placement/measurement rules as header. See Headers and footers |
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), including a measured header + footer height that leaves no room for content |
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,
header: (@Composable (PdfPageInfo) -> Unit)? = null,
footer: (@Composable (PdfPageInfo) -> Unit)? = null,
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).
See also
- Usage: Single Page
- Usage: Multi-page
- Usage: Auto-pagination – including the Headers and footers section
- API Reference: PdfPageInfo – Type passed to
header/footerslots - Guide: Server-side & Ktor