You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Jetpack Compose中Bitmap擦除区域显示黑色而非透明的问题解决

问题:Jetpack Compose中Bitmap擦除像素显示黑色而非透明

我在Jetpack Compose中尝试实现将Bitmap像素擦除为透明色,但加载Bitmap到Canvas时,擦除的像素显示为黑色。以下是我的Composable代码:

@RequiresApi(Build.VERSION_CODES.Q)
@Composable
fun EraseByHandCanvasContent(
    modifier: Modifier = Modifier,
    eraseByHandViewModel: EraseByHandViewModel = koinViewModel()
) {

    val drawingByHandState = eraseByHandViewModel.drawingByHandState.collectAsState()
    val bitmap = eraseByHandViewModel.pickedImage.collectAsState()

    val paint = remember {
        derivedStateOf {
            Paint().apply {
                isAntiAlias = true
                color = Color.Transparent.toArgb()
                style = Paint.Style.STROKE
                strokeWidth = drawingByHandState.value.eraseBrushSize
                xfermode = PorterDuffXfermode(PorterDuff.Mode.CLEAR)

            }
        }
    }

    Box(
        modifier = modifier.fillMaxWidth(),
        contentAlignment = Alignment.TopCenter,
    ) {
        Canvas(modifier = Modifier
            .fillMaxSize()
            .onPlaced { layoutCoordinates ->
                eraseByHandViewModel.setCanvasSize(layoutCoordinates.size)
            }
            .pointerInput(Unit) {
                detectDragGestures(
                    onDrag = { change, _ ->
                        eraseByHandViewModel.onDrawingAction(
                            DrawingByHandAction.onDraw(
                                offset = change.position
                            )
                        )
                        change.consume()
                    },
                    onDragStart = { offset ->
                        eraseByHandViewModel.onDrawingAction(
                            DrawingByHandAction.onNewPathDraw(
                                offset = offset
                            )
                        )
                    },
                    onDragEnd = {
                        eraseByHandViewModel.onDrawingAction(
                            DrawingByHandAction.onPathEnd()
                        )
                    }
                )
            }) {

            val currentBitmap =
                drawingByHandState.value.tempBitmap
                    ?: bitmap.value?.copy(Bitmap.Config.ARGB_8888, true)?.apply {
                        isPremultiplied = true
                        setHasAlpha(true)
                    }

            currentBitmap?.let { baseBitmap ->
                val outputBitmap = Bitmap.createScaledBitmap(
                    baseBitmap,
                    size.width.toInt(),
                    size.height.toInt(),
                    false,
                )

                val combinedCanvas = android.graphics.Canvas(outputBitmap)

                combinedCanvas.drawPath(
                    drawingByHandState.value.currentPath.asAndroidPath(),
                    paint.value,
                )

                eraseByHandViewModel.setTempBitmap(outputBitmap)

                drawImage(
                    image = outputBitmap.asImageBitmap(),
                )

            }
        }
    }
}

为了调试,我检查了Bitmap像素,发现countTransparent值始终为0,说明绘制过程存在问题:

private fun countTransparentPixels(bitmap: Bitmap) {
    var countTransparent = 0
    var countNonTransparent = 0

    val copyBitmap = bitmap.copy(Bitmap.Config.ARGB_8888,true).apply {
        setHasAlpha(true)
        isPremultiplied = true
    }

    for (x in 0 until copyBitmap.width) {
        for (y in 0 until copyBitmap.height) {
            val pixel = copyBitmap.getPixel(x, y)
            if (pixel == androidx.compose.ui.graphics.Color.Transparent.toArgb()){   
                countTransparent++
            } else {
                countNonTransparent++
            }
        }
    }

    Log.d("COUNTERS", "$countTransparent---$countNonTransparent")
}

我在应用中使用Coil展示Bitmap图片,将擦除后的Bitmap加载到图库时(擦除像素在图库中显示为白色),SubcomposeAsyncImage同样将擦除像素显示为黑色,和EraseByHandCanvasContent组件表现一致。我尝试了Paint对象和drawImage()方法的多种BlendMode组合,但始终无法得到透明Bitmap:

val copyBitmap = selectedImageState.value?.copy(Bitmap.Config.ARGB_8888,true)
copyBitmap?.apply {
    setHasAlpha(true)    
    isPremultiplied = true
}

SubcomposeAsyncImage(
    modifier = Modifier
        .fillMaxWidth()
        .weight(1f)
        .clickable {
            onPickImage()
        },

    model = copyBitmap,
    contentDescription = "",
    alignment = Alignment.TopCenter,
    contentScale = ContentScale.Crop,
)

解决方案

找到问题了。如果使用图片裁剪库,需要为裁剪选项设置以下参数:

val cropOption = CropImageContractOptions(
    uri = uri, cropImageOptions = CropImageOptions(
        backgroundColor = Color.Transparent.toArgb(),
        outputCompressFormat = Bitmap.CompressFormat.PNG
    )
)

编程愉快。

内容的提问来源于stack exchange,提问作者samedhrmn

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 07:28:15