PairingQrFrame.kt

2.0 KB · raw

1package com.peachpasswords.ui.pairing23import androidx.camera.core.ImageProxy4import com.google.zxing.BinaryBitmap5import com.google.zxing.DecodeHintType6import com.google.zxing.PlanarYUVLuminanceSource7import com.google.zxing.common.GlobalHistogramBinarizer8import com.google.zxing.common.HybridBinarizer9import com.google.zxing.qrcode.QRCodeReader1011/** QR-only CameraX decoder for reachability invitations. */12internal object PairingQrFrame {13    fun decode(image: ImageProxy): String? {14        val plane = image.planes.getOrNull(0) ?: return null15        val buffer = plane.buffer16        val data = ByteArray(buffer.remaining())17        buffer.get(data)18        val width = image.width19        val height = image.height20        val luma = if (plane.rowStride == width) {21            data22        } else {23            ByteArray(width * height).also { packed ->24                for (row in 0 until height) {25                    System.arraycopy(26                        data,27                        row * plane.rowStride,28                        packed,29                        row * width,30                        width,31                    )32                }33            }34        }35        val source = PlanarYUVLuminanceSource(36            luma,37            width,38            height,39            0,40            0,41            width,42            height,43            false,44        )45        val hints = mapOf(46            DecodeHintType.TRY_HARDER to true,47            DecodeHintType.POSSIBLE_FORMATS to listOf(com.google.zxing.BarcodeFormat.QR_CODE),48        )49        val attempts = listOf(50            BinaryBitmap(HybridBinarizer(source)),51            BinaryBitmap(GlobalHistogramBinarizer(source)),52            BinaryBitmap(HybridBinarizer(source.rotateCounterClockwise())),53        )54        for (candidate in attempts) {55            try {56                return QRCodeReader().decode(candidate, hints).text57            } catch (_: Exception) {58                // Try the next lighting/orientation strategy.59            }60        }61        return null62    }63}