Last active
September 29, 2023 10:19
-
-
Save Radiokot/f83f6d09ae48bf253a433dcb5e02765d to your computer and use it in GitHub Desktop.
A scalable ZXing QR code drawable, which supports tint and transparency. Unlike a 515x515 bitmap commonly used in Android QR guides, the drawable is always sharp.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.content.res.ColorStateList | |
import android.graphics.Canvas | |
import android.graphics.Color | |
import android.graphics.ColorFilter | |
import android.graphics.Paint | |
import android.graphics.PixelFormat | |
import android.graphics.RectF | |
import android.graphics.drawable.Drawable | |
import androidx.annotation.ColorInt | |
import com.google.zxing.common.BitMatrix | |
class BitMatrixDrawable( | |
private val bitMatrix: BitMatrix, | |
@ColorInt | |
squareColor: Int = Color.BLACK, | |
) : Drawable() { | |
private val defaultSquareColor = squareColor | |
private val squarePaint = Paint().apply { | |
color = squareColor | |
// Stroke is to compensate for float rounding. | |
style = Paint.Style.FILL_AND_STROKE | |
strokeWidth = 1f | |
} | |
private var squareWidth: Float = 1f | |
private var squareHeight: Float = 1f | |
override fun setBounds(left: Int, top: Int, right: Int, bottom: Int) { | |
super.setBounds(left, top, right, bottom) | |
squareWidth = (right - left).toFloat() / bitMatrix.width | |
squareHeight = (bottom - top).toFloat() / bitMatrix.height | |
} | |
override fun draw(canvas: Canvas) { | |
(0 until bitMatrix.width).forEach { x -> | |
(0 until bitMatrix.height).forEach { y -> | |
if (bitMatrix[x, y]) { | |
val left = x * squareWidth | |
val top = y * squareHeight | |
canvas.drawRect( | |
RectF( | |
left, | |
top, | |
left + squareWidth, | |
top + squareHeight | |
), | |
squarePaint | |
) | |
} | |
} | |
} | |
} | |
override fun setAlpha(alpha: Int) { | |
squarePaint.alpha = alpha | |
} | |
override fun setColorFilter(colorFilter: ColorFilter?) { | |
squarePaint.colorFilter = colorFilter | |
} | |
override fun setTintList(tint: ColorStateList?) { | |
if (tint != null) { | |
squarePaint.color = tint.defaultColor | |
} else { | |
squarePaint.color = defaultSquareColor | |
} | |
invalidateSelf() | |
} | |
override fun getOpacity(): Int = PixelFormat.TRANSLUCENT | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.graphics.Color | |
import androidx.annotation.ColorInt | |
import androidx.core.graphics.drawable.TintAwareDrawable | |
import com.google.zxing.BarcodeFormat | |
import com.google.zxing.EncodeHintType | |
import com.google.zxing.qrcode.QRCodeWriter | |
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel | |
class QrDrawableFactory { | |
private val writer = QRCodeWriter() | |
suspend fun getDrawable( | |
content: String, | |
@ColorInt | |
squareColor: Int = Color.BLACK, | |
errorCorrectionLevel: ErrorCorrectionLevel = ErrorCorrectionLevel.M, | |
margin: Int = 0, | |
) = writer.encode( | |
content, | |
BarcodeFormat.QR_CODE, | |
// 1x1 matrix yields the minimum size matrix for the data size. | |
1, 1, | |
mapOf( | |
EncodeHintType.ERROR_CORRECTION to errorCorrectionLevel, | |
EncodeHintType.MARGIN to margin, | |
) | |
).let { bitMatrix -> | |
checkNotNull(bitMatrix) | |
BitMatrixDrawable( | |
bitMatrix = bitMatrix, | |
squareColor = squareColor, | |
) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment