https://kotlinlang.org logo
#compose
Title
# compose
d

Daniel

03/07/2021, 3:42 PM
The docs for
BlendMode.SrcIn
appear to be incorrect.
Copy code
Show the source image, but only where the two images overlap. 
The destination image is not rendered, it is treated merely as a mask. 
The color channels of the destination are ignored, only the opacity has an effect
The color channels of the destination are used. Assuming this just wraps the native equivalent, this would be the expected behavior. Asking here to check I'm not missing something stupid before I file a bug.
r

romainguy

03/07/2021, 6:03 PM
What does the preview show?
Note that blend modes require an alpha channel and that a window on Android is opaque by default. Not sure whether preview uses an opaque or transparent render target
d

Daniel

03/07/2021, 6:05 PM
Here's an example. Code:
Copy code
Canvas {    
    drawIntoCanvas {
            it.nativeCanvas.drawText(text, textPadding, baseline, paint)
        }

        drawRect(
            Brush.linearGradient(0f to Color.Transparent, 1f to Color.Blue),
            size = Size(sizePx.width, turnSpace),
            blendMode = BlendMode.SrcIn
        )
}
I'm also confused by why the emulator shows no effect
If the issue is that the canvas doesn't have alpha, how can I fix that? @romainguy
r

romainguy

03/07/2021, 6:10 PM
The preview looks correct. Not sure why the device doesn't show the rectangle. To get an alpha render target you need to render into a layer (or into a bitmap ahead of time, a layer is easier)
d

Daniel

03/07/2021, 6:10 PM
I've tried adding a graphicsLayer and then a drawBehind, but it didn't fix the issue
r

romainguy

03/07/2021, 6:11 PM
Why a drawBehind?
d

Daniel

03/07/2021, 6:11 PM
@romainguy My initial question was that in the preview the blue color is transferred to the black letter, but based on the docs only the alpha should be transferred.
@romainguy I'm just using drawBehind to get a drawscope. Is that wrong?
Copy code
Spacer(
        Modifier
            .size(size.x, size.y)
            .graphicsLayer()
            .drawBehind {
                drawIntoCanvas {
                    it.nativeCanvas.drawText(text, textPadding, baseline, paint)
                }

                drawRect(
                    Brush.linearGradient(0f to Color.Transparent, 1f to Color.Blue),
                    size = Size(sizePx.width, turnSpace),
                    blendMode = BlendMode.SrcIn
                )
r

romainguy

03/07/2021, 6:11 PM
Also note that if you are trying to draw text with a gradient it's much easier to do so by setting the gradient on the paint used to draw text
And no the doc isn't wrong. The colors of the destination (the text) are ignored
Your gradient is the source here
d

Daniel

03/07/2021, 6:12 PM
Oh, thank you. I mixed up src and dest
I move the text up and down and want different parts of the gradient to be applied in each case. I think that's easier if I keep the gradient static, instead of computing different values for the gradient?
@romainguy the same code gives me a third result if I deploy the preview to an actual device (same type and api level as emulator)
(I get the same inconsistency if I deploy the whole app vs a preview)
r

romainguy

03/07/2021, 7:49 PM
You can keep the gradient static and still set it as a shader on the text paint
d

Daniel

03/07/2021, 8:18 PM
I would need to change the gradient bounds as the text moved then, to simulate the effect of the gradient staying still while the text moved. Otherwise the gradient and text move in unison, making it look like the gradient isn't moving
r

romainguy

03/08/2021, 12:35 AM
I haven't checked in compose but in native shaders you can set a local transform on the shader for that