2

In the view World we can just use View.draw(canvas) to draw view on our Canvas (which might be connected to bitmap). But here in compose how can we achieve the same.

We have a draw modifier but it has no method draw(canvas)

Update

What I need?

I wanted to blur a composable function by wrapping it inside a Blur Composable. Suppose xyz() is any random composabel function.

 @Composable
fun xyz(){
// compose logic.
}

I want to create another fun called Blur().

@Composable
fun Blur(content: @Composable() -> Unit){
//Blur logic.
}

The Blur composable takes any composable function (say xyz()) as input and Blurs it.

How I am going to implement it?

I thought I would take the same approach which the BlurView (A view blur library) takes.

  • The Blur View is a frame layout.
  • it blurs its content.
  • The BlurView first creates the bitmap of the content; blurs it; then draws it.
  • The function used to create teh bitmap of the content is view.draw(canvas: Canvas)

Why I need this?

I thought of creating my version of BlurView in compose. I know in compose there is a Modifier.blur; but since this is only supported in api 31( I guess) so I can't use it in my project.

3 Answers 3

2
+25

In Compose there is a Canvas composable function available with DrawScope. You can make use of that to draw.

DrawScope has drawImage function to take ImageBitmap. As you have Bitmap need to convert that using Bitmap.asImageBitmap()

Sign up to request clarification or add additional context in comments.

7 Comments

I need view to draw on canvus not just random bitmap.
In DrawScope you will have all Canvas operations.
That I Know and I am not looking for that. What I want is I want any random composable draw on my Canvas.
Can I describe more about the situation?
Thanks for ur time. Please re-read the question I have updated it.
|
0

As noted in another reply you can create a composable that uses a canvas and this will give you access to many of the same drawing methods you have in a regular View canvas.

@Composable
fun MyCanvasComposable(
    data: List<Int>, //some example data to pass in
    modifier: Modifier = Modifier
) {
        Canvas() {
            .. content here     
        }
}

Within the canvas you will be inside a DrawScope, which will allow you to do the canvas drawing as previous.

I'll add some examples assuming we're pulling the drawing logic into extension methods.

Examples:

Drawing some Text

internal fun DrawScope.drawSomeText() {
    //some logic here before drawing the text
    drawContext.canvas.nativeCanvas.drawText(
            [[your text]],
            positionX,
            positionY,
            paint
        )
}

Drawing a Path

internal fun DrawScope.plotXAxis(    
        //some custom rendering here followed by this method    
        drawPath(path, pathBrush, 0.5f)
}

In order to put your canvas on another layout you would call MyCanvasComposable with whatever layout modifiers are appropriate.

If you're trying to render other composables on top of the canvas the way you would do that is to just wrap the whole thing in a box and add the views before or after the canvas draw.

Example:

val myPainter = painterResource(id = R.drawable.src_image)
Box {

    Image(
        painter = myPainter
    )

    Canvas() {

        .. content here ..

    }

    Text( "some text")
}

In the above example you could also just call MyCanvasComposable instead of Canvas().

Note also Image will render before the canvas and Text will render after, which is to say on top of the canvas.

4 Comments

Thanks for you time. Much appreciated. I know I can get access to canvas using Canvus composable.
I will surely update the question once I am home?
I have updated the question. Please re-read it? Thanks.
Thanks again. I think you misunderstood my question. What I want to achieve is Blur any composable using my composable implementation. Blur(@composable () -> Unit ) {// content to be blured}
0

If you want to have a Bitmap that has been blurred from your View function or methods like RenderScript mentioned here, and draw landmarks or shapes on it you can use androidx.compose.ui.graphics.Canvas instead of androidx.compose.foundation.Canvas

val option = BitmapFactory.Options()
option.apply {
    inPreferredConfig = Bitmap.Config.ARGB_8888
    inMutable = true
}

val imageBitmap = RenderEffect.createBitmapEffect(Bitmap bitmap)

for api 31-

private Bitmap blur(Bitmap original, float radius) {
  Bitmap bitmap = Bitmap.createBitmap(
      original.getWidth(), original.getHeight(),
      Bitmap.Config.ARGB_8888);

  RenderScript rs = RenderScript.create(this);

  Allocation allocIn = Allocation.createFromBitmap(rs, original);
  Allocation allocOut = Allocation.createFromBitmap(rs, bitmap);

  ScriptIntrinsicBlur blur = ScriptIntrinsicBlur.create(
      rs, Element.U8_4(rs));
  blur.setInput(allocIn);
  blur.setRadius(radius);
  blur.forEach(allocOut);

  allocOut.copyTo(bitmap);
  rs.destroy();
  return bitmap;
} 

I'm not on my PC at the moment, when i'm available i will add it as modifier.

// 🔥 This is a function that returns Canvas which can be used to draw on an
// ImageBitmap that was sent as param. ImageBitmap that returned can be
// be used to display on Image or can be saved to a physical file.

val canvas: androidx.compose.ui.graphics.Canvas = Canvas(imageBitmap)

val paint = remember {
    Paint().apply {
        style = PaintingStyle.Stroke
        strokeWidth = 10f
        color = Color(0xff29B6F6)

    }
}

canvas.drawRect(0f, 0f, 200f, 200f, paint = paint)
canvas.drawCircle(
    Offset(
        imageBitmap.width / 2 - 75f,
        imageBitmap.height / 2 + 75f
    ), 150.0f, paint
)


// This bitmap has image and the drawing from canvas
Image(bitmap = imageBitmap, contentDescription = null)

3 Comments

Thankyou sir for ur help. What I first need is to draw composable on bitmap then blur it and emit new composable with result bitmap.
@SheikhZakirAhmad you need to use RenderScript as you can see how you can do it in the link i shared for below 31 api or RenderEffect, this is what Modifier.blur uses to blur an image, then you can use my answer after you get that Bitmap and draw on it and get the result ImageBitmap or Bitmap and set it to Imageor save physical file
RenderEffect documentation here

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.