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.QRCodeReader101112internal 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 59 }60 }61 return null62 }63}