Navaron Bracke

make scanner nullable to prevent leak; use early returns in process image callback; format

... ... @@ -20,12 +20,12 @@ import androidx.camera.core.ImageAnalysis
import androidx.camera.core.ImageProxy
import androidx.camera.core.Preview
import androidx.camera.core.TorchState
import androidx.camera.core.resolutionselector.AspectRatioStrategy
import androidx.camera.core.resolutionselector.ResolutionSelector
import androidx.camera.core.resolutionselector.ResolutionStrategy
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.core.content.ContextCompat
import androidx.lifecycle.LifecycleOwner
import com.google.mlkit.vision.barcode.BarcodeScanner
import com.google.mlkit.vision.barcode.BarcodeScannerOptions
import com.google.mlkit.vision.barcode.BarcodeScanning
import com.google.mlkit.vision.barcode.common.Barcode
... ... @@ -37,7 +37,6 @@ import io.flutter.view.TextureRegistry
import java.io.ByteArrayOutputStream
import kotlin.math.roundToInt
class MobileScanner(
private val activity: Activity,
private val textureRegistry: TextureRegistry,
... ... @@ -50,7 +49,7 @@ class MobileScanner(
private var camera: Camera? = null
private var preview: Preview? = null
private var textureEntry: TextureRegistry.SurfaceTextureEntry? = null
private var scanner = BarcodeScanning.getClient()
private var scanner: BarcodeScanner? = null
private var lastScanned: List<String?>? = null
private var scannerTimeout = false
private var displayListener: DisplayManager.DisplayListener? = null
... ... @@ -76,76 +75,75 @@ class MobileScanner(
scannerTimeout = true
}
scanner.process(inputImage)
.addOnSuccessListener { barcodes ->
scanner?.let {
it.process(inputImage).addOnSuccessListener { barcodes ->
if (detectionSpeed == DetectionSpeed.NO_DUPLICATES) {
val newScannedBarcodes = barcodes.mapNotNull { barcode -> barcode.rawValue }.sorted()
val newScannedBarcodes = barcodes.mapNotNull {
barcode -> barcode.rawValue
}.sorted()
if (newScannedBarcodes == lastScanned) {
// New scanned is duplicate, returning
return@addOnSuccessListener
}
if (newScannedBarcodes.isNotEmpty()) lastScanned = newScannedBarcodes
if (newScannedBarcodes.isNotEmpty()) {
lastScanned = newScannedBarcodes
}
}
val barcodeMap: MutableList<Map<String, Any?>> = mutableListOf()
for (barcode in barcodes) {
if (scanWindow != null) {
val match = isBarcodeInScanWindow(scanWindow!!, barcode, imageProxy)
if (!match) {
continue
} else {
barcodeMap.add(barcode.data)
}
} else {
if (scanWindow == null) {
barcodeMap.add(barcode.data)
continue
}
}
if (isBarcodeInScanWindow(scanWindow!!, barcode, imageProxy)) {
barcodeMap.add(barcode.data)
}
}
if (barcodeMap.isNotEmpty()) {
if (returnImage) {
val bitmap = Bitmap.createBitmap(mediaImage.width, mediaImage.height, Bitmap.Config.ARGB_8888)
val imageFormat = YuvToRgbConverter(activity.applicationContext)
imageFormat.yuvToRgb(mediaImage, bitmap)
if (barcodeMap.isEmpty()) {
return@addOnSuccessListener
}
val bmResult = rotateBitmap(bitmap, camera?.cameraInfo?.sensorRotationDegrees?.toFloat() ?: 90f)
if (!returnImage) {
mobileScannerCallback(
barcodeMap,
null,
null,
null
)
return@addOnSuccessListener
}
val stream = ByteArrayOutputStream()
bmResult.compress(Bitmap.CompressFormat.PNG, 100, stream)
val byteArray = stream.toByteArray()
val bmWidth = bmResult.width
val bmHeight = bmResult.height
bmResult.recycle()
val bitmap = Bitmap.createBitmap(mediaImage.width, mediaImage.height, Bitmap.Config.ARGB_8888)
val imageFormat = YuvToRgbConverter(activity.applicationContext)
imageFormat.yuvToRgb(mediaImage, bitmap)
mobileScannerCallback(
barcodeMap,
byteArray,
bmWidth,
bmHeight
)
val bmResult = rotateBitmap(bitmap, camera?.cameraInfo?.sensorRotationDegrees?.toFloat() ?: 90f)
} else {
val stream = ByteArrayOutputStream()
bmResult.compress(Bitmap.CompressFormat.PNG, 100, stream)
val byteArray = stream.toByteArray()
val bmWidth = bmResult.width
val bmHeight = bmResult.height
bmResult.recycle()
mobileScannerCallback(
barcodeMap,
null,
null,
null
)
}
}
}
.addOnFailureListener { e ->
mobileScannerCallback(
barcodeMap,
byteArray,
bmWidth,
bmHeight
)
}.addOnFailureListener { e ->
mobileScannerErrorCallback(
e.localizedMessage ?: e.toString()
)
}
.addOnCompleteListener { imageProxy.close() }
}.addOnCompleteListener { imageProxy.close() }
}
if (detectionSpeed == DetectionSpeed.NORMAL) {
// Set timer and continue
... ...