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

spierce7

06/14/2022, 9:54 PM
How would I use an image as a mask in compose? I have an effect that I’m drawing as a Shader, but I only want it to be applied there there are non-transparent pixels for an image. How would I do that?
r

romainguy

06/14/2022, 10:04 PM
It will work with an ALPHA_8 bitmap
One way to do this is create an ALPHA_8 bitmap, create a Canvas for it, draw your original image into it
Now you have an alpha mask
And this can be combined with other shaders to work like you want, as a mask
s

spierce7

06/14/2022, 10:09 PM
create an ALPHA_8 bitmap, create a Canvas for it, draw your original image into it
How would I do this? I’ve never heard of an Alpha 8 bitmap
create a Canvas for it
Is this an Android Canvas? Technically I’m doing this on Compose Desktop
I see - Compose ImageBitmap has an Alpha 8 option.
I understand generally what you are saying, but I’m struggling to apply it. I don’t suppose you have a sample?
k

Kirill Grouchnikov

06/14/2022, 11:13 PM
Your shader has access to every single pixel in the image. So it can look at the input alpha, and based on that output either transparent color or apply the filter on that pixel.
s

spierce7

06/14/2022, 11:35 PM
@Kirill Grouchnikov So here’s what I have:
Copy code
val svgPainter: Painter
val shader = Shader.makeFractalNoise(
    baseFrequencyX = 8.21f,
    baseFrequencyY = 8.21f,
    numOctaves = 3,
    seed = 0.0f,
)
val shaderBrush = ShaderBrush(shader)

Canvas(
    modifier = Modifier.size(width = maxWidth.dp, height = maxHeight.dp)
) {
    drawRect(shaderBrush)
}
I’m not understanding how this all comes together. I want to use the shader as a mask so that I can draw the
svgPainter
where the
shaderBrush
draws something.
I’ve looked at
BlendMode
and it sounds like it could work, but there aren’t a ton of examples of this online.
r

romainguy

06/14/2022, 11:38 PM
I should check compose desktop
But the equivalent of Paint.setShader will use a bitmap as an alpha mask
Ie draw bitmap(theMask, thePaint) will do what you want
BlendMode will only work when you render into an intermediate transparent layer
s

spierce7

06/14/2022, 11:40 PM
But the equivalent of Paint.setShader will use a bitmap as an alpha mask
So both Skia
Paint
and androidx
Paint
look like there is a
setShader
method. How does the bitmap come into play?
It looks like part of my problem is that I need to somehow get my svg
Painter
to a bitmap or drawn on the canvas.
ok - I found out how to draw the svg painter on the canvas. I’m still not understanding how to use the shader as a mask.
Copy code
val shader = Shader.makeFractalNoise(
    baseFrequencyX = 8.21f,
    baseFrequencyY = 8.21f,
    numOctaves = 3,
    seed = 0.0f,
)
val shaderBrush = ShaderBrush(shader)

val svgSize = Size(width = maxWidth.toFloat(), height = maxHeight.toFloat())
Canvas(
    modifier = Modifier.size(width = maxWidth.dp, height = maxHeight.dp)
) {
    drawRect(shaderBrush, size = svgSize)

    with(svgPainter) {
        draw(size = svgSize)
    }
}
r

romainguy

06/15/2022, 12:05 AM
Is the noise your mask?
s

spierce7

06/15/2022, 12:05 AM
yes
The SVG is something like this.
I need to produce something like this
This was achieved by using the fractal noise as a mask on the SVG
I should be able to create the same thing in compose
r

romainguy

06/15/2022, 12:11 AM
Note that you probably don’t even need the SVG for this. You could just use gradients. Anyway, there are two ways you can do this:
• Create an ARGB8888 bitmap, draw SVG, then draw the noise as a rect using the appropriate BlendMode
• Create an ALPHA_8 bitmap, draw the noise in it. Create another bitmap, draw the SVG in it. Draw the first bitmap, using the second bitmap as its brush
Since your SVG doesn’t use colors, the second method is a bit wasteful
s

spierce7

06/15/2022, 12:14 AM
@romainguy I do need the SVG for this. This is being applied to a templating system on a JVM server that uses Compose to render images for customers on the fly. This is the shadow for 1 of 8 image templates that’s being rendered currently.
we were using html to generate the images, but compose can do in millis what html can do in 8-15 seconds.
r

romainguy

06/15/2022, 12:42 AM
If your goal is generating images then solution #1 I highlighted above is probably best
s

spierce7

06/15/2022, 12:42 AM
I think I’ve got #1 working correctly
r

romainguy

06/15/2022, 12:43 AM
Create an ARGB8888 image, draw your SVG, then apply the mask with
DST_IN
(or
CLEAR
but I don’t remember if
CLEAR
modulates by alpha)
s

spierce7

06/15/2022, 12:43 AM
Copy code
val bitmap = ImageBitmap(width = width, height = height, config = ImageBitmapConfig.Alpha8)
    .also { bitmap ->
        val canvas = Canvas(bitmap)

        val shaderBrush = ShaderBrush(
            Shader.makeFractalNoise(
                baseFrequencyX = 8.21f,
                baseFrequencyY = 8.21f,
                numOctaves = 3,
                seed = 0.0f,
            )
        )

        val svgSize = Size(width = width.toFloat(), height = height.toFloat())
        CanvasDrawScope().draw(LocalDensity.current, LayoutDirection.Ltr, canvas, svgSize) {
            with(painter) {
                draw(size = svgSize)
            }

            drawRect(brush = shaderBrush, size = svgSize, blendMode = BlendMode.DstIn)
        }
    }
It looks like the shadow it’s creating is black now though
It’s not maintaining the original color of the shadow
r

romainguy

06/15/2022, 12:44 AM
Yeah because you are creating an
ALPHA_8
bitmap
Make it ARGB888 or whatever is the equivalent
s

spierce7

06/15/2022, 12:45 AM
ah
that’s what I was about to try
Argb8888
Works perfectly. I love compose so much.
Thanks @romainguy and thanks @Kirill Grouchnikov for your blog posts on Skia shaders. They really helped me out here!
s

Stylianos Gakis

06/15/2022, 6:14 AM
I can't help but think what you're doing here Scott sounds super interesting but very hard to follow from a slack thread. But I feel like I'd love to see exactly what you're trying to do. If you ever have some final snippet lying around of what you're doing or you're gonna write up a blog about this I'd be super interested in reading it!
💯 1
3
18 Views