Получить растровое изображение перед использованием в Composable with Coil

Я пытаюсь получить два изображения с URL-адреса, а затем у меня естьComposableдля рисования на холсте нужны два растровых изображения, я пробовал, но холст не рисуется, я что-то упустил?

      val overlayImage =
            "https://st2.depositphotos.com/1400069/5999/i/600/depositphotos_59995765-stock-photo-abstract-galaxy-background.jpg"
        val baseImage =
            "https://www.vitrinesdocomercio.com/uploads/1/3/9/4/13943900/1278180_orig.jpg"

        val overlayImageLoaded = rememberAsyncImagePainter(
            model = overlayImage,
        )
        val baseImageLoaded = rememberAsyncImagePainter(
            model = baseImage
        )

        var overlayBitmap = remember<Bitmap?> {
            null
        }
        var baseBitmap = remember<Bitmap?> {
            null
        }

        val overlayImageLoadedState = overlayImageLoaded.state
        if (overlayImageLoadedState is AsyncImagePainter.State.Success) {
            overlayBitmap = overlayImageLoadedState.result.drawable.toBitmap()
        }

        val baseImageLoadedState = baseImageLoaded.state
        if (baseImageLoadedState is AsyncImagePainter.State.Success) {
            baseBitmap = baseImageLoadedState.result.drawable.toBitmap()
        }

        MyCanvasComposable(baseBitmap, overlayBitmap)

1 ответ

Вы должны назначить размер для создаваемого рисовальщика, иначе он вернет ошибку

      val overlayPainter = rememberAsyncImagePainter(
    model = ImageRequest.Builder(LocalContext.current)
        .data(overlayImage)
        .size(coil.size.Size.ORIGINAL) // Set the target size to load the image at.
        .build()
)
val basePainter = rememberAsyncImagePainter(
    model = ImageRequest.Builder(LocalContext.current)
        .data(baseImage)
        .size(coil.size.Size.ORIGINAL) // Set the target size to load the image at.
        .build()
)

Результат

Вы можете отправить оба ImageBitmaps, когда оба состояния успешны с

      @Composable
private fun MyComposable() {

    val overlayImage =
        "https://st2.depositphotos.com/1400069/5999/i/600/depositphotos_59995765-stock-photo-abstract-galaxy-background.jpg"
    val baseImage =
        "https://www.vitrinesdocomercio.com/uploads/1/3/9/4/13943900/1278180_orig.jpg"


    val overlayPainter = rememberAsyncImagePainter(
        model = ImageRequest.Builder(LocalContext.current)
            .data(overlayImage)
            .size(coil.size.Size.ORIGINAL) // Set the target size to load the image at.
            .build()
    )
    val basePainter = rememberAsyncImagePainter(
        model = ImageRequest.Builder(LocalContext.current)
            .data(baseImage)
            .size(coil.size.Size.ORIGINAL) // Set the target size to load the image at.
            .build()
    )

    val overlayImageLoadedState = overlayPainter.state
    val baseImageLoadedState = basePainter.state

    if (
        baseImageLoadedState is AsyncImagePainter.State.Success &&
        overlayImageLoadedState is AsyncImagePainter.State.Success
    ) {

        SideEffect {
            println(" COMPOSING...")
        }

        val baseImageBitmap =
            baseImageLoadedState.result.drawable.toBitmap()
                .asImageBitmap()
        val overlayImageBitmap =
            overlayImageLoadedState.result.drawable
                .toBitmap()
                .asImageBitmap()

        EraseBitmapSample(
            baseImageBitmap = baseImageBitmap,
            overlayImageBitmap = overlayImageBitmap,
            modifier = Modifier
                .fillMaxWidth()
                .aspectRatio(4 / 3f)
        )
    }
}

И что вы хотите достичь

      @Composable
