Hush lite wallet for Android
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

66 lines
2.0 KiB

package cash.z.ecc.android.ui.scan
import androidx.camera.core.ImageAnalysis
import androidx.camera.core.ImageProxy
import cash.z.ecc.android.util.twig
import com.google.zxing.BinaryBitmap
import com.google.zxing.NotFoundException
import com.google.zxing.PlanarYUVLuminanceSource
import com.google.zxing.Reader
import com.google.zxing.common.HybridBinarizer
import com.google.zxing.qrcode.QRCodeReader
class QrAnalyzer(val scanCallback: (qrContent: String, image: ImageProxy) -> Unit) :
ImageAnalysis.Analyzer {
private val reader = QRCodeReader()
override fun analyze(image: ImageProxy) {
image.toBinaryBitmap().let { bitmap ->
val qrContent = bitmap.decodeWith(reader) ?: bitmap.flip().decodeWith(reader)
if (qrContent == null) {
image.close()
} else {
onImageScan(qrContent, image)
}
}
}
private fun ImageProxy.toBinaryBitmap(): BinaryBitmap {
return planes[0].buffer.let { buffer ->
ByteArray(buffer.remaining()).also { buffer.get(it) }
}.let { bytes ->
PlanarYUVLuminanceSource(bytes, width, height, 0, 0, width, height, false)
}.let { source ->
BinaryBitmap(HybridBinarizer(source))
}
}
private fun BinaryBitmap.decodeWith(reader: Reader): String? {
return try {
reader.decode(this).toString()
} catch (e: NotFoundException) {
// these happen frequently. Whenever no QR code is found in the frame. No need to log.
null
} catch (e: Throwable) {
twig("Error while scanning QR: $e")
twig(e)
null
}
}
private fun BinaryBitmap.flip(): BinaryBitmap {
blackMatrix.apply {
repeat(width) { w ->
repeat(height) { h ->
flip(w, h)
}
}
}
return this
}
private fun onImageScan(result: String, image: ImageProxy) {
scanCallback(result, image)
}
}