目標
実装
言語はKotlinで実装しましたが、生成QRコードの2値情報が作れれば何でも実装できます。
ライブラリは zxing
だけ使います。
build.gradle
repositories {
mavenCentral()
}
dependencies {
implementation("com.google.zxing:core:3.5.0")
}
sizeが0で最小のQRコードができます。
なるべく余白がない文字がいいので、探した所、「█」と「▀」と「▄」の記号を見つけました。縦長なので、縦2列で1つの文字を使います。
実装1
import com.google.zxing.BarcodeFormat import com.google.zxing.EncodeHintType import com.google.zxing.MultiFormatWriter import com.google.zxing.common.BitMatrix import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel class CharQRCodeGenerator { fun generate(text: String) { val hints: MutableMap<EncodeHintType, Any> = mutableMapOf() hints[EncodeHintType.MARGIN] = 0 hints[EncodeHintType.ERROR_CORRECTION] = ErrorCorrectionLevel.L val size = 0 val matrix = MultiFormatWriter().encode( text, BarcodeFormat.QR_CODE, size, size, hints ) println( generateTwoYQRCode(matrix.toList()) ) } private fun BitMatrix.toList(): List<List<Boolean>> { val matrix = this return (0 until matrix.height).map { y -> (0 until matrix.width).map { x -> matrix.get(x, y) } } } private fun generateTwoYQRCode(matrix: List<List<Boolean>>): String { val result = matrix.windowed(size = 2, step = 2, partialWindows = true).map { yList -> (yList[0].indices).map { xIndex -> val yTop = yList[0][xIndex] val yBottom = yList.getOrNull(1)?.get(xIndex) ?: false when { yTop && yBottom -> { "█" } yTop && !yBottom -> { "▀" } !yTop && yBottom -> { "▄" } else -> { " " } } } } return result.joinToString("\n") { row -> row.joinToString("") } } }
出力結果
こちらで https://matsudamper.hatenablog.com/entry/2022/07/24/063640?hoge=hoge&hoge=hoge&hoge=hoge&hoge=hoge
のQRを生成した結果。こちらになりました。
█▀▀▀▀▀█ ▀▄▄▀▀▀▀ ▄█▀▄▀▀▄ █ ▀ ▄ █▀▀▀▀▀█ █ ███ █ ▀ ██▀▄▄▄▀▀███▀▀█▀ █ █ ███ █ █ ▀▀▀ █ ▀▄▀▄ █ █▄█▀▄▄ ▄▀▀█ █ █ ▀▀▀ █ ▀▀▀▀▀▀▀ █ █▄▀▄▀ ▀ █ ▀ █▄▀▄▀▄█ ▀▀▀▀▀▀▀ ▀█ ██▄▀ ▀▀▀▄ ▄▄▀█▄█ ▀██▄▄▄█▄▀▄▄ ▄▀ ▀█▄▄ █▀ ██ █▄▀ ▀▀▄ ▄▄▀▄▀ ▀▄█▀█▀█▀▀█▀▀ ██▄█▄ ▀ ▄▄█▀▀ ▄▄ ▄ ▀ ██▄▄▄██▀▀▀▄█▄█▀ ▄▀ █▀▄▄ ▀█▀▀▄▀ ▀ ▀▄ ▄ █▀▀█ ▀ ▀▄ ▄▀█ ▀▄ ▀▀ ▀▄▄▄ ▄▄█ █ ▄▄██ ▀▄█ ▄ ▄▀█ █▀▀▀ █ ▀█ ▀▀ ▄ ▀▄▄ █▄▀ █ ██ ▄▄▀█▀▄ ▀▄ █ ▀██▀▀▀█▄▄▄ ▀ ██▀█▀▄█ ▀██ ▀▄▀▀▀███ █▀ ▄█ ▀██▀ ▀▀▄ ▀▀▄█▀█ ▄ █▀█ █▄▀█▀▀▄▄▄█ ▄ ▄█▀ ▀██▀▀ █▄▄▄█▄▄▀▀ ██▄▄ ██▄▀▀▄▀ ▄▀ █▀▀▄▀█▀█▄██ ▀▀▀█ ██▀▀▄▄█ ▄▀▄▀██▄▄█▀█ ▀ ▀▀▀ ▀▀█▀█▀▀██▄ ▄▄█ ▀▄█▄▀█▀▀▀█▄██ █▀▀▀▀▀█ ▀██ █ ██ ▀ ▀▀▀██▀▄█ ▀ ██▀ ▀ █ ███ █ █▄█▄▀▄███▀▄▄ ▄▀▄▄▄▄▀▀██▀▀ ▄ ▀ █ ▀▀▀ █ ▄▄█▀ ▀▀▀▄ ▀ ▀▀█▀▄ ▀▀▄█▀▄█▄█ ▀▀▀▀▀▀▀ ▀▀ ▀ ▀▀ ▀ ▀ ▀ ▀ ▀ ▀ ▀
GitHubに貼り付けた様子
こちらでは読み込めませんでした。
しかし、検出パターンを黒く塗りつぶせば読み込めることがわかりました。
実装2
しっかり検出パターンを作らなければいけませんが、文字列の上下にスペースがあるので厳しいです。なので、白黒のパターンを反転させてみることにしました。
import com.google.zxing.BarcodeFormat import com.google.zxing.EncodeHintType import com.google.zxing.MultiFormatWriter import com.google.zxing.common.BitMatrix import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel class CharQRCodeGenerator { fun generate(text: String) { val hints: MutableMap<EncodeHintType, Any> = mutableMapOf() hints[EncodeHintType.MARGIN] = 1 // 周りの縁用にマージンを設定 hints[EncodeHintType.ERROR_CORRECTION] = ErrorCorrectionLevel.L val size = 0 val matrix = MultiFormatWriter().encode( text, BarcodeFormat.QR_CODE, size, size, hints ) println( generateTwoYQRCode(matrix.toList()) ) } private fun BitMatrix.toList(): List<List<Boolean>> { val matrix = this return (0 until matrix.height).map { y -> (0 until matrix.width).map { x -> matrix.get(x, y).not() // 反転させる } } } private fun generateTwoYQRCode(matrix: List<List<Boolean>>): String { val result = matrix.windowed(size = 2, step = 2, partialWindows = true).map { yList -> (yList[0].indices).map { xIndex -> val yTop = yList[0][xIndex] val yBottom = yList.getOrNull(1)?.get(xIndex) ?: false when { yTop && yBottom -> { "█" } yTop && !yBottom -> { "▀" } !yTop && yBottom -> { "▄" } else -> { " " } } } } return result.joinToString("\n") { row -> row.joinToString("") } } }
出力結果
█▀▀▀▀▀▀▀█▀██▀▀▀▀██▀▀█▀▀██▀█▀███▀▀▀▀▀▀▀█ █ █▀▀▀█ ██▄ █▀▀▀█▄▄▀ ▀▀ ▀ ▀▀█ █ █▀▀▀█ █ █ █ █ ██▀█▀▄▄▀▄ ▄▀▀▄▄▄█▀ ▀█ █ █ █ █ █ ▀▀▀▀▀ █▀█ █ █ █ ▄ █ ▄▀▄▀█ █ █ ▀▀▀▀▀ █ █▀▀█▀▀█▀█▄▀ █▄██▀▀▄▀██ ▀▄█▄ █▀█████▀█ █▀ █▄▄ ▀█▀▀█▀▄▀▄ ▀▄▄▄█▀█ ▄ ▄ ▀ ▀▀ ▀█ █▀ ▄ █▄▀█▄▄▀ ████▄█▄ █ ▀██▄ ▀ ▀ █▀▄▀▀█ █▄ ▄▄▄▀▀█▄▄ ▀▀▀▄ █▀▄▀██▄▄ ▄▀█▀▄▄▄ ▀█ █ ██▀▀▄▀▄▄██▄█▀▄▀███▀ █▄▀▄▀█▄██▀▀▄▀ ▀ █ █▀▄█▀▀█▀ ▄▄█ ▄▄█ █ ▄ ▄█▀▀▄▄█ ▀ █▄▀▄██▀█ █▄▀▀▀ ▀▀▀█▄██ ▄▀ ▀▀▄▀█ ▀▄ █ ▀ ▀▀ █▀ █ ██▀▄ ▀▀▀▄ ▄█▀▀▄ ▀ █▄▄█▀ ██ █▀▀ ▄█▄▀█ █▄▄█▀ ▄▀▀▀▀ █▀█▄▄▀▄█▀ █ ▀▄██ █ ▀█ ▄▄ █ █ ▀ ▄▀▀▀ ▄▀▀█▄ ▄ ▀▀▀▄▄ ▄█ ▄ ▀▀▄█▀ ▀█ █ █▀ ▀▄▀ ▀▀▀▀█▄█▄▄▀█▄ ▄▀▄▀ ▀ ▄ ▀▄█ █▀▀▀▀▀▀▀█▄▀ ▀█ ▄ ▀█▄ ▄▀▀▀ █ █▀█ ▄▀█ █ █▀▀▀█ █▀█ ▄▀▄▀ ▀████▀█▄▄█ ▀▀▀ ▄██▀█ █ █ █ █▄▄ █▄ █▄▄▀▄▀ ▄█▀ ▄▀▀█ █▀█ █ ▀▀▀▀▀ █ ▄█▀██▀▀▄██▀██▀▄█ █▀█ ▄▀▄▄▄ █ ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
GitHubに貼り付けた様子
こちらは読み込めました。
おわりに
GitHubが画像アップロードAPIを提供していなくて、IssueにQRコードを貼り付けるのが困難なので、これで解決しました。