How can I integrate ZXing library in order to use it with new Android Jetpack CameraX?
I know that I've to build an ImageAnalyzer
and inside it I've to use ZXing to decode QR Codes and Barcodes
On click of button_scan_qr_code , CaptureActivity will start scanning using default camera. Once it scans any QR code, it sends back the result to onActivityResult the MainActivity . ZXing also provides online QR Code Generator. Enter the required fields, generate and scan it to get the results.
Google uses ZXing by web search to obtain millions of barcodes on the web indexable. It also creates the foundation of Android’s Barcode Scanner app and is combined into Google Product and Book Search.
It has support for the 1D product, 1D industrial, and 2D barcodes. Google uses ZXing by web search to obtain millions of barcodes on the web indexable. It also creates the foundation of Android’s Barcode Scanner app and is combined into Google Product and Book Search.
To create a new project in Android Studio please refer to How to Create/Start a New Project in Android Studio. Note that select Java as the programming language. Note: Choose API 24 and onwards as Minimum SDK . In order to use the Zxing library in our application we need to add it’s dependency in our application’s gradle file.
Unlike barcodes, the QR codes can be scanned accurately with a smartphone by giving the camera permission to scan. And it doesn’t require any specialized hardware like the barcodes. However, in some smartphones, you may need a QR code scanner for accessing QR codes.
Here below the ImageAnalyzer
I've built up to do that:
class ZxingQrCodeAnalyzer(
private val onQrCodesDetected: (qrCode: Result) -> Unit
) : ImageAnalysis.Analyzer {
companion object {
val reader = MultiFormatReader()
}
/*
https://developer.android.com/training/camerax/configuration
Default resolution: The default target resolution setting is 640x480.
Adjusting both target resolution and corresponding aspect ratio will result
in a best-supported resolution under 1080p (max analysis resolution).
*/
override fun analyze(imageProxy: ImageProxy, rotationDegrees: Int) {
// okay - manage rotation, not needed for QRCode decoding [-;
// okay - manage it for barcode scanning instead!!!
try {
imageProxy.image?.let {
// ImageProxy uses an ImageReader under the hood:
// https://developer.android.com/reference/androidx/camera/core/ImageProxy.html
// That has a default format of YUV_420_888 if not changed.
// https://developer.android.com/reference/android/graphics/ImageFormat.html#YUV_420_888
// https://developer.android.com/reference/android/media/ImageReader.html
if ((it.format == ImageFormat.YUV_420_888
|| it.format == ImageFormat.YUV_422_888
|| it.format == ImageFormat.YUV_444_888)
&& it.planes.size == 3) {
val buffer = it.planes[0].buffer // We get the luminance plane only, since we
// want to binarize it and we don't wanna take color into consideration.
val bytes = ByteArray(buffer.capacity())
buffer.get(bytes)
// Create a LuminanceSource.
val rotatedImage = RotatedImage(bytes, imageProxy.width, imageProxy.height)
rotateImageArray(rotatedImage, rotationDegrees)
val source = PlanarYUVLuminanceSource(rotatedImage.byteArray,
rotatedImage.width,
rotatedImage.height,
0,
0,
rotatedImage.width,
rotatedImage.height,
false)
// Create a Binarizer
val binarizer = HybridBinarizer(source)
// Create a BinaryBitmap.
val binaryBitmap = BinaryBitmap(binarizer)
// Try decoding...
val result: Result
try {
result = reader.decode(binaryBitmap)
onQrCodesDetected(result)
} catch (e: NotFoundException) {
e.printStackTrace()
}
} else {
// Manage other image formats
// TODO - https://developer.android.com/reference/android/media/Image.html
}
}
} catch (ise: IllegalStateException) {
ise.printStackTrace()
}
}
// 90, 180. 270 rotation
private fun rotateImageArray(imageToRotate: RotatedImage, rotationDegrees: Int) {
if (rotationDegrees == 0) return // no rotation
if (rotationDegrees % 90 != 0) return // only 90 degree times rotations
val width = imageToRotate.width
val height = imageToRotate.height
val rotatedData = ByteArray(imageToRotate.byteArray.size)
for (y in 0 until height) { // we scan the array by rows
for (x in 0 until width) {
when (rotationDegrees) {
90 -> rotatedData[x * height + height - y - 1] =
imageToRotate.byteArray[x + y * width] // Fill from top-right toward left (CW)
180 -> rotatedData[width * (height - y - 1) + width - x - 1] =
imageToRotate.byteArray[x + y * width] // Fill from bottom-right toward up (CW)
270 -> rotatedData[y + x * height] =
imageToRotate.byteArray[y * width + width - x - 1] // The opposite (CCW) of 90 degrees
}
}
}
imageToRotate.byteArray = rotatedData
if (rotationDegrees != 180) {
imageToRotate.height = width
imageToRotate.width = height
}
}
}
private data class RotatedImage(var byteArray: ByteArray, var width: Int, var height: Int)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With