### Install KitePDF Skia Renderer Source: https://github.com/yuroyami/kitepdf/blob/main/docs/rendering.md Add the dependency to your project's build configuration. ```kotlin dependencies { implementation("io.github.yuroyami:kitepdf-skia-renderer:0.2.0") } ``` -------------------------------- ### Compose Multiplatform viewer setup Source: https://github.com/yuroyami/kitepdf/blob/main/docs/index.md Add the Compose viewer dependency and implement the PDF view component. ```kotlin implementation("io.github.yuroyami:kitepdf-compose-viewer:0.2.0") ``` ```kotlin val state = rememberPdfViewState(doc) PdfView( state = state, layout = PdfLayout.Paged(Orientation.Horizontal), // or Continuous / SinglePage zoomSpec = PdfZoomSpec(maxZoom = 6f), // pinch, double-tap, pan renderSpec = PdfRenderSpec.Rasterized(), // or Vectorized() overlay = { PdfNavigationControls(it, Modifier.align(Alignment.BottomCenter)) }, ) PdfPageIndicator(state) PdfThumbnailStrip(state) ``` -------------------------------- ### Install kitepdf-compose-viewer dependency Source: https://github.com/yuroyami/kitepdf/blob/main/docs/compose-viewer.md Add the library to your project dependencies for KMP or Android/JVM targets. ```kotlin // commonMain dependencies { implementation("io.github.yuroyami:kitepdf-compose-viewer:0.2.0") } ``` ```gradle dependencies { implementation("io.github.yuroyami:kitepdf-compose-viewer:0.2.0") } ``` -------------------------------- ### Install ApplePdfRasterizer dependency Source: https://github.com/yuroyami/kitepdf/blob/main/docs/rendering.md Add the native renderer dependency to your Apple platform sourceSet. ```kotlin // In your ios/macOS sourceSet dependencies { implementation("io.github.yuroyami:kitepdf-native-renderer:0.2.0") } ``` -------------------------------- ### Trigger Navigation via UI Source: https://github.com/yuroyami/kitepdf/blob/main/docs/compose-viewer.md Example of launching navigation actions from a button click using rememberCoroutineScope. ```kotlin val scope = rememberCoroutineScope() Button(onClick = { scope.launch { state.nextPage() } }) { Text("Next") } ``` -------------------------------- ### Install KitePDF in Kotlin Multiplatform Source: https://github.com/yuroyami/kitepdf/blob/main/docs/index.md Add the KitePDF dependency to your commonMain source set. ```kotlin kotlin { sourceSets { commonMain.dependencies { implementation("io.github.yuroyami:kitepdf:0.2.0") } } } ``` -------------------------------- ### Redact sensitive information example Source: https://github.com/yuroyami/kitepdf/blob/main/docs/editing.md A complete workflow for opening a document, redacting a specific area, and saving the result. ```kotlin val doc = PdfDocument.open(idCardBytes) val editor = doc.edit() // Redact a rectangular area containing the SSN (coordinates in points) editor.redactRegion(doc.pages[0], Rectangle( left = 50.0, bottom = 100.0, right = 200.0, top = 130.0 )) // Mandatory for redaction val redacted = editor.saveRewritten() ``` -------------------------------- ### Initialize and build a basic PDF Source: https://github.com/yuroyami/kitepdf/blob/main/docs/writing.md Demonstrates the standard workflow for creating a PDF document with metadata and a single page of text. ```kotlin import io.github.yuroyami.kitepdf.writer.PdfBuilder import io.github.yuroyami.kitepdf.writer.StandardFont val pdf = PdfBuilder() .setInfo(title = "My Report", author = "Kotlin App") .page { text(StandardFont.Helvetica, 24.0, 72.0, 700.0, "Hello, world!") } .build() // pdf is a ByteArray; write it to disk or send over the network ``` -------------------------------- ### Open PDF on JVM/Desktop Source: https://github.com/yuroyami/kitepdf/blob/main/docs/getting-started.md Read PDF bytes from a local file and initialize the document. ```kotlin import java.io.File import io.github.yuroyami.kitepdf.KitePDF val bytes = File("sample.pdf").readBytes() val doc = KitePDF.open(bytes) println("${doc.pageCount} pages") println("PDF version ${doc.version}") ``` -------------------------------- ### Configure Paged Layout Source: https://github.com/yuroyami/kitepdf/blob/main/docs/compose-viewer.md Sets up a snapped, page-by-page viewing experience suitable for books or slides. ```kotlin PdfView( state, layout = PdfLayout.Paged( orientation = Orientation.Horizontal, offscreenPages = 1, // pages pre-rasterized on each side ), ) ``` -------------------------------- ### Render pages to PNG files Source: https://github.com/yuroyami/kitepdf/blob/main/docs/recipes.md Uses pure JDK for rasterization, suitable for headless backends and CI pipelines. ```kotlin import io.github.yuroyami.kitepdf.nativerenderer.AwtPdfRasterizer import java.io.File val doc = PdfDocument.open(bytes) for ((index, page) in doc.pages.withIndex()) { val png = AwtPdfRasterizer.encodeToPng(page, scale = 1.0) File("page_${index + 1}.png").writeBytes(png) } ``` -------------------------------- ### Open an EPUB document Source: https://github.com/yuroyami/kitepdf/blob/main/docs/epub.md Opens an EPUB file from bytes. Use openOrNull to handle format errors gracefully. ```kotlin import io.github.yuroyami.kitepdf.epub.EpubDocument val book = EpubDocument.open(epubBytes) println("${book.pageCount} pages at ${book.pageWidth} x ${book.pageHeight} pt") ``` -------------------------------- ### Modify page content stream Source: https://github.com/yuroyami/kitepdf/blob/main/docs/editing.md Examples for filtering drawing commands or using built-in shorthand to remove text. ```kotlin // Remove all text from a page editor.editPageContent(doc.pages[0]) { ops -> ops.filter { it.operator !in setOf("Tj", "TJ", "'", "\"") } } ``` ```kotlin editor.removeAllText(doc.pages[0]) ``` -------------------------------- ### Open an EPUB with custom layout settings Source: https://github.com/yuroyami/kitepdf/blob/main/docs/epub.md Configures pagination dimensions and font settings during the initial document opening. ```kotlin val book = EpubDocument.open( epubBytes, pageWidth = 400.0, // points pageHeight = 640.0, fontSize = 12.0, // body size; author CSS scales relative to it margin = 36.0, ) ``` -------------------------------- ### Create PdfImage instances Source: https://github.com/yuroyami/kitepdf/blob/main/docs/writing.md Create images from raw pixel data or JPEG bytes. RGBA images automatically handle transparency via /SMask. ```kotlin import io.github.yuroyami.kitepdf.writer.PdfImage // 8-bit RGBA (4 bytes per pixel: R, G, B, A) val imageWithAlpha = PdfImage.rgba(pixelBytes, width = 100, height = 100) // 8-bit RGB (3 bytes per pixel: R, G, B) val imageRgb = PdfImage.rgb(pixelBytes, width = 100, height = 100) // 8-bit grayscale (1 byte per pixel) val imageGray = PdfImage.gray(pixelBytes, width = 100, height = 100) // JPEG passthrough (no re-encoding) val imageJpeg = PdfImage.jpeg(jpegBytes, width = 800, height = 600) ``` -------------------------------- ### Build pages imperatively Source: https://github.com/yuroyami/kitepdf/blob/main/docs/writing.md Use this approach for async layout generation by manually creating content streams and adding them to the builder. ```kotlin val builder = PdfBuilder() val content = builder.newPageContent() // … draw into content (fonts and images registered here) content.text(StandardFont.Helvetica, 14.0, 50.0, 750.0, "Async layout") builder.addPage(612.0, 792.0, content) builder.build() ``` -------------------------------- ### Draw Paths and Shapes Source: https://github.com/yuroyami/kitepdf/blob/main/docs/writing.md Demonstrates path construction using move, line, and rectangle operations, followed by stroke and fill commands. ```kotlin // Draw and stroke an outline content.moveTo(100.0, 100.0) content.lineTo(200.0, 100.0) content.lineTo(200.0, 200.0) content.lineTo(100.0, 200.0) content.closePath() // Close the path (line back to start) content.stroke() // Stroke with current color and line width // Draw and fill a rectangle content.setFillRgb(0.2, 0.8, 0.2) content.rectangle(50.0, 50.0, 150.0, 100.0) content.fill() // Fill and stroke in one operation content.setFillRgb(1.0, 1.0, 0.0) content.setStrokeRgb(0.0, 0.0, 0.0) content.rectangle(100.0, 100.0, 200.0, 200.0) content.fillAndStroke() ``` -------------------------------- ### Perform PDF operations in commonMain Source: https://github.com/yuroyami/kitepdf/blob/main/docs/index.md Demonstrates opening, reading, editing, and creating PDF documents using the KitePDF API in commonMain. ```kotlin // commonMain. Nothing platform-specific. This runs everywhere Kotlin runs. val doc = PdfDocument.open(bytes) val text = doc.pages[0].extractText() // read doc.edit().apply { // edit redactRegion(doc.pages[0], Rectangle(72.0, 700.0, 320.0, 720.0)) }.saveRewritten() val fresh = PdfBuilder() // create .page { text(StandardFont.Helvetica, 24.0, x = 72.0, y = 720.0, "Hello, world!") } .build() ``` -------------------------------- ### Display a PDF document Source: https://github.com/yuroyami/kitepdf/blob/main/docs/compose-viewer.md Basic implementation for rendering a full document or a single page. ```kotlin val document = remember { PdfDocument.open(bytes) } PdfView(document, modifier = Modifier.fillMaxSize()) ``` ```kotlin PdfView(document, page = 2, modifier = Modifier.fillMaxWidth()) ``` -------------------------------- ### Stamp a PDF page in Kotlin Source: https://github.com/yuroyami/kitepdf/blob/main/docs/editing.md Demonstrates initializing an editor, applying a text stamp to the first page, and saving incrementally. ```kotlin val doc = PdfDocument.open(pdfBytes) val editor = doc.edit() editor.setInfo(title = "Processed") editor.stampPage(doc.pages[0]) { setFillRgb(0.8, 0.1, 0.1) text(StandardFont.HelveticaBold, 48.0, 120.0, 400.0, "DRAFT") } val updated = editor.saveIncremental() ``` -------------------------------- ### Configure Continuous Layout Source: https://github.com/yuroyami/kitepdf/blob/main/docs/compose-viewer.md Sets up a lazy-loaded strip for end-to-end reading. ```kotlin PdfView( state, layout = PdfLayout.Continuous(orientation = Orientation.Vertical), // vertical = scroll down through all pages; horizontal = scroll right ) ``` -------------------------------- ### Open a PDF document Source: https://github.com/yuroyami/kitepdf/blob/main/docs/reading.md Opens a PDF from a byte array. Throws exceptions on failure. ```kotlin import io.github.yuroyami.kitepdf.PdfDocument val bytes = File("example.pdf").readBytes() val doc = PdfDocument.open(bytes) println("${doc.pageCount} pages: PDF ${doc.version}") ``` -------------------------------- ### Display Single PDF Page Source: https://github.com/yuroyami/kitepdf/blob/main/docs/getting-started.md Render a specific page with fit-to-viewport letterboxing using a zero-based index. ```kotlin @Composable fun SinglePageView(doc: PdfDocument) { PdfView( document = doc, page = 0, // zero-based index modifier = Modifier.fillMaxSize() ) } ``` -------------------------------- ### Render EPUB pages Source: https://github.com/yuroyami/kitepdf/blob/main/docs/epub.md Renders a page to a canvas or uses the drop-in Compose viewer. ```kotlin // Any canvas backend works: AwtCanvas, SkiaCanvas, ComposeCanvas, ... val canvas = AwtCanvas(graphics2d) book.pages[0].renderTo(canvas) ``` ```kotlin EpubView(document = book, modifier = Modifier.fillMaxSize()) ``` -------------------------------- ### Generate a PDF document with Kotlin Source: https://github.com/yuroyami/kitepdf/blob/main/docs/writing.md Demonstrates building a structured PDF with headers, text, and table elements. Requires the PdfBuilder class and standard font definitions. ```kotlin import io.github.yuroyami.kitepdf.writer.PdfBuilder import io.github.yuroyami.kitepdf.writer.StandardFont fun main() { val pdf = PdfBuilder() .setInfo( title = "Invoice #123", author = "E-Commerce System", creator = "MyApp/1.0" ) .page { // Draw a blue header box setFillRgb(0.2, 0.4, 0.8) rectangle(0.0, 650.0, 612.0, 142.0) fill() // Title in white setFillRgb(1.0, 1.0, 1.0) text(StandardFont.HelveticaBold, 36.0, 50.0, 730.0, "INVOICE") text(StandardFont.Helvetica, 14.0, 50.0, 690.0, "Invoice #123-2025") // Content in black setFillRgb(0.0, 0.0, 0.0) text(StandardFont.Helvetica, 12.0, 50.0, 600.0, "Bill To:") text(StandardFont.Helvetica, 11.0, 50.0, 580.0, "John Doe") text(StandardFont.Helvetica, 11.0, 50.0, 565.0, "john@example.com") // Horizontal line setStrokeRgb(0.8, 0.8, 0.8) setLineWidth(1.0) moveTo(50.0, 540.0) lineTo(562.0, 540.0) stroke() // Table header with light gray background setFillRgb(0.95, 0.95, 0.95) rectangle(50.0, 520.0, 512.0, 20.0) fill() setFillRgb(0.0, 0.0, 0.0) text(StandardFont.HelveticaBold, 11.0, 60.0, 528.0, "Description") text(StandardFont.HelveticaBold, 11.0, 350.0, 528.0, "Unit Price") text(StandardFont.HelveticaBold, 11.0, 450.0, 528.0, "Qty") text(StandardFont.HelveticaBold, 11.0, 500.0, 528.0, "Total") // Item rows text(StandardFont.Helvetica, 10.0, 60.0, 500.0, "Consulting Services") text(StandardFont.Helvetica, 10.0, 350.0, 500.0, "$150.00") text(StandardFont.Helvetica, 10.0, 450.0, 500.0, "8") text(StandardFont.Helvetica, 10.0, 500.0, 500.0, "$1,200.00") } .build() // Write to file (JVM example; use platform APIs on other targets) java.nio.file.Files.write( java.nio.file.Paths.get("invoice.pdf"), pdf ) } ``` -------------------------------- ### Render PDF with Canvas2D Source: https://github.com/yuroyami/kitepdf/blob/main/docs/rendering.md Initialize a Canvas2D context and render a PDF page using a transformation matrix. ```kotlin import io.github.yuroyami.kitepdf.nativerenderer.Canvas2dCanvas import io.github.yuroyami.kitepdf.PdfDocument import io.github.yuroyami.kitepdf.core.render.Matrix as PdfMatrix import org.w3c.dom.CanvasRenderingContext2D // In a context val canvas: CanvasRenderingContext2D = /* ... */ val pdfCanvas = Canvas2dCanvas(canvas) val pdf = PdfDocument.open(/* ... */) val page = pdf.pages[0] val deviceCtm = PdfMatrix(scale, 0.0, 0.0, -scale, 0.0, page.height * scale) page.renderTo(pdfCanvas, deviceCtm) // To save as PNG: use the browser's canvas.toBlob() or toDataURL() ``` -------------------------------- ### Perform common PDF operations in Kotlin Source: https://github.com/yuroyami/kitepdf/blob/main/README.md Demonstrates opening a password-protected PDF, extracting text, filling form fields, and applying watermarks to pages. ```kotlin // Open a password-protected PDF val doc = PdfDocument.open(bytes, password = "secret".encodeToByteArray()) require(doc.isAuthenticated) // Read text val text = doc.pages[0].extractText() // Fill a form field and save (append-only) val out = doc.edit() .apply { setTextFieldValue(doc.formField("ApplicantName")!!, "Jane Doe") } .saveIncremental() // Watermark every page val stamped = doc.edit().apply { doc.pages.forEach { page -> stampPage(page) { setFillRgb(0.8, 0.1, 0.1) text(StandardFont.HelveticaBold, 48.0, x = 120.0, y = 400.0, "DRAFT") } } }.saveIncremental() ``` -------------------------------- ### Create a date-stamped approval box Source: https://github.com/yuroyami/kitepdf/blob/main/docs/editing.md Combine path drawing and text placement to create a complex stamp overlay. ```kotlin val editor = doc.edit() editor.stampPage(doc.pages[0]) { setFillRgb(0.0, 0.0, 0.0) setLineWidth(1.5) // Draw a box rectangle(400.0, 700.0, 150.0, 80.0) stroke() // Text inside setFillRgb(0.2, 0.2, 0.2) text(StandardFont.HelveticaBold, 12.0, 410.0, 760.0, "APPROVED") text(StandardFont.Helvetica, 10.0, 410.0, 740.0, "2025-06-17") } val stamped = editor.saveIncremental() ``` -------------------------------- ### Render PDF Pages with Skia Source: https://github.com/yuroyami/kitepdf/blob/main/docs/rendering.md Demonstrates opening a PDF document and rendering a page to a Skia image or PNG bytes. Remember to call close() on Skia images to prevent memory leaks. ```kotlin import io.github.yuroyami.kitepdf.skia.PdfPageRasterizer import io.github.yuroyami.kitepdf.PdfDocument import org.jetbrains.skia.Color import java.io.File val pdf = PdfDocument.openFile("sample.pdf") val page = pdf.pages[0] // Render to Skia Image val image = PdfPageRasterizer.renderToImage( page, scale = 2.0, background = Color.WHITE ) // Encode to PNG bytes and write to disk val pngBytes = PdfPageRasterizer.encodeToPng(page, scale = 2.0) File("preview.png").writeBytes(pngBytes) // Clean up the image if you only needed bytes image.close() ``` -------------------------------- ### View a single page in Compose Source: https://github.com/yuroyami/kitepdf/blob/main/docs/recipes.md Render a specific page of a document by passing the page index to the PdfView component. ```kotlin PdfView( document = doc, page = 0, modifier = Modifier.fillMaxWidth(), ) ``` -------------------------------- ### Configure SinglePage Layout Source: https://github.com/yuroyami/kitepdf/blob/main/docs/compose-viewer.md Displays a single fixed page letterboxed to the viewport. ```kotlin PdfView(state, layout = PdfLayout.SinglePage(pageIndex = 3)) ``` -------------------------------- ### Advanced PDF Viewer Configuration Source: https://github.com/yuroyami/kitepdf/blob/main/docs/getting-started.md Customize layout, zoom specifications, rendering quality, and UI overlays. ```kotlin import androidx.compose.foundation.gestures.Orientation import androidx.compose.ui.Alignment import androidx.compose.ui.graphics.Color import io.github.yuroyami.kitepdf.PdfDocument import io.github.yuroyami.kitepdf.compose.* @Composable fun AdvancedViewer(doc: PdfDocument) { val state = rememberPdfViewState(doc) PdfView( state = state, modifier = Modifier.fillMaxSize(), layout = PdfLayout.Paged(Orientation.Horizontal), zoomSpec = PdfZoomSpec(minZoom = 0.5f, maxZoom = 6f), renderSpec = PdfRenderSpec.Rasterized( quality = 1f, maxBitmapLongSide = 4096, rerasterizeOnZoom = true, preserveHairlines = true ), colors = PdfViewColors( pageBackground = Color.White, viewportBackground = Color(0xFF1E1E1E) ), overlay = { state -> PdfNavigationControls(state, Modifier.align(Alignment.BottomCenter)) } ) } ``` -------------------------------- ### Configure full PdfView composable Source: https://github.com/yuroyami/kitepdf/blob/main/docs/compose-viewer.md Advanced usage with hoisted state, custom layout, zoom specifications, and navigation overlays. ```kotlin val state = rememberPdfViewState(document) PdfView( state = state, modifier = Modifier.fillMaxSize(), layout = PdfLayout.Paged(Orientation.Horizontal), zoomSpec = PdfZoomSpec(maxZoom = 6f), renderSpec = PdfRenderSpec.Rasterized(quality = 1.5f), colors = PdfViewColors(pageBackground = Color.White), pageSpacing = 8.dp, overlay = { state -> PdfNavigationControls(state, Modifier.align(Alignment.BottomCenter).padding(16.dp)) }, ) ``` -------------------------------- ### Create a PDF document Source: https://github.com/yuroyami/kitepdf/blob/main/docs/recipes.md Use PdfBuilder to define document metadata and page content. Coordinates are measured in points with the origin at the bottom-left. ```kotlin import io.github.yuroyami.kitepdf.writer.PdfBuilder import io.github.yuroyami.kitepdf.writer.StandardFont val bytes = PdfBuilder() .setInfo(title = "Invoice", author = "MyApp") .page(width = 612.0, height = 792.0) { // US Letter: 612×792 points text(StandardFont.HelveticaBold, 24.0, 36.0, 750.0, "Invoice #2024-001") text(StandardFont.Helvetica, 12.0, 36.0, 720.0, "Customer: Jane Doe") text(StandardFont.Helvetica, 12.0, 36.0, 705.0, "Amount: $500.00") } .build() writeFile("invoice.pdf", bytes) ``` -------------------------------- ### Configure Compose PDF viewer Source: https://github.com/yuroyami/kitepdf/blob/main/docs/platforms.md Customize the viewer layout, zoom, and rendering behavior using state and configuration objects. ```kotlin val state = rememberPdfViewState(doc) PdfView( state = state, layout = PdfLayout.Paged(Orientation.Horizontal), zoomSpec = PdfZoomSpec(maxZoom = 6f), renderSpec = PdfRenderSpec.Rasterized(quality = 1f), colors = PdfViewColors(viewportBackground = Color.DarkGray), overlay = { s -> PdfNavigationControls(s, Modifier.align(Alignment.BottomCenter).padding(16.dp)) }, ) // The same state drives widgets outside the viewport: PdfPageIndicator(state) PdfThumbnailStrip(state) ``` -------------------------------- ### Initialize PdfViewState Source: https://github.com/yuroyami/kitepdf/blob/main/docs/compose-viewer.md Create the state object to hoist outside the PdfView for external control. ```kotlin val state = rememberPdfViewState(document) ``` -------------------------------- ### Display PDF Document Source: https://github.com/yuroyami/kitepdf/blob/main/docs/getting-started.md Render a full PDF document using vertical continuous scroll. ```kotlin import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.ui.Modifier import io.github.yuroyami.kitepdf.PdfDocument import io.github.yuroyami.kitepdf.compose.PdfView @Composable fun PdfViewer(doc: PdfDocument) { PdfView(document = doc, modifier = Modifier.fillMaxSize()) } ``` -------------------------------- ### Retrieving Viewer Preferences Source: https://github.com/yuroyami/kitepdf/blob/main/docs/reading.md Access document-level viewer hints such as page layout and display mode. ```kotlin val prefs = doc.viewerPreferences val layout = doc.pageLayout // SinglePage, TwoPageLeft, TwoPageRight, etc. val mode = doc.pageMode // UseNone, UseOutlines, UseThumbs, UseOC, etc. ``` -------------------------------- ### Configure PDF compression during build Source: https://github.com/yuroyami/kitepdf/blob/main/docs/writing.md Toggle the compress parameter in the build method to enable or disable FlateDecode compression for content streams. ```kotlin val compressedPdf = PdfBuilder().page { /* … */ }.build(compress = true) // default val uncompressedPdf = PdfBuilder().page { /* … */ }.build(compress = false) ``` -------------------------------- ### Add pages with custom dimensions Source: https://github.com/yuroyami/kitepdf/blob/main/docs/writing.md Shows how to chain multiple pages with specific sizes to a PDF builder. ```kotlin PdfBuilder() .page { text(StandardFont.Helvetica, 14.0, 50.0, 750.0, "This is page 1") } .page(width = 595.0, height = 842.0) { text(StandardFont.Helvetica, 14.0, 50.0, 750.0, "This is A4") } .build() ``` -------------------------------- ### Read document metadata and outlines Source: https://github.com/yuroyami/kitepdf/blob/main/docs/recipes.md Access document information and hierarchical bookmarks from an opened PDF document. ```kotlin val doc = PdfDocument.open(bytes) // Trailer /Info dict println("Title: ${doc.info.title}") println("Author: ${doc.info.author}") // Bookmarks for (outline in doc.outlines) { println("- ${outline.title}") for (child in outline.children) { println(" - ${child.title}") } } ``` -------------------------------- ### Traverse Document Outlines Source: https://github.com/yuroyami/kitepdf/blob/main/docs/reading.md Iterate through the document's bookmark tree to access titles and nested children. ```kotlin for (outline in doc.outlines) { println("${outline.title} (count: ${outline.count})") for (child in outline.children) { println(" - ${child.title}") } } ``` -------------------------------- ### Configure PDF rendering mode Source: https://github.com/yuroyami/kitepdf/blob/main/docs/recipes.md Choose between rasterized rendering for performance or vectorized rendering for resolution independence. ```kotlin PdfView( state = state, modifier = Modifier.fillMaxSize(), renderSpec = PdfRenderSpec.Rasterized( quality = 1f, // 1 = display resolution maxBitmapLongSide = 4096, // cap memory rerasterizeOnZoom = true, // crisp at deep zoom preserveHairlines = true, // keep thin lines visible ), ) ``` ```kotlin PdfView( state = state, modifier = Modifier.fillMaxSize(), renderSpec = PdfRenderSpec.Vectorized(hairlineWidthPx = 1f), ) ``` -------------------------------- ### Implement Page Indicator Source: https://github.com/yuroyami/kitepdf/blob/main/docs/compose-viewer.md Display a formatted string showing the current page index relative to the total page count. ```kotlin PdfPageIndicator( state, modifier = Modifier.padding(8.dp), format = { current, total -> "Page ${current + 1} / $total" }, ) ``` -------------------------------- ### Headless PDF rendering Source: https://github.com/yuroyami/kitepdf/blob/main/docs/index.md Render PDF pages to image bytes for server-side or CI environments. ```kotlin implementation("io.github.yuroyami:kitepdf-native-renderer:0.2.0") // or kitepdf-skia-renderer ``` ```kotlin val png = AwtPdfRasterizer.encodeToPng(doc.pages[0], scale = 2.0) ``` -------------------------------- ### Render PDF page to Bitmap in Compose Source: https://github.com/yuroyami/kitepdf/blob/main/docs/rendering.md Perform rendering on a background thread and display the resulting ImageBitmap in a Compose UI component. ```kotlin import io.github.yuroyami.kitepdf.nativerenderer.AndroidPdfBitmapRenderer import io.github.yuroyami.kitepdf.PdfDocument import android.graphics.Color import android.graphics.Bitmap import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.graphics.ImageBitmap import androidx.compose.ui.graphics.asImageBitmap import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext // Render off the main thread, then draw the result once it lands. val imageBitmap = remember { mutableStateOf(null) } LaunchedEffect(pdf) { val bitmap = withContext(Dispatchers.Default) { AndroidPdfBitmapRenderer.renderToBitmap( page, scale = 1.5, background = Color.WHITE ) } imageBitmap.value = bitmap.asImageBitmap() } imageBitmap.value?.let { Image(it, contentDescription = "Page thumbnail") } ``` -------------------------------- ### Configure PDF Zoom and Gestures Source: https://github.com/yuroyami/kitepdf/blob/main/docs/compose-viewer.md Define zoom bounds and enable or disable specific gestures like pinch and double-tap. ```kotlin val spec = PdfZoomSpec( pinchEnabled = true, doubleTapEnabled = true, panEnabled = true, minZoom = 1f, maxZoom = 8f, doubleTapZoom = 2.5f, // what double-tap toggles to resetZoomOnPageChange = true, // snap to minZoom when paging ) PdfView(state, zoomSpec = spec) ``` ```kotlin PdfView(state, zoomSpec = PdfZoomSpec.Disabled) ``` -------------------------------- ### Configure Differential Test Parameters Source: https://github.com/yuroyami/kitepdf/blob/main/kitepdf-native-renderer/DIFFTEST.md Runs the test suite with custom DPI and error budget settings. ```bash ./gradlew :kitepdf-native-renderer:jvmTest \ -Dkitepdf.diff.dpi=150 -Dkitepdf.diff.budget=0.10 ``` -------------------------------- ### Configure Kotlin Multiplatform Dependencies Source: https://github.com/yuroyami/kitepdf/blob/main/docs/platforms.md Add these dependencies to the commonMain source set in your build.gradle.kts file. ```kotlin // The core engine (always add this) implementation("io.github.yuroyami:kitepdf:0.2.0") // Optional: Compose viewer implementation("io.github.yuroyami:kitepdf-compose-viewer:0.2.0") // Optional: platform-native rasterizer (no Compose) implementation("io.github.yuroyami:kitepdf-native-renderer:0.2.0") // Optional: Skia rasterizer (headless, one common API) implementation("io.github.yuroyami:kitepdf-skia-renderer:0.2.0") ``` -------------------------------- ### Add Navigation Controls Source: https://github.com/yuroyami/kitepdf/blob/main/docs/compose-viewer.md Create a floating navigation pill for moving between pages, typically used within an overlay. ```kotlin overlay = { state -> PdfNavigationControls( state, modifier = Modifier .align(Alignment.BottomCenter) .padding(16.dp), contentColor = Color.White, containerColor = Color(0xB3222222), // semi-transparent dark ) } ``` -------------------------------- ### Configure Vectorized Rendering Source: https://github.com/yuroyami/kitepdf/blob/main/docs/compose-viewer.md Use vectorized rendering for simple documents where memory efficiency and resolution independence are prioritized over gesture smoothness. ```kotlin val spec = PdfRenderSpec.Vectorized( hairlineWidthPx = 1f, // minimum stroke width in device pixels ) PdfView(state, renderSpec = spec) ``` -------------------------------- ### Display PDF with Compose viewer Source: https://github.com/yuroyami/kitepdf/blob/main/docs/platforms.md Integrate a PDF viewer into Compose Multiplatform applications using the PdfView composable. ```kotlin val doc = remember(bytes) { PdfDocument.open(bytes) } PdfView(document = doc, modifier = Modifier.fillMaxSize()) ``` -------------------------------- ### PdfView Configuration Source: https://github.com/yuroyami/kitepdf/blob/main/docs/compose-viewer.md Configuring zoom behavior and rendering strategies for the PdfView component. ```APIDOC ## PdfView(state, zoomSpec, renderSpec) ### Description The primary component for displaying PDF documents in Compose. It accepts specifications for zoom behavior and rendering strategies. ### Parameters - **state** (PdfState) - Required - The state object managing the PDF document. - **zoomSpec** (PdfZoomSpec) - Optional - Configuration for pinch, double-tap, pan, and zoom bounds. Use `PdfZoomSpec.Disabled` to disable zoom. - **renderSpec** (PdfRenderSpec) - Optional - Configuration for how pages are rendered (Rasterized or Vectorized). ### Usage Example ```kotlin val spec = PdfZoomSpec( pinchEnabled = true, doubleTapEnabled = true, panEnabled = true, minZoom = 1f, maxZoom = 8f, doubleTapZoom = 2.5f, resetZoomOnPageChange = true ) PdfView(state, zoomSpec = spec) ``` ``` ```APIDOC ## PdfRenderSpec.Rasterized ### Description Rasterizes pages into bitmaps. Best for complex content and smooth gestures. ### Parameters - **quality** (Float) - Optional - Supersampling multiplier (default 1.0). - **maxBitmapLongSide** (Int) - Optional - Memory cap for the longest side (default 4096). - **rerasterizeOnZoom** (Boolean) - Optional - Re-render at settled zoom for crispness (default true). - **preserveHairlines** (Boolean) - Optional - Compensate sub-pixel strokes (default true). ### Usage Example ```kotlin val spec = PdfRenderSpec.Rasterized( quality = 1f, maxBitmapLongSide = 4096, rerasterizeOnZoom = true, preserveHairlines = true ) PdfView(state, renderSpec = spec) ``` ``` ```APIDOC ## PdfRenderSpec.Vectorized ### Description Executes page content directly into a live Canvas. Best for simple pages and memory-constrained environments. ### Parameters - **hairlineWidthPx** (Float) - Optional - Minimum stroke width in device pixels (default 1.0). ### Usage Example ```kotlin val spec = PdfRenderSpec.Vectorized( hairlineWidthPx = 1f ) PdfView(state, renderSpec = spec) ``` ``` -------------------------------- ### View a full PDF in Compose Source: https://github.com/yuroyami/kitepdf/blob/main/docs/recipes.md Integrate a full PDF viewer using PdfView and rememberPdfViewState. Supports vertical scrolling, swiping, and pinch-zoom by default. ```kotlin import io.github.yuroyami.kitepdf.compose.PdfView import io.github.yuroyami.kitepdf.compose.rememberPdfViewState @Composable fun PdfViewer(doc: PdfDocument) { PdfView( state = rememberPdfViewState(doc), modifier = Modifier.fillMaxSize(), ) } ``` -------------------------------- ### Iterating Article Threads Source: https://github.com/yuroyami/kitepdf/blob/main/docs/reading.md Access reading-order sequences for multi-column layouts by iterating through article threads. ```kotlin for (thread in doc.articleThreads) { println("Thread with ${thread.beads.size} beads") } ``` -------------------------------- ### Build MuPDF Oracle Source: https://github.com/yuroyami/kitepdf/blob/main/kitepdf-native-renderer/DIFFTEST.md Compiles the MuPDF mutool binary from source without optional dependencies. ```bash make -C mupdf-master build=release HAVE_X11=no HAVE_GLUT=no mujs=no -j4 # → mupdf-master/build/release/mutool ``` -------------------------------- ### Implement horizontal pager layout with custom controls Source: https://github.com/yuroyami/kitepdf/blob/main/docs/recipes.md Create a custom PDF viewer with horizontal paging and external navigation controls using PdfView state. ```kotlin @Composable fun PdfPager(doc: PdfDocument) { val state = rememberPdfViewState(doc) val scope = rememberCoroutineScope() Column(Modifier.fillMaxSize()) { PdfView( state = state, modifier = Modifier.weight(1f), layout = PdfLayout.Paged(Orientation.Horizontal), pageSpacing = 12.dp, ) Row(Modifier.padding(8.dp), horizontalArrangement = Arrangement.spacedBy(8.dp)) { Button(onClick = { scope.launch { state.previousPage() } }) { Text("← Prev") } Text("${state.currentPage + 1} / ${state.pageCount}") Button(onClick = { scope.launch { state.nextPage() } }) { Text("Next →") } } } } ``` -------------------------------- ### Render PDF page to image files Source: https://github.com/yuroyami/kitepdf/blob/main/docs/getting-started.md Encodes a PDF page into PNG or JPEG format at a specified scale. ```kotlin import io.github.yuroyami.kitepdf.nativerenderer.AwtPdfRasterizer import java.io.File val page = doc.pages[0] // Render at 2× scale (e.g. for print or high-DPI screenshots) val pngBytes = AwtPdfRasterizer.encodeToPng(page, scale = 2.0) File("page-0.png").writeBytes(pngBytes) // Or JPEG val jpegBytes = AwtPdfRasterizer.encodeToJpeg(page, scale = 1.0) File("page-0.jpg").writeBytes(jpegBytes) ``` -------------------------------- ### Apply a watermark to all pages Source: https://github.com/yuroyami/kitepdf/blob/main/docs/editing.md Iterate through document pages to apply a consistent watermark overlay. ```kotlin // A watermark on every page for (page in doc.pages) { editor.stampPage(page) { setFillGray(0.9) // Text baseline at (50, 50) text(StandardFont.Helvetica, 24.0, 50.0, 50.0, "Watermark") } } ``` -------------------------------- ### Accessing Page Labels Source: https://github.com/yuroyami/kitepdf/blob/main/docs/reading.md Retrieve formatted page labels, falling back to the one-based index if no labels are defined. ```kotlin for (page in doc.pages) { println("Label: ${page.label}") // "1", "i", "A-1", etc. } ``` -------------------------------- ### Run Differential Tests Source: https://github.com/yuroyami/kitepdf/blob/main/kitepdf-native-renderer/DIFFTEST.md Executes the differential rendering test suite using Gradle. ```bash ./gradlew :kitepdf-native-renderer:jvmTest --tests "*DifferentialTest*" ``` -------------------------------- ### Run PDF differential tests Source: https://github.com/yuroyami/kitepdf/blob/main/corpus/README.md Command to execute the PDF differential test suite using the mutool oracle. ```bash MUTOOL="$(which mutool)" ./gradlew :kitepdf-native-renderer:jvmTest --tests "*DifferentialTest*" ``` -------------------------------- ### Listing Attachments Source: https://github.com/yuroyami/kitepdf/blob/main/docs/reading.md Iterate through embedded files attached to the document. ```kotlin for (attachment in doc.attachments) { println("${attachment.filename}: ${attachment.size} bytes") } ``` -------------------------------- ### Drive external zoom and pan controls Source: https://github.com/yuroyami/kitepdf/blob/main/docs/recipes.md Integrates custom UI components with PdfViewState to manage zoom levels and reset functionality. ```kotlin @Composable fun CustomZoomControls(state: PdfViewState) { var zoomValue by remember { mutableFloatStateOf(state.zoom) } val scope = rememberCoroutineScope() Column(Modifier.padding(8.dp)) { Slider( value = zoomValue, onValueChange = { zoomValue = it }, valueRange = 1f..8f, onValueChangeFinished = { scope.launch { state.setZoom(zoomValue) } }, ) Button(onClick = { scope.launch { state.resetZoom() } }) { Text("Reset") } Button(onClick = { scope.launch { state.animateZoomTo(2f) } }) { Text("2x") } } } ``` -------------------------------- ### Display Thumbnail Strip Source: https://github.com/yuroyami/kitepdf/blob/main/docs/compose-viewer.md Render a horizontal carousel of tappable page thumbnails for quick navigation. ```kotlin PdfThumbnailStrip( state, modifier = Modifier.fillMaxWidth(), thumbnailHeight = 72.dp, spacing = 8.dp, selectedBorderColor = Color.Blue, pageBackground = Color.White, ) ``` -------------------------------- ### EpubDocument.withSettings Source: https://github.com/yuroyami/kitepdf/blob/main/docs/epub.md Applies reader settings to an existing EpubDocument instance to re-flow the content. ```APIDOC ## EpubDocument.withSettings(settings: EpubSettings) ### Description Returns a new EpubDocument instance with updated reader settings applied, reusing the underlying DOM and resources. ### Parameters - **settings** (EpubSettings) - Required - The settings object containing font, color, and layout overrides. ``` -------------------------------- ### Rasterize PDF on JVM Source: https://github.com/yuroyami/kitepdf/blob/main/docs/platforms.md Render a PDF page to a PNG byte array using the AWT graphics stack. ```kotlin // JVM / Desktop val png: ByteArray = AwtPdfRasterizer.encodeToPng(doc.pages[0], scale = 2.0) File("preview.png").writeBytes(png) ``` -------------------------------- ### Convert coordinate systems Source: https://github.com/yuroyami/kitepdf/blob/main/docs/writing.md Convert from a top-left origin coordinate system to the PDF bottom-left origin system. ```kotlin // Convert from top-left (like Android) to bottom-left (PDF) val pageHeight = 792.0 val textY_pdf = pageHeight - textY_topLeft content.text(font, size, textX, textY_pdf, "Text") ``` -------------------------------- ### PdfViewState Navigation Methods Source: https://github.com/yuroyami/kitepdf/blob/main/docs/compose-viewer.md Methods for navigating through pages in the PDF viewer. These methods are suspending and should be called from a coroutine scope. ```APIDOC ## Navigation Methods ### Description Methods to control page navigation within the PDF viewer. ### Methods - **scrollToPage(pageIndex: Int)** - Jump to a specific page immediately. - **animateScrollToPage(pageIndex: Int)** - Smoothly animate to a specific page. - **nextPage()** - Navigate to the next page. - **previousPage()** - Navigate to the previous page. ``` -------------------------------- ### Rasterize PDF pages to images Source: https://github.com/yuroyami/kitepdf/blob/main/README.md Convert PDF pages to image bytes using either the platform-native renderer or the cross-platform Skia renderer. ```kotlin // kitepdf-native-renderer, JVM (AWT). Also CoreGraphics (Apple), android.graphics, Canvas2D (JS). val awtPng = AwtPdfRasterizer.encodeToPng(doc.pages[0], scale = 2.0) // kitepdf-skia, one common API via Skiko (JVM, Android, Apple, Linux, web). val skiaPng = PdfPageRasterizer.encodeToPng(doc.pages[0], scale = 2.0) ``` -------------------------------- ### Navigate PDF Pages Source: https://github.com/yuroyami/kitepdf/blob/main/docs/compose-viewer.md Use suspending functions within a coroutine scope to jump, animate, or step through pages. ```kotlin scope.launch { // Jump to a page (immediately) state.scrollToPage(2) // Animate to a page (smooth scroll) state.animateScrollToPage(2) // One page at a time state.nextPage() state.previousPage() } ``` -------------------------------- ### Create and edit PDF documents Source: https://github.com/yuroyami/kitepdf/blob/main/docs/index.md Modify existing PDFs by filling forms or redacting regions, or build new documents using a content DSL. ```kotlin // Fill a form field and save (append-only) doc.edit().apply { setTextFieldValue(doc.formField("Name")!!, "Jane Doe") }.saveIncremental() // Truly redact a region (the underlying content is removed, not covered) doc.edit().apply { redactRegion(doc.pages[0], Rectangle(72.0, 700.0, 320.0, 720.0)) }.saveRewritten() // Build a new PDF from scratch PdfBuilder() .page { text(StandardFont.HelveticaBold, 24.0, x = 72.0, y = 720.0, "Invoice") setFillRgb(0.9, 0.95, 1.0); rectangle(72.0, 600.0, 200.0, 80.0); fill() } .build() ``` -------------------------------- ### Open PDF on Android Source: https://github.com/yuroyami/kitepdf/blob/main/docs/getting-started.md Load PDF bytes from application resources or the cache directory. ```kotlin import io.github.yuroyami.kitepdf.KitePDF // From resources or assets val bytes = context.resources.openRawResource(R.raw.sample).readBytes() val doc = KitePDF.open(bytes) // Or from a file val bytes = File(context.cacheDir, "sample.pdf").readBytes() val doc = KitePDF.open(bytes) ``` -------------------------------- ### Add headless renderer dependency Source: https://github.com/yuroyami/kitepdf/blob/main/README.md Include either the native or Skia-based renderer artifact for server-side or non-Compose PDF processing. ```kotlin implementation("io.github.yuroyami:kitepdf-native-renderer:0.2.0") // or kitepdf-skia-renderer ``` -------------------------------- ### EpubDocument.open Source: https://github.com/yuroyami/kitepdf/blob/main/docs/epub.md Opens an EPUB document from bytes. Throws EpubFormatException on failure. ```APIDOC ## EpubDocument.open(epubBytes: ByteArray, pageWidth: Double?, pageHeight: Double?, fontSize: Double?, margin: Double?) ### Description Opens an EPUB document. If dimensions are provided, the book is reflowed to those specifications. ### Parameters - **epubBytes** (ByteArray) - Required - The raw EPUB file data. - **pageWidth** (Double) - Optional - Target page width in points. - **pageHeight** (Double) - Optional - Target page height in points. - **fontSize** (Double) - Optional - Base font size in points. - **margin** (Double) - Optional - Page margin in points. ``` -------------------------------- ### Retrieving Document Language Source: https://github.com/yuroyami/kitepdf/blob/main/docs/reading.md Access the document's language using the BCP 47 tag format. ```kotlin println("Language: ${doc.language}") // "en-US", "fr-CA", null ``` -------------------------------- ### Open password-protected PDF Source: https://github.com/yuroyami/kitepdf/blob/main/docs/getting-started.md Provide a byte array password to open encrypted PDF documents. ```kotlin import io.github.yuroyami.kitepdf.PdfDocument val doc = PdfDocument.open(bytes, "secret".encodeToByteArray()) ``` -------------------------------- ### Export Compose ImageBitmap to PNG Source: https://github.com/yuroyami/kitepdf/blob/main/docs/rendering.md Convert a rendered ImageBitmap from the Compose viewer into a PNG byte array and save it to a file. ```kotlin import androidx.compose.ui.graphics.ImageBitmap import io.github.yuroyami.kitepdf.compose.encodeToPng import java.io.File // Assuming you've rendered a page into an ImageBitmap (e.g., via PdfView's onPageRendered) val imageBitmap: ImageBitmap = /* ... */ val pngBytes = imageBitmap.encodeToPng() ?: return // Write to disk File("export.png").writeBytes(pngBytes) ``` -------------------------------- ### Search and navigate text Source: https://github.com/yuroyami/kitepdf/blob/main/docs/epub.md Performs full-book searches and retrieves structured text or page indices for internal links. ```kotlin // Engine-level search across the whole book. for (hit in book.search("whale")) { println("page ${hit.pageIndex}: ${hit.text}") // hit.quads are page-space rectangles, ready for highlight overlays } // Structured text with geometry, per page. val text = book.pages[0].textContent() // Internal links resolve to page indices. val target: Int? = book.pageOf("chapter2.xhtml#section-3") ``` -------------------------------- ### Configure Android or JVM Dependencies Source: https://github.com/yuroyami/kitepdf/blob/main/docs/platforms.md Add these dependencies to your standard dependencies block for Android or JVM projects. ```kotlin implementation("io.github.yuroyami:kitepdf:0.2.0") implementation("io.github.yuroyami:kitepdf-native-renderer:0.2.0") // or implementation("io.github.yuroyami:kitepdf-skia-renderer:0.2.0") ``` -------------------------------- ### Configure Vectorized Rendering Source: https://github.com/yuroyami/kitepdf/blob/main/docs/platforms.md Use the Vectorized variant for live rendering at layout resolution, providing crisp deep zoom and minimal memory usage. ```kotlin renderSpec = PdfRenderSpec.Vectorized( hairlineWidthPx = 1f, // minimum stroke width in device pixels (ISO hairline default) ) ``` -------------------------------- ### Access metadata and table of contents Source: https://github.com/yuroyami/kitepdf/blob/main/docs/epub.md Retrieves EPUB-specific metadata and iterates through the table of contents to resolve page locations. ```kotlin val meta = book.epubMetadata // EPUB-specific: identifier, cover path, direction, ... println("${meta.title} by ${meta.creators.joinToString()}") for (entry in book.tableOfContents.entries) { val page = entry.href?.let { book.pageOf(it) } println("${entry.label} -> page $page") } ``` -------------------------------- ### Check document permissions Source: https://github.com/yuroyami/kitepdf/blob/main/docs/recipes.md Verify document access rights based on the security handler's bit-flags. ```kotlin val perms = doc.permissions if (!perms.canPrint) { println("User cannot print this document") } ```