Julian Steenbakker

feat: add new resolution selector with parameter for android

package dev.steenbakker.mobile_scanner
import android.app.Activity
import android.content.Context
import android.graphics.Bitmap
import android.graphics.Matrix
import android.graphics.Rect
import android.hardware.display.DisplayManager
import android.net.Uri
import android.os.Build
import android.os.Handler
import android.os.Looper
import android.util.Size
import android.view.Surface
import androidx.camera.core.*
import android.view.WindowManager
import androidx.camera.core.Camera
import androidx.camera.core.CameraSelector
import androidx.camera.core.ExperimentalGetImage
import androidx.camera.core.ImageAnalysis
import androidx.camera.core.ImageProxy
import androidx.camera.core.Preview
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
... ... @@ -22,11 +35,7 @@ import dev.steenbakker.mobile_scanner.utils.YuvToRgbConverter
import io.flutter.view.TextureRegistry
import java.io.ByteArrayOutputStream
import kotlin.math.roundToInt
import android.util.Size
import android.hardware.display.DisplayManager
import android.view.WindowManager
import android.content.Context
import android.os.Build
class MobileScanner(
private val activity: Activity,
... ... @@ -216,7 +225,8 @@ class MobileScanner(
mobileScannerStartedCallback: MobileScannerStartedCallback,
mobileScannerErrorCallback: (exception: Exception) -> Unit,
detectionTimeout: Long,
cameraResolution: Size?
cameraResolution: Size?,
newCameraResolutionSelector: Boolean
) {
this.detectionSpeed = detectionSpeed
this.detectionTimeout = detectionTimeout
... ... @@ -277,9 +287,19 @@ class MobileScanner(
val displayManager = activity.applicationContext.getSystemService(Context.DISPLAY_SERVICE) as DisplayManager
if (cameraResolution != null) {
// TODO: migrate to ResolutionSelector with ResolutionStrategy when upgrading to camera 1.3.0
// Override initial resolution
if (newCameraResolutionSelector) {
val selectorBuilder = ResolutionSelector.Builder()
selectorBuilder.setResolutionStrategy(
ResolutionStrategy(
cameraResolution,
ResolutionStrategy.FALLBACK_RULE_CLOSEST_HIGHER_THEN_LOWER
)
)
analysisBuilder.setResolutionSelector(selectorBuilder.build()).build()
} else {
@Suppress("DEPRECATION")
analysisBuilder.setTargetResolution(getResolution(cameraResolution))
}
if (displayListener == null) {
displayListener = object : DisplayManager.DisplayListener {
... ... @@ -288,9 +308,21 @@ class MobileScanner(
override fun onDisplayRemoved(displayId: Int) {}
override fun onDisplayChanged(displayId: Int) {
if (newCameraResolutionSelector) {
val selectorBuilder = ResolutionSelector.Builder()
selectorBuilder.setResolutionStrategy(
ResolutionStrategy(
cameraResolution,
ResolutionStrategy.FALLBACK_RULE_CLOSEST_HIGHER_THEN_LOWER
)
)
analysisBuilder.setResolutionSelector(selectorBuilder.build()).build()
} else {
@Suppress("DEPRECATION")
analysisBuilder.setTargetResolution(getResolution(cameraResolution))
}
}
}
displayManager.registerDisplayListener(
displayListener, null,
... ...
... ... @@ -137,6 +137,7 @@ class MobileScannerHandler(
val speed: Int = call.argument<Int>("speed") ?: 1
val timeout: Int = call.argument<Int>("timeout") ?: 250
val cameraResolutionValues: List<Int>? = call.argument<List<Int>>("cameraResolution")
val useNewCameraSelector: Boolean = call.argument<Boolean>("useNewCameraSelector") ?: false
val cameraResolution: Size? = if (cameraResolutionValues != null) {
Size(cameraResolutionValues[0], cameraResolutionValues[1])
} else {
... ... @@ -219,6 +220,7 @@ class MobileScannerHandler(
},
timeout.toLong(),
cameraResolution,
useNewCameraSelector
)
}
... ...
... ... @@ -17,7 +17,7 @@ class _BarcodeScannerWithControllerState
BarcodeCapture? barcode;
final MobileScannerController controller = MobileScannerController(
torchEnabled: true,
torchEnabled: true, useNewCameraSelector: true,
// formats: [BarcodeFormat.qrCode]
// facing: CameraFacing.front,
// detectionSpeed: DetectionSpeed.normal
... ...
... ... @@ -16,7 +16,7 @@ class _BarcodeScannerReturningImageState
extends State<BarcodeScannerReturningImage>
with SingleTickerProviderStateMixin {
BarcodeCapture? barcode;
MobileScannerArguments? arguments;
// MobileScannerArguments? arguments;
final MobileScannerController controller = MobileScannerController(
torchEnabled: true,
... ...
... ... @@ -225,12 +225,22 @@ class _MobileScannerState extends State<MobileScanner>
return Stack(
alignment: Alignment.center,
children: [
_scanner(value.size, value.webId, value.textureId, value.nrOfCameras),
_scanner(
value.size,
value.webId,
value.textureId,
value.nrOfCameras,
),
widget.overlay!,
],
);
} else {
return _scanner(value.size, value.webId, value.textureId, value.nrOfCameras);
return _scanner(
value.size,
value.webId,
value.textureId,
value.nrOfCameras,
);
}
},
);
... ...
... ... @@ -23,6 +23,7 @@ class MobileScannerController {
this.onPermissionSet,
this.autoStart = true,
this.cameraResolution,
this.useNewCameraSelector = false,
});
/// Select which camera should be used.
... ... @@ -74,6 +75,12 @@ class MobileScannerController {
/// Currently only supported on Android.
final Size? cameraResolution;
/// Use the new resolution selector. Warning: not fully tested, may produce
/// unwanted/zoomed images.
///
/// Only supported on Android
final bool useNewCameraSelector;
/// Sets the barcode stream
final StreamController<BarcodeCapture> _barcodesController =
StreamController.broadcast();
... ... @@ -136,6 +143,7 @@ class MobileScannerController {
arguments['speed'] = detectionSpeed.rawValue;
arguments['timeout'] = detectionTimeoutMs;
arguments['returnImage'] = returnImage;
arguments['useNewCameraSelector'] = useNewCameraSelector;
/* if (scanWindow != null) {
arguments['scanWindow'] = [
... ...
... ... @@ -24,6 +24,6 @@ class MobileScannerArguments {
required this.hasTorch,
this.textureId,
this.webId,
this.nrOfCameras
this.nrOfCameras,
});
}
... ...