How to draw cutout in PreviewView Android Compose?

543 views Asked by At

I'm creating a QR Scanner where the preview view is blur except the centre square part, I was able to blur PreviewView but not able to think of a way to unblur the centre cutout part.

  AndroidView(
            modifier = Modifier.fillMaxSize(),
            factory = { context ->

                val previewView = PreviewView(context).apply {
                    setRenderEffect( RenderEffect.createBlurEffect(
                        26f, 26f,Shader.TileMode.CLAMP))
                    implementationMode = PreviewView.ImplementationMode.COMPATIBLE

                }

                val preview = Preview.Builder().build()

                val selector = CameraSelector.Builder().requireLensFacing(CameraSelector.LENS_FACING_BACK).build()

                preview.setSurfaceProvider(previewView.surfaceProvider)


                val imageAnalysis = ImageAnalysis.Builder().setTargetResolution(
                    Size(
                        previewView.width, previewView.height
                    )
                ).setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST).build()

                imageAnalysis.setAnalyzer(
                    ContextCompat.getMainExecutor(context),
                    QrCodeAnalyzer { result ->
                        onScan(result)
                    })
                try {
                    camera = cameraProviderFuture.get().bindToLifecycle(
                        lifecycleOwner, selector, preview, imageAnalysis, imageCapture
                    )
                } catch (e: Exception) {
                    e.printStackTrace()
                }

                previewView
            },
        )
        if (overlay != null) {
            overlay()
        }

Current Result

1

There are 1 answers

0
Volodymyr Zakharov On

Parent component:

          Box(contentAlignment = Alignment.Center) {
                CameraView()
                ScannerArea(modifier = Modifier.fillMaxSize())
                //some buttons (flash, take photo)
                    ....
            }

ScannerArea:

@Composable
fun ScannerArea(
    modifier: Modifier,
    horizontalPadding: Dp = 36.dp,
    scannerHeight: Dp = 280.dp,
    scannerCornerRadius: Dp = 8.dp,
    scannerStrokeWidth: Dp = 2.dp,
    scannerColor: Color = Color(0xFFFFFFFFF),
    darkTint: Color = Color(0x40000000)
) {
    Canvas(modifier = modifier) {
        val horizontalPaddingPx = horizontalPadding.toPx()
        val scannerHeightPx = scannerHeight.toPx()
        val scannerCornerRadiusPx = scannerCornerRadius.toPx()
        val scannerStrokeWidthPx = scannerStrokeWidth.toPx()
        val scannerPath = getScannerPath(
            size = size,
            scannerHeight = scannerHeightPx,
            horizontalPadding = horizontalPaddingPx,
            scannerCornerRadius = scannerCornerRadiusPx
        )
        clipPath(path = scannerPath, clipOp = ClipOp.Difference) {
            drawRect(color = darkTint, size = size)
        }
        drawPath(
            path = scannerPath,
            color = scannerColor,
            style = Stroke(width = scannerStrokeWidthPx)
        )
    }
}

private fun getScannerPath(
    size: Size,
    scannerHeight: Float,
    horizontalPadding: Float,
    scannerCornerRadius: Float
) = Path().apply {
    moveTo(
        x = horizontalPadding + scannerCornerRadius,
        y = size.center.y - scannerHeight / 2f
    )
    lineTo(
        x = size.width - horizontalPadding - scannerCornerRadius,
        y = size.center.y - scannerHeight / 2f
    )
    quadraticBezierTo(
        x1 = size.width - horizontalPadding,
        y1 = size.center.y - scannerHeight / 2f,
        x2 = size.width - horizontalPadding,
        y2 = size.center.y - scannerHeight / 2f + scannerCornerRadius
    )
    lineTo(
        x = size.width - horizontalPadding,
        y = size.center.y + scannerHeight / 2f - scannerCornerRadius
    )
    quadraticBezierTo(
        x1 = size.width - horizontalPadding,
        y1 = size.center.y + scannerHeight / 2f,
        x2 = size.width - scannerCornerRadius - horizontalPadding,
        y2 = size.center.y + scannerHeight / 2f
    )
    lineTo(
        x = horizontalPadding + scannerCornerRadius,
        y = size.center.y + scannerHeight / 2f
    )
    quadraticBezierTo(
        x1 = horizontalPadding,
        y1 = size.center.y + scannerHeight / 2f,
        x2 = horizontalPadding,
        y2 = size.center.y + scannerHeight / 2f - scannerCornerRadius
    )
    lineTo(
        x = horizontalPadding,
        y = size.center.y - scannerHeight / 2f + scannerCornerRadius
    )
    quadraticBezierTo(
        x1 = horizontalPadding,
        y1 = size.center.y - scannerHeight / 2f,
        x2 = horizontalPadding + scannerCornerRadius,
        y2 = size.center.y - scannerHeight / 2f
    )
}