package io.flamenet.e2e import java.awt.image.BufferedImage import java.io.File import javax.imageio.ImageIO import kotlin.test.Test /** * Renders QR codes to PNG so an INDEPENDENT decoder can read them back. */ class QrCodeRenderForDecodingTest { @Test fun `render the corpus`() { val out = File(System.getProperty("fnmsg.qr.out") ?: "build/qr-corpus") out.mkdirs() CORPUS.forEachIndexed { index, text -> ImageIO.write(render(text, scale = 8, quiet = 4), "png", File(out, "qr-$index.png")) File(out, "qr-$index.txt").writeText(text) } println("wrote ${CORPUS.size} QR images to ${out.absolutePath}") } private fun render( text: String, scale: Int, quiet: Int, ): BufferedImage { val m = QrCode.encode(text) val side = (m.size + quiet * 2) * scale val image = BufferedImage(side, side, BufferedImage.TYPE_INT_RGB) val g = image.createGraphics() g.color = java.awt.Color.WHITE g.fillRect(0, 0, side, side) g.color = java.awt.Color.BLACK for (r in 0 until m.size) { for (c in 0 until m.size) { if (m[r, c]) g.fillRect((c + quiet) * scale, (r + quiet) * scale, scale, scale) } } g.dispose() return image } companion object { /** * Chosen to cross every version boundary the encoder supports, because * the block layout, the alignment patterns and the version-information * block all change with version and each is its own chance to be wrong. */ val CORPUS: List = listOf( "flamenet:fnid:kx7q2m", // v1 "flamenet:fnid:" + "a".repeat(52) + "@relay1.flamenet.io", // a real address "flamenet:fnid:" + "b".repeat(52) + "@" + "long".repeat(8) + ".example.com", // Exactly full, version by version: data codewords minus the mode // nibble and character count. "x".repeat(14), // v1 "x".repeat(26), // v2 "x".repeat(42), // v3 "x".repeat(62), // v4 "x".repeat(84), // v5 "x".repeat(106), // v6 "x".repeat(122), // v7, first version with a version-information block "x".repeat(152), // v8, two block groups of different sizes "x".repeat(180), // v9 "x".repeat(213), // v10, the largest this encoder makes ) } }