Reputation: 117
I am working on a specialized industrial device running Andoid 7.1 I want to make screenshots of the camera preview (to jpg) into the cache storage, when an event happens on the device (that event it is triggering a LaunchedEffect block).
My current code looks like this:
@Composable
fun CameraScreen() {
val coroutineScope = rememberCoroutineScope()
val lifecycle = LocalLifecycleOwner.current
val ctx = LocalContext.current
val vm = viewModel<MyViewModel>()
var cameraProvider: ProcessCameraProvider
var cameraPreviewView = PreviewView(ctx).apply {
this.scaleType = scaleType
layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
)
implementationMode = PreviewView.ImplementationMode.COMPATIBLE
}
val imageCapture by remember {
mutableStateOf(
ImageCapture.Builder()
.setJpegQuality(80)
.setResolutionSelector(
ResolutionSelector.Builder()
.setResolutionStrategy(
ResolutionStrategy(
Size(640, 480),
ResolutionStrategy.FALLBACK_RULE_CLOSEST_HIGHER_THEN_LOWER
)
)
.setAspectRatioStrategy(AspectRatioStrategy.RATIO_4_3_FALLBACK_AUTO_STRATEGY)
.build()
)
.setCaptureMode(CAPTURE_MODE_MINIMIZE_LATENCY)
.build()
)
}
LaunchedEffect(vm.eventHappened) {
if (vm.eventHappened) {
val bitmap = cameraPreviewView.bitmap // !!! HERE BITMAP IS ALWAYS NULL
if (bitmap != null) {
saveBitmapImageToFile(vm.photoFile, bitmap)
}
}
}
Box(
modifier = Modifier.fillMaxSize()
) {
AndroidView(
modifier = Modifier.width(pixelToDp(640)).height(pixelToDp(480)),
factory = { context ->
val previewUseCase = Preview.Builder()
.build()
.also {
it.surfaceProvider = cameraPreviewView.surfaceProvider
}
coroutineScope.launch {
val cameraProviderFuture = ProcessCameraProvider.getInstance(ctx)
cameraProviderFuture.addListener({
cameraProvider = cameraProviderFuture.get()
val cameraSelector = CameraSelector.Builder()
.apply {
requireLensFacing(CameraSelector.LENS_FACING_BACK)
}.build()
cameraProvider.unbindAll()
cameraProvider.bindToLifecycle(lifecycle, cameraSelector, previewUseCase, imageCapture)
}, ContextCompat.getMainExecutor(ctx))
}
cameraPreviewView
}
)
}
}
The camera preview works with no problems, but when the vm.eventHappened
is triggered, the bitmap returned from the cameraPreviewView is null.
I have also tried calling cameraPreviewView.drawToBitmap()
but that crashes with exception saying View needs to be laid out before calling drawToBitmap()
Thanks for all the help.
Upvotes: 0
Views: 42
Reputation: 117
The only working solution was to use ImageAnalysis
instead of ImageCapture
val imageAnalysis = ImageAnalysis.Builder()
.setTargetResolution(Size(640, 480))
.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
.build()
imageAnalysis.setAnalyzer(cameraExecutor, ImageAnalysis.Analyzer { imageProxy ->
if (vm.takePhoto) {
vm.lastPhoto = imageProxy.toBitmap()
vm.takePhoto = false
}
imageProxy.close()
})
cameraProvider.bindToLifecycle(lifecycle, cameraSelector, previewUseCase, imageAnalysis)
Upvotes: 0
Reputation: 1
You need to wrap the cameraProviderView in a remember function like this:
val cameraPreviewView by remember {
mutableStateOf(
PreviewView(ctx).apply {
this.scaleType = scaleType
layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
)
implementationMode = PreviewView.ImplementationMode.COMPATIBLE
}
)
}
Upvotes: 0