Skip to content

Instantly share code, notes, and snippets.

@SherifMuSherif
Forked from dev-niiaddy/QRPainter.kt
Last active January 28, 2024 06:52
Show Gist options
  • Save SherifMuSherif/c305efdd0f8cab7ba3b41cf9149455ea to your computer and use it in GitHub Desktop.
Save SherifMuSherif/c305efdd0f8cab7ba3b41cf9149455ea to your computer and use it in GitHub Desktop.
A function to encode text as a QR code using BitmapPainter and zxing-core for use in Jetpack Compose with Image composable. Note: This function has been optimized to set all pixels at once using setPixels, which significantly improves performance, especially when used in a LazyColumn. Thanks @dev-niiaddy!
@Composable
fun rememberQrBitmapPainter(
content: String,
size: Dp = 150.dp,
padding: Dp = 0.dp
): BitmapPainter {
val density = LocalDensity.current
val sizePx = with(density) { size.roundToPx() }
val paddingPx = with(density) { padding.roundToPx() }
var bitmap by remember(content) {
mutableStateOf<Bitmap?>(null)
}
LaunchedEffect(bitmap) {
if (bitmap != null) return@LaunchedEffect
launch(Dispatchers.IO) {
val qrCodeWriter = QRCodeWriter()
val encodeHints = mutableMapOf<EncodeHintType, Any?>()
.apply {
this[EncodeHintType.MARGIN] = paddingPx
}
val bitmapMatrix = try {
qrCodeWriter.encode(
content, BarcodeFormat.QR_CODE,
sizePx, sizePx, encodeHints
)
} catch (ex: WriterException) {
null
}
val matrixWidth = bitmapMatrix?.width ?: sizePx
val matrixHeight = bitmapMatrix?.height ?: sizePx
val newBitmap = Bitmap.createBitmap(
bitmapMatrix?.width ?: sizePx,
bitmapMatrix?.height ?: sizePx,
Bitmap.Config.ARGB_8888,
)
val pixels = IntArray(matrixWidth * matrixHeight)
for (x in 0 until matrixWidth) {
for (y in 0 until matrixHeight) {
val shouldColorPixel = bitmapMatrix?.get(x, y) ?: false
val pixelColor = if (shouldColorPixel) Color.BLACK else Color.WHITE
pixels[y * matrixWidth + x] = pixelColor
}
}
newBitmap.setPixels(pixels, 0, matrixWidth, 0, 0, matrixWidth, matrixHeight)
bitmap = newBitmap
}
}
return remember(bitmap) {
val currentBitmap = bitmap ?: Bitmap.createBitmap(
sizePx, sizePx,
Bitmap.Config.ARGB_8888,
).apply { eraseColor(Color.TRANSPARENT) }
BitmapPainter(currentBitmap.asImageBitmap())
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment