2

I want to use BlendMode.DstAtop while doing some custom drawing with Canvas but this doesn't work as it should. Here is my code:

Column {
    Canvas(
        modifier = Modifier
            .height(90.dp)
            .fillMaxWidth()
            .graphicsLayer(
                compositingStrategy = CompositingStrategy.Offscreen
            )
    ) {
        val canvasWidth = size.width
        val canvasHeight = size.height

        drawRect(
            Color.Blue,
            Offset(canvasWidth*0.8f/2, canvasHeight*0.8f/2),
        )

        drawCircle(
            Color.Red,
            center = Offset(canvasWidth*0.8f/2, canvasHeight/2),
            blendMode = BlendMode.DstAtop
        )
    }
}

I expect to get this result for BlendMode.DstAtop: I expect to get this result for BlendMode.DstAtop: But get this instead: But get this instead:

I've also checked BlendMode.SrcIn, BlendMode.DstIn, BlendMode.Multiply, BlendMode.SrcOut, BlendMode.SrcOut and these blendmodes don't work as it should either, while BlendMode.DstOut, BlendMode.SrcAtop, BlendMode.SrcOver, BlendMode.DstOver work good.

I tried these solutions:

but it doesn't help, at least with Jetpack Compose 1.4.1

DKavaliou
  • 138
  • 1
  • 5
  • Unlike those images you draw two shapes that overlap each other only in intersection of two. But destination and source images have the same dimension with each other. So when a blend mode is applied it's applied to both dimensions. – Thracian Apr 19 '23 at 05:01
  • Ah, that's interesting. Thanks a lot, I think I got the idea why it doesn't work. You mean that I just draw a circle, not a circle with transparent background over all image. So I have another question :) Is there any way to draw a circle on transparent background over all image and use blend mode at the same time? I mean to draw this circle with drawing instructions only, without creating a separate layer on a bitmap and drawing that bitmap. – DKavaliou Apr 19 '23 at 09:08

2 Answers2

0

Change circle to Destination and rectangle to Source and apply BlendMode.SrcAtop.

enter image description here

@Preview
@Composable
private fun Test() {
    Column {
        Canvas(
            modifier = Modifier
                .height(90.dp)
                .fillMaxWidth()
                .graphicsLayer(
                    compositingStrategy = CompositingStrategy.Offscreen
                )
        ) {
            val canvasWidth = size.width
            val canvasHeight = size.height

            // Destination
            drawCircle(
                Color.Red,
                center = Offset(canvasWidth * 0.8f / 2, canvasHeight / 2),
            )

            // Source
            drawRect(
                Color.Blue,
                Offset(canvasWidth * 0.8f / 2, canvasHeight * 0.8f / 2),
                blendMode = BlendMode.SrcAtop

            )
        }
    }
}
Thracian
  • 43,021
  • 16
  • 133
  • 222
0

finally was able to do it, big thanks to @Thracian for the key. Here is the code:

Column {
Canvas(
    modifier = Modifier
        .height(90.dp)
        .fillMaxWidth()
        .graphicsLayer(
            compositingStrategy = CompositingStrategy.Offscreen
        )
) {

    val canvasWidth = size.width
    val canvasHeight = size.height


    drawRect(
        Color.Blue,
        Offset(canvasWidth*0.8f/2, canvasHeight*0.8f/2),
    )

    drawIntoCanvas {canvas ->
        canvas.saveLayer(
            Rect(Offset.Zero, Size(canvasWidth, canvasHeight)),
            Paint().apply {
                blendMode = BlendMode.DstAtop
            }
        )
        drawCircle(
            Color.Red,
            center = Offset(canvasWidth*0.8f/2, canvasHeight/2),
        )
        canvas.restore()
    }
}

}

Here it the result: result

DKavaliou
  • 138
  • 1
  • 5