You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Kotlin+Jetpack Compose中用ZXing识别彩色二维码

ZXing识别彩色二维码失败的解决办法

我正在使用ZXing在Kotlin中识别二维码,黑白二维码识别效果良好,但彩色二维码无法被识别,想了解解决方法。

可正常识别的黑白二维码:
黑白二维码

无法识别的彩色二维码:
彩色二维码


当前实现代码与配置

CaptureActivityPortrait.kt

class CaptureActivityPortrait: CaptureActivity() {
}

build.gradle

implementation("com.journeyapps:zxing-android-embedded:4.3.0")

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="co.edu.ut.jrbustosm.calina"
    xmlns:tools="http://schemas.android.com/tools">

    <uses-permission android:name="android.permission.CAMERA" />
    <uses-sdk tools:overrideLibrary="com.google.zxing.client.android" />
    ....
    <application
        ....
        android:hardwareAccelerated="true"
        ....
        >
        <activity
            android:name=".MainActivity"
            ....
            android:screenOrientation="portrait"
            tools:replace="android:screenOrientation"
            ....
            >
        ....
        </activity>
        <activity
            android:name=".CaptureActivityPortrait"
            android:screenOrientation="sensorPortrait"
            android:stateNotNeeded="true"
            android:theme="@style/zxing_CaptureTheme"
            android:windowSoftInputMode="stateAlwaysHidden" />
    </application>
</manifest>

AnyFile.kt

val scanLauncher = rememberLauncherForActivityResult(
    contract = ScanContract(),
) { result ->
    if (result.contents != null) {/*do something with result*/}
}

val scanOptions = ScanOptions()
scanOptions.setDesiredBarcodeFormats(ScanOptions.QR_CODE)
scanOptions.setOrientationLocked(true)
scanOptions.setPrompt("Reading QR code")
scanOptions.setBeepEnabled(false)
scanOptions.setCaptureActivity(CaptureActivityPortrait().javaClass)

scanLauncher.launch(scanOptions)

解决方法

ZXing默认识别逻辑依赖高对比度黑白像素区分,彩色二维码色块对比度不足时会触发识别失败,可通过以下方式解决:

1. 自定义摄像头预览帧处理,转灰度图增强对比度

继承CaptureActivity并覆盖预览回调方法,将彩色帧转为灰度图后再交给ZXing识别:

class CaptureActivityPortrait : CaptureActivity() {
    override fun createCameraPreviewCallback(): CameraPreviewCallback {
        return object : CameraPreviewCallback() {
            override fun onPreviewFrame(data: ByteArray?, camera: Camera?) {
                data?.let {
                    val parameters = camera?.parameters
                    val size = parameters?.previewSize ?: return
                    // 提取YUV数据中的Y分量(即灰度信息)
                    val grayData = ByteArray(size.width * size.height)
                    System.arraycopy(it, 0, grayData, 0, size.width * size.height)
                    // 传入灰度数据进行识别
                    super.onPreviewFrame(grayData, camera)
                } ?: super.onPreviewFrame(data, camera)
            }
        }
    }
}

注:若使用CameraX版本的ZXing库,需调整为处理ImageProxy的逻辑,核心仍是提取灰度通道。

2. 配置解码提示,放宽对比度要求

通过DecodeHintType参数强制ZXing启用更复杂的识别逻辑,适配低对比度条码:

val scanOptions = ScanOptions()
// 保留原有配置
scanOptions.setDesiredBarcodeFormats(ScanOptions.QR_CODE)
scanOptions.setOrientationLocked(true)
scanOptions.setPrompt("扫描二维码")
scanOptions.setBeepEnabled(false)
scanOptions.setCaptureActivity(CaptureActivityPortrait::class.java)

// 添加解码提示
val hints = mutableMapOf<DecodeHintType, Any>()
hints[DecodeHintType.TRY_HARDER] = true // 启用高强度识别模式
scanOptions.setDecodeHints(hints)

scanLauncher.launch(scanOptions)

3. 升级ZXing依赖版本

部分第三方维护的ZXing分支已针对彩色条码做优化,尝试升级至最新稳定版:

implementation("com.journeyapps:zxing-android-embedded:4.3.0")
implementation("com.google.zxing:core:3.5.2") // 确保core库版本匹配

4. 预处理本地彩色图片(若识别本地二维码)

如果是识别本地存储的彩色二维码图片,先转高对比度灰度图再解码:

fun decodeColorQrCode(bitmap: Bitmap): String? {
    // 转为灰度图
    val grayBitmap = Bitmap.createBitmap(bitmap.width, bitmap.height, Bitmap.Config.ARGB_8888)
    val canvas = Canvas(grayBitmap)
    val paint = Paint().apply {
        colorFilter = ColorMatrixColorFilter(ColorMatrix().apply { setSaturation(0f) })
    }
    canvas.drawBitmap(bitmap, 0f, 0f, paint)
    
    // ZXing解码灰度图
    val source = BitmapLuminanceSource(grayBitmap)
    val binaryBitmap = BinaryBitmap(HybridBinarizer(source))
    return try {
        MultiFormatReader().decode(binaryBitmap).text
    } catch (e: Exception) {
        null
    }
}

内容的提问来源于stack exchange,提问作者Jose Ricardo Bustos M.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 13:36:37