fun EraseBitmapSample(
    overlayImageBitmap: ImageBitmap,
    baseImageBitmap: ImageBitmap,
    modifier: Modifier
) {

    var matchPercent by remember {
        mutableStateOf(100f)
    }

    BoxWithConstraints(modifier) {

        // Path used for erasing. In this example erasing is faked by drawing with canvas color
        // above draw path.
        val erasePath = remember { Path() }

        var motionEvent by remember { mutableStateOf(MotionEvent.Idle) }
        // This is our motion event we get from touch motion
        var currentPosition by remember { mutableStateOf(Offset.Unspecified) }
        // This is previous motion event before next touch is saved into this current position
        var previousPosition by remember { mutableStateOf(Offset.Unspecified) }

        val imageWidth = constraints.maxWidth
        val imageHeight = constraints.maxHeight


        val drawImageBitmap = remember {
            Bitmap.createScaledBitmap(
                overlayImageBitmap.asAndroidBitmap(),
                imageWidth,
                imageHeight,
                false
            )
                .asImageBitmap()
        }

        // Pixels of scaled bitmap, we scale it to composable size because we will erase
        // from Composable on screen
        val originalPixels: IntArray = remember {
            val buffer = IntArray(imageWidth * imageHeight)
            drawImageBitmap
                .readPixels(
                    buffer = buffer,
                    startX = 0,
                    startY = 0,
                    width = imageWidth,
                    height = imageHeight
                )

            buffer
        }

        val erasedBitmap: ImageBitmap = remember {
            Bitmap.createBitmap(imageWidth, imageHeight, Bitmap.Config.ARGB_8888).asImageBitmap()
        }

        val canvas: Canvas = remember {
            Canvas(erasedBitmap)
        }

        val paint = remember {
            Paint()
        }

        val erasePaint = remember {
            Paint().apply {
                blendMode = BlendMode.Clear
                this.style = PaintingStyle.Stroke
                strokeWidth = 30f
            }
        }


        canvas.apply {
            val nativeCanvas = this.nativeCanvas
            val canvasWidth = nativeCanvas.width.toFloat()
            val canvasHeight = nativeCanvas.height.toFloat()


            when (motionEvent) {

                MotionEvent.Down -> {
                    erasePath.moveTo(currentPosition.x, currentPosition.y)
                    previousPosition = currentPosition

                }
                MotionEvent.Move -> {

                    erasePath.quadraticBezierTo(
                        previousPosition.x,
                        previousPosition.y,
                        (previousPosition.x + currentPosition.x) / 2,
                        (previousPosition.y + currentPosition.y) / 2

                    )
                    previousPosition = currentPosition
                }

                MotionEvent.Up -> {
                    erasePath.lineTo(currentPosition.x, currentPosition.y)
                    currentPosition = Offset.Unspecified
                    previousPosition = currentPosition
                    motionEvent = MotionEvent.Idle

                    matchPercent = compareBitmaps(
                        originalPixels,
                        erasedBitmap,
                        imageWidth,
                        imageHeight
                    )
                }
                else -> Unit
            }

            with(canvas.nativeCanvas) {
                drawColor(android.graphics.Color.TRANSPARENT, PorterDuff.Mode.CLEAR)

                drawImageRect(
                    image = drawImageBitmap,
                    dstSize = IntSize(canvasWidth.toInt(), canvasHeight.toInt()),
                    paint = paint
                )

                drawPath(
                    path = erasePath,
                    paint = erasePaint
                )
            }
        }

        val canvasModifier = Modifier.pointerMotionEvents(
            Unit,
            onDown = { pointerInputChange ->
                motionEvent = MotionEvent.Down
                currentPosition = pointerInputChange.position
                pointerInputChange.consume()
            },
            onMove = { pointerInputChange ->
                motionEvent = MotionEvent.Move
                currentPosition = pointerInputChange.position
                pointerInputChange.consume()
            },
            onUp = { pointerInputChange ->
                motionEvent = MotionEvent.Up
                pointerInputChange.consume()
            },
            delayAfterDownInMillis = 20
        )

        Image(
            bitmap = baseImageBitmap,
            contentDescription = null
        )

        Image(
            modifier = canvasModifier
                .clipToBounds()
                .matchParentSize()
                .border(2.dp, Color.Green),
            bitmap = erasedBitmap,
            contentDescription = null,
            contentScale = ContentScale.FillBounds
        )

    }

    Text(
        text = "Bitmap match ${matchPercent}%",
        color = Color.Red,
        fontSize = 22.sp,
    )
}
Другие вопросы по тегам