This commit is contained in:
Adam Velebil 2022-11-03 16:29:40 +01:00
commit 10c207c337
No known key found for this signature in database
GPG Key ID: AC6D6B9D715FC084
6 changed files with 117 additions and 19 deletions

View File

@ -2,7 +2,7 @@ group 'com.yubico.authenticator.flutter_plugins.qrscanner_zxing'
version '1.0'
buildscript {
ext.kotlin_version = '1.7.10'
ext.kotlin_version = '1.7.20'
repositories {
google()
mavenCentral()

View File

@ -149,7 +149,7 @@ internal class QRScannerView(
imageAnalysis = null
cameraExecutor.shutdown()
methodChannel.setMethodCallHandler(null)
Log.d(TAG, "View disposed")
Log.v(TAG, "dispose()")
}
private val methodChannel: MethodChannel = MethodChannel(binaryMessenger, CHANNEL_NAME)
@ -166,12 +166,16 @@ internal class QRScannerView(
}
}
Log.v(TAG, "marginPct: $marginPct")
if (context is Activity) {
permissionsGranted = allPermissionsGranted(context)
if (!permissionsGranted) {
Log.v(TAG, "permissionsGranted = false -> requesting permission")
requestPermissionsFromUser(context)
} else {
Log.v(TAG, "permissionsGranted = true -> binding use cases")
bindUseCases(context)
}
@ -293,10 +297,15 @@ internal class QRScannerView(
it.setHints(mapOf(DecodeHintType.POSSIBLE_FORMATS to listOf(BarcodeFormat.QR_CODE)))
}
private fun ByteBuffer.toByteArray(): ByteArray {
var analyzedImagesCount = 0
private fun ByteBuffer.toByteArray(lastRowPadding: Int): ByteArray {
rewind()
val data = ByteArray(remaining())
get(data)
val size = remaining()
val paddedSize = size + lastRowPadding
val data = ByteArray(paddedSize)
get(data, 0, size)
data.fill(0, size, paddedSize)
return data
}
@ -307,13 +316,58 @@ internal class QRScannerView(
return
}
val buffer = imageProxy.planes[0].buffer
val intArray = buffer.toByteArray().map { it.toInt() }.toIntArray()
val plane0 = imageProxy.planes[0]
val source: LuminanceSource =
RGBLuminanceSource(imageProxy.width, imageProxy.height, intArray)
if (analyzedImagesCount == 0) {
Log.v(TAG, "First image received for analysis:")
Log.v(TAG, " Image format: ${imageProxy.format}")
Log.v(TAG, " WxH: ${imageProxy.width}x${imageProxy.height}")
val fullSize = BinaryBitmap(HybridBinarizer(source))
for (indexedPlane in imageProxy.planes.withIndex()) {
val index = indexedPlane.index
val plane = indexedPlane.value
try {
Log.v(TAG, " plane[$index].rowStride: ${plane.rowStride} ")
} catch (_: UnsupportedOperationException) {
Log.v(TAG, " plane[$index].rowStride: Unsupported Operation")
}
try {
Log.v(TAG, " plane[$index].pixelStride: ${plane.pixelStride}")
} catch (_: UnsupportedOperationException) {
Log.v(TAG, " plane[$index].pixelStride: Unsupported Operation")
}
Log.v(TAG, " plane[$index].buffer.size: ${plane.buffer.toByteArray(0).size}")
}
}
val buffer = plane0.buffer
val rowStride = plane0.rowStride
// the new array has to pad extra size for situation when rowStride > image width
val intArray =
buffer.toByteArray(rowStride - imageProxy.width).map { it.toInt() }.toIntArray()
val planeLuminanceSource =
RGBLuminanceSource(rowStride, imageProxy.height, intArray)
val luminanceSource =
if (rowStride > imageProxy.width && planeLuminanceSource.isCropSupported) {
if (analyzedImagesCount == 0) {
Log.v(
TAG, " row stride greater than image -> "+
"cropping luminance source of size " +
"${plane0.rowStride}x${imageProxy.height} to " +
"${imageProxy.width}x${imageProxy.height}"
)
}
planeLuminanceSource.crop(0, 0, imageProxy.width, imageProxy.height)
} else {
planeLuminanceSource
}
val fullSize = BinaryBitmap(HybridBinarizer(luminanceSource))
val bitmapToProcess = if (marginPct != null) {
val shorterDim = min(imageProxy.width, imageProxy.height)
@ -321,6 +375,9 @@ internal class QRScannerView(
val cropWH = shorterDim - 2.0 * cropMargin
val cropT = (imageProxy.height - cropWH) / 2.0
val cropL = (imageProxy.width - cropWH) / 2.0
if(analyzedImagesCount == 0) {
Log.v(TAG, " bitmap l:t:w:h $cropL:$cropT:$cropWH:$cropWH")
}
fullSize.crop(
cropL.toInt(),
cropT.toInt(),
@ -328,18 +385,31 @@ internal class QRScannerView(
cropWH.toInt()
)
} else {
if(analyzedImagesCount == 0) {
Log.v(
TAG,
" bitmap l:t:w:h 0:0:${imageProxy.width}:${imageProxy.height} (full size)"
)
}
fullSize
}
val result: com.google.zxing.Result = multiFormatReader.decode(bitmapToProcess)
analysisPaused = true // pause
Log.d(TAG, "Analysis result: ${result.text}")
Log.v(TAG, "Analysis result: ${result.text}")
listener.invoke(Result.success(result.text))
} catch (_: NotFoundException) {
// ignored: no code was found
if (analyzedImagesCount == 0) {
Log.v(TAG, " No QR code found (NotFoundException)")
}
} finally {
// important call
imageProxy.close()
analyzedImagesCount++
if (analyzedImagesCount % 50 == 0) {
Log.v(TAG, "Count of analyzed images so far: $analyzedImagesCount")
}
}
}
}
@ -348,14 +418,14 @@ internal class QRScannerView(
private var cameraOpened: Boolean = false
override fun onChanged(t: CameraState) {
Log.d(TAG, "Camera state changed to ${t.type}")
Log.v(TAG, "Camera state changed to ${t.type}")
if (t.type == CameraState.Type.OPEN) {
cameraOpened = true
}
if (cameraOpened && t.type == CameraState.Type.CLOSED) {
Log.d(TAG, "Camera closed")
Log.v(TAG, "Camera closed")
val stateChangedIntent =
Intent("com.yubico.authenticator.QRScannerView.CameraClosed")
context.sendBroadcast(stateChangedIntent)

View File

@ -26,7 +26,7 @@ apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
android {
compileSdkVersion flutter.compileSdkVersion
compileSdkVersion 33
ndkVersion flutter.ndkVersion
compileOptions {
@ -48,7 +48,7 @@ android {
// You can update the following values to match your application needs.
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration.
minSdkVersion 21
targetSdkVersion flutter.targetSdkVersion
targetSdkVersion 33
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
}

View File

@ -2,7 +2,7 @@
package="com.yubico.authenticator.flutter_plugins.qrscanner_zxing_example">
<application
android:label="qrscanner_zxing_example"
android:name="${applicationName}"
android:name=".App"
android:icon="@mipmap/ic_launcher">
<activity
android:name=".MainActivity"

View File

@ -0,0 +1,28 @@
/*
* Copyright (C) 2022 Yubico.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.yubico.authenticator.flutter_plugins.qrscanner_zxing_example
import android.os.StrictMode
import io.flutter.app.FlutterApplication
class App : FlutterApplication() {
init {
if (BuildConfig.DEBUG) {
StrictMode.enableDefaults()
}
}
}

View File

@ -1,12 +1,12 @@
buildscript {
ext.kotlin_version = '1.6.10'
ext.kotlin_version = '1.7.20'
repositories {
google()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:7.1.2'
classpath 'com.android.tools.build:gradle:7.1.3'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}