1package com.peachpasswords.codex23import android.graphics.Bitmap4import android.graphics.Color5import android.graphics.Paint6import android.graphics.Rect7import android.graphics.pdf.PdfDocument8import java.io.ByteArrayOutputStream910111213141516object CodexPdf {17 private const val PAGE_W = 59518 private const val PAGE_H = 84219 private const val MARGIN = 36f20 private const val HEADER_H = 54f21 private const val FOOTER_H = 28f2223 fun render(aztecs: List<Bitmap>, manifest: CodexManifest): ByteArray {24 val doc = PdfDocument()25 val gridTop = MARGIN + HEADER_H26 val gridW = PAGE_W - 2 * MARGIN27 val gridH = PAGE_H - gridTop - MARGIN - FOOTER_H28 val cellW = gridW / CODES_PER_ROW29 val cellH = gridH / CODES_PER_COL30 val cell = minOf(cellW, cellH)31 32 33 val pad = cell * 0.05f3435 val title = Paint().apply { color = Color.BLACK; textSize = 16f; isAntiAlias = true; isFakeBoldText = true }36 val mono = Paint().apply { color = Color.rgb(0x55, 0x55, 0x55); textSize = 9f; isAntiAlias = true }37 val codePaint = Paint().apply { isFilterBitmap = false }3839 val pageCount = Math.ceil(aztecs.size.toDouble() / CODES_PER_PAGE).toInt().coerceAtLeast(1)40 for (page in 0 until pageCount) {41 val info = PdfDocument.PageInfo.Builder(PAGE_W, PAGE_H, page + 1).create()42 val pg = doc.startPage(info)43 val canvas = pg.canvas4445 canvas.drawText("Peach Codex", MARGIN, MARGIN + 18f, title)46 canvas.drawText(manifest.verifyCode, MARGIN, MARGIN + 36f, mono)47 canvas.drawText(48 "${manifest.entryCount} entries · ${manifest.totalChunks} codes · keep with your recovery words",49 MARGIN + 120f, MARGIN + 36f, mono,50 )5152 val first = page * CODES_PER_PAGE53 val last = minOf(first + CODES_PER_PAGE, aztecs.size)54 for (idx in first until last) {55 val slot = idx - first56 val row = slot / CODES_PER_ROW57 val col = slot % CODES_PER_ROW58 val left = MARGIN + col * cell + pad59 val top = gridTop + row * cell + pad60 val dst = Rect(left.toInt(), top.toInt(), (left + cell - 2 * pad).toInt(), (top + cell - 2 * pad).toInt())61 canvas.drawBitmap(aztecs[idx], null, dst, codePaint)62 }6364 canvas.drawText(65 "page ${page + 1} of $pageCount · ${manifest.verifyCode}",66 MARGIN, PAGE_H - MARGIN + 4f, mono,67 )68 doc.finishPage(pg)69 }7071 val out = ByteArrayOutputStream()72 doc.writeTo(out)73 doc.close()74 return out.toByteArray()75 }76}