<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Addy Godwin Nii</title>
    <description>The latest articles on Forem by Addy Godwin Nii (@devniiaddy).</description>
    <link>https://forem.com/devniiaddy</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F607449%2Faae19272-522b-4bbe-a8d0-98f696b97b85.jpeg</url>
      <title>Forem: Addy Godwin Nii</title>
      <link>https://forem.com/devniiaddy</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/devniiaddy"/>
    <language>en</language>
    <item>
      <title>How to Render Text as a QR code in Jetpack Compose</title>
      <dc:creator>Addy Godwin Nii</dc:creator>
      <pubDate>Sun, 08 Jan 2023 07:46:48 +0000</pubDate>
      <link>https://forem.com/devniiaddy/qr-code-with-jetpack-compose-47e</link>
      <guid>https://forem.com/devniiaddy/qr-code-with-jetpack-compose-47e</guid>
      <description>&lt;p&gt;A &lt;strong&gt;QR Code&lt;/strong&gt; (quick repose code) is a type of barcode represented as a matrix of black and white squares. QR codes make it very convenient to represent text such as phone numbers, URLs and other information in an image format.&lt;/p&gt;

&lt;p&gt;In &lt;a href="https://developer.android.com/jetpack/compose" rel="noopener noreferrer"&gt;Jetpack Compose&lt;/a&gt; (Google's new UI toolkit for android apps), it is very easy to create an instance of &lt;code&gt;Painter&lt;/code&gt; which is used to render images and UI elements that can be drawn into a specified bounded area. There are number of &lt;code&gt;Painter&lt;/code&gt; subclasses provided in compose by default but we will be focusing on the &lt;code&gt;BitmapPainter&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Adding Zxing Core Dependency
&lt;/h4&gt;

&lt;p&gt;The first step is to generate the QR code Bitmap image that will be rendered in our UI. To do this we will be using &lt;a href="https://mvnrepository.com/artifact/com.google.zxing/core/3.5.1" rel="noopener noreferrer"&gt;&lt;code&gt;zxing-core&lt;/code&gt;&lt;/a&gt; library by Google. &lt;a href="https://github.com/zxing/zxing" rel="noopener noreferrer"&gt;Zxing&lt;/a&gt; is an open-source barcode scanning libary for Java and Android. Add the dependency to the module level (in a simple project this would be app) &lt;code&gt;build.gradle&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dependencies {
    ...
    implementation "com.google.zxing:core:3.5.1"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Defining the Painter function
&lt;/h4&gt;

&lt;p&gt;Let's define a special type of composable function that returns a value and has a &lt;strong&gt;camelCase&lt;/strong&gt; naming as opposed to our usual composable functions that emit UI with a &lt;strong&gt;PascalCase&lt;/strong&gt; naming and return no value (Unit). This returns the &lt;code&gt;BitmapPainter&lt;/code&gt; that will render the QR code when passed to our &lt;code&gt;Image&lt;/code&gt; composable function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Composable
fun rememberQrBitmapPainter(
    content: String,
    size: Dp = 150.dp,
    padding: Dp = 0.dp
): BitmapPainter {
    return BitmapPainter()
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our &lt;code&gt;rememberQrBitmapPainter&lt;/code&gt; takes a &lt;code&gt;content: String&lt;/code&gt; which represents the text value we want to encode in our QR code, &lt;code&gt;size:Dp&lt;/code&gt; which represent the size(width x height) of our QR specified as a device-independent pixel value (to ensure we have a sharp image on different device with different pixel densities) and the &lt;code&gt;padding:Dp&lt;/code&gt; represent the amount of white space border we want around the generated code. The padding is set to a default of 0 to override/remove the default padding that the zxing library adds when generating a QR bitmap.&lt;/p&gt;

&lt;p&gt;Let's add 4 new variables to our function; &lt;br&gt;
&lt;code&gt;density&lt;/code&gt; to retrieve the current screen density information of the device using the &lt;code&gt;LocalDensity&lt;/code&gt; composition local. The &lt;code&gt;Density&lt;/code&gt; interface provides useful extension functions for performing simple operations like getting the device pixel equivalent of the &lt;code&gt;.dp&lt;/code&gt; values we specified earlier. &lt;br&gt;
The &lt;code&gt;sizePx&lt;/code&gt; and &lt;code&gt;paddingPx&lt;/code&gt; variables are used to represent the pixel equivalent of the size and padding respectively.&lt;br&gt;
A &lt;code&gt;bitmap&lt;/code&gt; mutable state variable to hold the bitmap of the QR code. In order to prevent our bitmap from being recalculated any time the UI is redrawn due to state changes (re-composition) we wrap it with a remember function with a key of content. The content key allows us to re-calculate the bitmap when the value our QR contains changes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@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&amp;lt;Bitmap?&amp;gt;(null)
    }

    return BitmapPainter()
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The QR code is a matrix which consists of multiple pixels whose values if computed on the UI thread, can cause your UI to stutter or hang; for this reason we will make use of a &lt;code&gt;LaunchedEffect&lt;/code&gt; and &lt;code&gt;IO&lt;/code&gt; &lt;code&gt;CoroutineDispatcher&lt;/code&gt; to offload the work required to compute the Bitmap of the QR code off the UI thread:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;LaunchedEffect(bitmap) {
    if (bitmap != null) return@LaunchedEffect

    launch(Dispatchers.IO) {
       val qrCodeWriter = QRCodeWriter()

       val encodeHints = mutableMapOf&amp;lt;EncodeHintType, Any?&amp;gt;()
           .apply {
              this[EncodeHintType.MARGIN] = paddingPx
           }

       val bitmapMatrix = try {
           qrCodeWriter.encode(
              content, BarcodeFormat.QR_CODE,
              sizePx, sizePx, encodeHints
            )
       } catch (ex: WriterException) {
          null
       }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we create a &lt;code&gt;QRCodeWriter&lt;/code&gt; instance which would be used to encode the QR. The &lt;code&gt;encodeHints&lt;/code&gt; variable is a map of &lt;code&gt;EncodeHintType&lt;/code&gt; to values which is used to configure the &lt;code&gt;QRCodeWriter&lt;/code&gt;. A &lt;code&gt;bitmapMatrix&lt;/code&gt; is created by encoding the content string and specifying the height and width of the QR.&lt;/p&gt;

&lt;p&gt;We need to create a bitmap from the bitmapMatrix and set the color for each pixel (either white or black):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;val matrixWidth = bitmapMatrix?.width ?: sizePx
val matrixHeight = bitmapMatrix?.height ?: sizePx

val newBitmap = Bitmap.createBitmap(
    bitmapMatrix?.width ?: sizePx,
    bitmapMatrix?.height ?: sizePx,
    Bitmap.Config.ARGB_8888,
)

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

       newBitmap.setPixel(x, y, pixelColor)
     }
}

bitmap = newBitmap
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In our final step we return an instance of &lt;code&gt;BitmapPainter&lt;/code&gt; with the computed bitmap passed as an argument to it. If the bitmap is yet to be computed, we pass an empty bitmap of equal size with a transparent color. The bitmap is then converted to an image bitmap using the &lt;code&gt;Bitmap.asImagePainter()&lt;/code&gt; extension function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;return remember(bitmap) {
   val currentBitmap = bitmap ?: Bitmap.createBitmap(
       sizePx, sizePx,
       Bitmap.Config.ARGB_8888,
   ).apply { eraseColor(Color.TRANSPARENT) }

   BitmapPainter(currentBitmap.asImageBitmap())
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;How you would use it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Image(
    painter = rememberQrBitmapPainter("https://dev.to"),
    contentDescription = "DEV Communit Code",
    contentScale = ContentScale.FillBounds,
    modifier = Modifier.size(135.dp),
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Putting everything together we get: &lt;a href="https://gist.github.com/dev-niiaddy/8f936062291e3d328c7d10bb644273d0" rel="noopener noreferrer"&gt;QRPainter.kt&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I hope you find this article useful and thanks for reading.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>codereview</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
