1package com.peachpasswords.codex23import android.graphics.Color4import android.graphics.Paint5import android.graphics.RectF6import android.graphics.pdf.PdfDocument7import com.google.zxing.common.BitMatrix8import java.io.ByteArrayOutputStream91011121314151617181920212223242526object CodexPdf {27 28 29 30 private val PAGE_W = CodexPageLayout.PAGE_WIDTH.toInt()31 private val PAGE_H = CodexPageLayout.PAGE_HEIGHT.toInt()32 private const val MARGIN = CodexPageLayout.MARGIN3334 fun render(aztecs: List<BitMatrix>, manifest: CodexManifest): ByteArray {35 val doc = PdfDocument()3637 val title = Paint().apply { color = Color.BLACK; textSize = 16f; isAntiAlias = true; isFakeBoldText = true }38 val mono = Paint().apply { color = Color.rgb(0x55, 0x55, 0x55); textSize = 9f; isAntiAlias = true }39 40 41 42 val modulePaint = Paint().apply { color = Color.BLACK; isAntiAlias = false }4344 val pageCount = Math.ceil(aztecs.size.toDouble() / CODES_PER_PAGE).toInt().coerceAtLeast(1)45 for (page in 0 until pageCount) {46 val info = PdfDocument.PageInfo.Builder(PAGE_W, PAGE_H, page + 1).create()47 val pg = doc.startPage(info)48 val canvas = pg.canvas4950 canvas.drawText("Peach Codex", MARGIN, MARGIN + 18f, title)51 canvas.drawText(manifest.verifyCode, MARGIN, MARGIN + 36f, mono)52 canvas.drawText(53 "${manifest.entryCount} entries · ${manifest.totalChunks} codes · keep with your recovery words",54 MARGIN + 120f, MARGIN + 36f, mono,55 )5657 val first = page * CODES_PER_PAGE58 val last = minOf(first + CODES_PER_PAGE, aztecs.size)59 for (idx in first until last) {60 val slot = idx - first61 val row = slot / CODES_PER_ROW62 val col = slot % CODES_PER_ROW63 drawAztecVector(64 canvas,65 aztecs[idx],66 CodexPageLayout.codeLeft(col),67 CodexPageLayout.codeTop(row),68 CodexPageLayout.CODE_SIZE,69 modulePaint,70 )71 }7273 canvas.drawText(74 "page ${page + 1} of $pageCount · ${manifest.verifyCode}",75 MARGIN, PAGE_H - MARGIN + 4f, mono,76 )77 doc.finishPage(pg)78 }7980 val out = ByteArrayOutputStream()81 doc.writeTo(out)82 doc.close()83 return out.toByteArray()84 }8586 87888990919293 private fun drawAztecVector(94 canvas: android.graphics.Canvas,95 matrix: BitMatrix,96 left: Float,97 top: Float,98 sizePt: Float,99 paint: Paint,100 ) {101 val n = matrix.width 102 val moduleSize = sizePt / n103 for (y in 0 until n) {104 var x = 0105 while (x < n) {106 if (!matrix.get(x, y)) {107 x++108 continue109 }110 val spanStart = x111 while (x < n && matrix.get(x, y)) x++112 val rectLeft = left + spanStart * moduleSize113 val rectRight = left + x * moduleSize114 val rectTop = top + y * moduleSize115 canvas.drawRect(rectLeft, rectTop, rectRight, rectTop + moduleSize, paint)116 }117 }118 }119}