package com.peachpasswords.ui.pairing import androidx.camera.core.ImageProxy import com.google.zxing.BinaryBitmap import com.google.zxing.DecodeHintType import com.google.zxing.PlanarYUVLuminanceSource import com.google.zxing.common.GlobalHistogramBinarizer import com.google.zxing.common.HybridBinarizer import com.google.zxing.qrcode.QRCodeReader /** QR-only CameraX decoder for reachability invitations. */ internal object PairingQrFrame { fun decode(image: ImageProxy): String? { val plane = image.planes.getOrNull(0) ?: return null val buffer = plane.buffer val data = ByteArray(buffer.remaining()) buffer.get(data) val width = image.width val height = image.height val luma = if (plane.rowStride == width) { data } else { ByteArray(width * height).also { packed -> for (row in 0 until height) { System.arraycopy( data, row * plane.rowStride, packed, row * width, width, ) } } } val source = PlanarYUVLuminanceSource( luma, width, height, 0, 0, width, height, false, ) val hints = mapOf( DecodeHintType.TRY_HARDER to true, DecodeHintType.POSSIBLE_FORMATS to listOf(com.google.zxing.BarcodeFormat.QR_CODE), ) val attempts = listOf( BinaryBitmap(HybridBinarizer(source)), BinaryBitmap(GlobalHistogramBinarizer(source)), BinaryBitmap(HybridBinarizer(source.rotateCounterClockwise())), ) for (candidate in attempts) { try { return QRCodeReader().decode(candidate, hints).text } catch (_: Exception) { // Try the next lighting/orientation strategy. } } return null } }