Search code examples
androidkotlinandroid-jetpack-composeqr-codezxing

How to read QR codes with colors using zxing in kotlin and Jetpack Compose


I'm using zxing in kotlin to read QR codes, and it works great, however I want to read QR codes with colors and it doesn't work, only black and white, how to do this?

this one reads it well,

black and white QR code

this cannot be read,

color QR code

CaptureActivityPortrait.kt

class CaptureActivityPortrait: CaptureActivity() {
}

build.graddle

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)

Solution

  • This seems to be by design in zxing, which is the de-facto standard.

    You could however create some pre-processing of the image. The more colors you support the more error-prone the solution will be. (ie. if there are more than two colors, the likelyhood of getting it wrong increases).

    You could use the ColorMatrixColorFilter in Kotlin and apply a ColorMatrix to turn the bitmap into grayscale, and try reading it again.

    See example here: Manipulate Visual Effects With the ColorMatrixFilter and ConvolutionFilter

    If grayscale doesn't cut it, you will have to decide an arbitrary shade of grey – the threshold – that you will want to convert to white, and above it to black - to end up with the desired two colors only.

    You could use ImageMagick via. kmagick that has a oneliner for exactly this purpose:

    convert <input> -threshold xx% <output>
    

    See other answers for tweaking: