New debug mode for extended live analysis overlay
This commit is contained in:
@@ -46,6 +46,7 @@ import androidx.compose.ui.graphics.BlendMode
|
|||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.ColorFilter
|
import androidx.compose.ui.graphics.ColorFilter
|
||||||
import androidx.compose.ui.graphics.asImageBitmap
|
import androidx.compose.ui.graphics.asImageBitmap
|
||||||
|
import androidx.compose.ui.graphics.drawscope.DrawScope
|
||||||
import androidx.compose.ui.graphics.toArgb
|
import androidx.compose.ui.graphics.toArgb
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.viewinterop.AndroidView
|
import androidx.compose.ui.viewinterop.AndroidView
|
||||||
@@ -149,17 +150,15 @@ fun bindCameraUseCases(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun AnalysisOverlay(liveAnalysisState: LiveAnalysisState) {
|
fun AnalysisOverlay(liveAnalysisState: LiveAnalysisState, debugMode: Boolean) {
|
||||||
val binaryMask = liveAnalysisState.binaryMask
|
val binaryMask = liveAnalysisState.binaryMask
|
||||||
if (binaryMask == null) {
|
if (binaryMask == null) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val maskOverlay = replaceColor(binaryMask, Color.Black, Color.Transparent)
|
|
||||||
Canvas(modifier = Modifier.fillMaxSize()) {
|
Canvas(modifier = Modifier.fillMaxSize()) {
|
||||||
drawImage(
|
if (debugMode) {
|
||||||
maskOverlay.scale(size.width.toInt(), size.height.toInt()).asImageBitmap(),
|
drawMask(this, binaryMask)
|
||||||
colorFilter = ColorFilter.tint(Color(0x8000FF00), BlendMode.SrcIn)
|
}
|
||||||
)
|
|
||||||
if (liveAnalysisState.documentQuad != null) {
|
if (liveAnalysisState.documentQuad != null) {
|
||||||
val scaledQuad = liveAnalysisState.documentQuad.scaledTo(
|
val scaledQuad = liveAnalysisState.documentQuad.scaledTo(
|
||||||
fromWidth = binaryMask.width,
|
fromWidth = binaryMask.width,
|
||||||
@@ -174,6 +173,15 @@ fun AnalysisOverlay(liveAnalysisState: LiveAnalysisState) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun drawMask(drawScope: DrawScope, binaryMask: Bitmap) {
|
||||||
|
val maskOverlay = replaceColor(binaryMask, Color.Black, Color.Transparent)
|
||||||
|
val size = drawScope.size
|
||||||
|
drawScope.drawImage(
|
||||||
|
maskOverlay.scale(size.width.toInt(), size.height.toInt()).asImageBitmap(),
|
||||||
|
colorFilter = ColorFilter.tint(Color(0x8000FF00), BlendMode.SrcIn)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fun replaceColor(bitmap: Bitmap, toReplace: Color, replacement: Color): Bitmap {
|
fun replaceColor(bitmap: Bitmap, toReplace: Color, replacement: Color): Bitmap {
|
||||||
val width = bitmap.width
|
val width = bitmap.width
|
||||||
val height = bitmap.height
|
val height = bitmap.height
|
||||||
|
|||||||
@@ -86,6 +86,7 @@ data class CameraUiState(
|
|||||||
val liveAnalysisState: LiveAnalysisState,
|
val liveAnalysisState: LiveAnalysisState,
|
||||||
val captureState: CaptureState,
|
val captureState: CaptureState,
|
||||||
val showDetectionError: Boolean,
|
val showDetectionError: Boolean,
|
||||||
|
val isDebugMode: Boolean
|
||||||
)
|
)
|
||||||
|
|
||||||
const val CAPTURED_IMAGE_DISPLAY_DURATION = 1500L
|
const val CAPTURED_IMAGE_DISPLAY_DURATION = 1500L
|
||||||
@@ -101,6 +102,7 @@ fun CameraScreen(
|
|||||||
var previewView by remember { mutableStateOf<PreviewView?>(null) }
|
var previewView by remember { mutableStateOf<PreviewView?>(null) }
|
||||||
val pageIds by viewModel.pageIds.collectAsStateWithLifecycle()
|
val pageIds by viewModel.pageIds.collectAsStateWithLifecycle()
|
||||||
val thumbnailCoords = remember { mutableStateOf(Offset.Zero) }
|
val thumbnailCoords = remember { mutableStateOf(Offset.Zero) }
|
||||||
|
var isDebugMode by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
val captureController = remember { CameraCaptureController() }
|
val captureController = remember { CameraCaptureController() }
|
||||||
DisposableEffect(Unit) {
|
DisposableEffect(Unit) {
|
||||||
@@ -149,7 +151,12 @@ fun CameraScreen(
|
|||||||
{ offset -> thumbnailCoords.value = offset }
|
{ offset -> thumbnailCoords.value = offset }
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
cameraUiState = CameraUiState(pageIds.size, liveAnalysisState, captureState, showDetectionError),
|
cameraUiState = CameraUiState(
|
||||||
|
pageIds.size,
|
||||||
|
liveAnalysisState,
|
||||||
|
captureState,
|
||||||
|
showDetectionError,
|
||||||
|
isDebugMode),
|
||||||
onCapture = {
|
onCapture = {
|
||||||
previewView?.bitmap?.let {
|
previewView?.bitmap?.let {
|
||||||
Log.i("MyScan", "Pressed <Capture>")
|
Log.i("MyScan", "Pressed <Capture>")
|
||||||
@@ -160,6 +167,7 @@ fun CameraScreen(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
onFinalizePressed = onFinalizePressed,
|
onFinalizePressed = onFinalizePressed,
|
||||||
|
onDebugModeSwitched = { isDebugMode = !isDebugMode },
|
||||||
thumbnailCoords = thumbnailCoords,
|
thumbnailCoords = thumbnailCoords,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -171,6 +179,7 @@ private fun CameraScreenScaffold(
|
|||||||
cameraUiState: CameraUiState,
|
cameraUiState: CameraUiState,
|
||||||
onCapture: () -> Unit,
|
onCapture: () -> Unit,
|
||||||
onFinalizePressed: () -> Unit,
|
onFinalizePressed: () -> Unit,
|
||||||
|
onDebugModeSwitched: () -> Unit,
|
||||||
thumbnailCoords: MutableState<Offset>,
|
thumbnailCoords: MutableState<Offset>,
|
||||||
) {
|
) {
|
||||||
Box {
|
Box {
|
||||||
@@ -180,6 +189,7 @@ private fun CameraScreenScaffold(
|
|||||||
pageList = pageList,
|
pageList = pageList,
|
||||||
pageCount = cameraUiState.pageCount,
|
pageCount = cameraUiState.pageCount,
|
||||||
onFinalizePressed = onFinalizePressed,
|
onFinalizePressed = onFinalizePressed,
|
||||||
|
onDebugModeSwitched = onDebugModeSwitched,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
) { innerPadding ->
|
) { innerPadding ->
|
||||||
@@ -189,7 +199,9 @@ private fun CameraScreenScaffold(
|
|||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
) {
|
) {
|
||||||
CameraPreviewWithOverlay(cameraPreview, cameraUiState)
|
CameraPreviewWithOverlay(cameraPreview, cameraUiState)
|
||||||
MessageBox(cameraUiState.liveAnalysisState.inferenceTime)
|
if (cameraUiState.isDebugMode) {
|
||||||
|
MessageBox(cameraUiState.liveAnalysisState.inferenceTime)
|
||||||
|
}
|
||||||
CaptureButton(
|
CaptureButton(
|
||||||
onClick = onCapture,
|
onClick = onCapture,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@@ -228,16 +240,16 @@ private fun CapturedImage(image: ImageBitmap, thumbnailCoords: MutableState<Offs
|
|||||||
val density = LocalDensity.current
|
val density = LocalDensity.current
|
||||||
Box (contentAlignment = Alignment.BottomStart,
|
Box (contentAlignment = Alignment.BottomStart,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxHeight(0.8f)
|
.fillMaxHeight(0.8f)
|
||||||
.onGloballyPositioned { coordinates ->
|
.onGloballyPositioned { coordinates ->
|
||||||
val bounds = coordinates.boundsInWindow()
|
val bounds = coordinates.boundsInWindow()
|
||||||
val centerX = bounds.left + bounds.width / 2
|
val centerX = bounds.left + bounds.width / 2
|
||||||
val centerY = bounds.top + bounds.height / 2
|
val centerY = bounds.top + bounds.height / 2
|
||||||
with(density) {
|
with(density) {
|
||||||
targetOffsetX = thumbnailCoords.value.x - centerX
|
targetOffsetX = thumbnailCoords.value.x - centerX
|
||||||
targetOffsetY = thumbnailCoords.value.y - centerY
|
targetOffsetY = thumbnailCoords.value.y - centerY
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
) {
|
) {
|
||||||
Image(
|
Image(
|
||||||
bitmap = image,
|
bitmap = image,
|
||||||
@@ -309,7 +321,7 @@ private fun CameraPreviewWithOverlay(
|
|||||||
.height(height.dp)
|
.height(height.dp)
|
||||||
) {
|
) {
|
||||||
cameraPreview()
|
cameraPreview()
|
||||||
AnalysisOverlay(cameraUiState.liveAnalysisState)
|
AnalysisOverlay(cameraUiState.liveAnalysisState, cameraUiState.isDebugMode)
|
||||||
captureState.frozenImage?.let {
|
captureState.frozenImage?.let {
|
||||||
Image(
|
Image(
|
||||||
bitmap = it.asImageBitmap(),
|
bitmap = it.asImageBitmap(),
|
||||||
@@ -358,7 +370,25 @@ fun CameraScreenFooter(
|
|||||||
pageList: @Composable () -> Unit,
|
pageList: @Composable () -> Unit,
|
||||||
pageCount: Int,
|
pageCount: Int,
|
||||||
onFinalizePressed: () -> Unit,
|
onFinalizePressed: () -> Unit,
|
||||||
|
onDebugModeSwitched: () -> Unit,
|
||||||
) {
|
) {
|
||||||
|
var tapCount by remember { mutableStateOf(0) }
|
||||||
|
var lastTapTime by remember { mutableStateOf(0L) }
|
||||||
|
val tapThreshold = 500L
|
||||||
|
val onPageCountClick = {
|
||||||
|
val currentTime = System.currentTimeMillis()
|
||||||
|
if (currentTime - lastTapTime < tapThreshold) {
|
||||||
|
tapCount++
|
||||||
|
if (tapCount >= 3) {
|
||||||
|
onDebugModeSwitched()
|
||||||
|
tapCount = 0
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tapCount = 1
|
||||||
|
}
|
||||||
|
lastTapTime = currentTime
|
||||||
|
}
|
||||||
|
|
||||||
Column (modifier = Modifier.background(MaterialTheme.colorScheme.primaryContainer)) {
|
Column (modifier = Modifier.background(MaterialTheme.colorScheme.primaryContainer)) {
|
||||||
pageList()
|
pageList()
|
||||||
BottomAppBar(
|
BottomAppBar(
|
||||||
@@ -373,7 +403,8 @@ fun CameraScreenFooter(
|
|||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = "$pageCount pages",
|
text = "$pageCount pages",
|
||||||
style = MaterialTheme.typography.bodyMedium
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
|
modifier = Modifier.clickable(onClick = onPageCountClick)
|
||||||
)
|
)
|
||||||
|
|
||||||
Button (
|
Button (
|
||||||
@@ -432,9 +463,10 @@ private fun ScreenPreview(captureState: CaptureState) {
|
|||||||
listState = LazyListState(),
|
listState = LazyListState(),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
cameraUiState = CameraUiState(pageCount = 4, LiveAnalysisState(), captureState, false),
|
cameraUiState = CameraUiState(pageCount = 4, LiveAnalysisState(), captureState, false, false),
|
||||||
onCapture = {},
|
onCapture = {},
|
||||||
onFinalizePressed = {},
|
onFinalizePressed = {},
|
||||||
|
onDebugModeSwitched = {},
|
||||||
thumbnailCoords = thumbnailCoords,
|
thumbnailCoords = thumbnailCoords,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user