package eu.geyskens.pdfscan.pdf import android.graphics.Bitmap import android.graphics.Canvas import android.graphics.Color import android.graphics.Paint import android.graphics.Rect import android.graphics.pdf.PdfDocument import java.io.File import java.io.FileOutputStream /** How each PDF page is sized relative to its scanned image. */ enum class PageSizeMode { A4, ORIGINAL } object PdfBuilder { // A4 in PostScript points (1/72"): 210 x 297 mm. private const val A4_WIDTH_PT = 595 private const val A4_HEIGHT_PT = 842 /** * Writes [pages] into a single multi-page PDF at [output]. * With [PageSizeMode.A4] each image is centered and scaled to fit an A4 page * (portrait or landscape chosen per image); with ORIGINAL the page matches the image. */ fun build(pages: List, output: File, mode: PageSizeMode = PageSizeMode.A4) { require(pages.isNotEmpty()) { "Cannot build a PDF with no pages." } val doc = PdfDocument() val paint = Paint(Paint.FILTER_BITMAP_FLAG or Paint.ANTI_ALIAS_FLAG) try { pages.forEachIndexed { index, bitmap -> val (pageW, pageH) = when (mode) { PageSizeMode.ORIGINAL -> bitmap.width to bitmap.height PageSizeMode.A4 -> if (bitmap.width >= bitmap.height) A4_HEIGHT_PT to A4_WIDTH_PT // landscape else A4_WIDTH_PT to A4_HEIGHT_PT } val info = PdfDocument.PageInfo.Builder(pageW, pageH, index + 1).create() val page = doc.startPage(info) val canvas = page.canvas canvas.drawColor(Color.WHITE) canvas.drawBitmap(bitmap, null, fitRect(bitmap, pageW, pageH), paint) doc.finishPage(page) } FileOutputStream(output).use { doc.writeTo(it) } } finally { doc.close() } } /** Largest centered rect inside the page that preserves the bitmap's aspect ratio. */ private fun fitRect(bitmap: Bitmap, pageW: Int, pageH: Int): Rect { val scale = minOf(pageW.toFloat() / bitmap.width, pageH.toFloat() / bitmap.height) val w = (bitmap.width * scale).toInt() val h = (bitmap.height * scale).toInt() val left = (pageW - w) / 2 val top = (pageH - h) / 2 return Rect(left, top, left + w, top + h) } }