Draw Image with fixed height and width jetpack compose canvas using drawImage()

913 Views Asked by At

How can I draw an image on a Jetpack Compose canvas while ensuring that the image fits perfectly within the entire canvas width and height, especially when the resolution of the image is significantly larger than the canvas size? I would like to reduce the image's size to match the canvas dimensions.

@Composable
fun Item(
    imageResId: Int,
    parallaxOffset: Float,
    pagerHeight: Dp,
    screenWidth: Dp,
    density: Float,
    scaleFactor: Float,
    modifier: Modifier = Modifier,
    imageCornerRadius: Dp = 24.dp,
    imageHeight: Dp = 250.dp,
) {
    // Load the image bitmap
    val imageBitmap = ImageBitmap.imageResource(id = imageResId)
   

  
    Column(
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.Center
    ) {
        // Card composable for the item
        Box(modifier = modifier
            .graphicsLayer {
                scaleX = scaleFactor
                scaleY = scaleFactor
            }
            .clip(RoundedCornerShape(imageCornerRadius))) {
            
            Canvas(
                modifier = Modifier
                    .fillMaxWidth()
                    .height(250.dp)
                    .clip(shape)
            ) {)
                translate(left = parallaxOffset * density) {
                    // Draw the image
                    drawImage(
                        image = imageBitmap,
                        dstOffset = IntOffset(-xOffset.toIntPx(density), 0),
                    )
                }
            }

        }
       
    }

}

Canvas Image

2

There are 2 best solutions below

0
Thracian On

You can use dstSize param to draw whole canvas if you want to.

srcSize how big image itself should be drawn dstSize how big the draw area should be inside canvas

By default dstSize is equal to srcSize and because of this when image is small draw area is smaller than Canvas. And when srcSize is bigger than Canvas dstSize draws it as big as image pixels are but since we can only see screen you only see some part of it as its cropped when image is big. By changing srcOffset you can set which part is drawn in that case as well.

You can test srcSize/Offset, dstSize/Offset params in this tutorial any image you can add to it.

https://github.com/SmartToolFactory/Jetpack-Compose-Tutorials/blob/fc09f45147e3c49d75b52fb7f0f5b46cfcb78bc9/Tutorial1-1Basics/src/main/java/com/smarttoolfactory/tutorial1_1basics/chapter6_graphics/Tutorial6_1_2CanvasBasics2.kt#L331

Result is from a image that is bigger than Canvas. First one draws the section while in second one image is fit into Canvas.

enter image description here

@Preview
@Composable
private fun CanvasScaleTest() {
    val imageBitmap = ImageBitmap.imageResource(R.drawable.sample)

    Column {
        Canvas(
            modifier = Modifier.fillMaxWidth().aspectRatio(4/3f).clipToBounds()
        ) {
            drawImage(
                image = imageBitmap,
            )
        }

        Spacer(modifier = Modifier.height(20.dp))
        Canvas(
            modifier = Modifier.fillMaxWidth().aspectRatio(4/3f).clipToBounds()
        ) {
            val canvasWidth = size.width.toInt()
            val canvasHeight = size.height.toInt()
            drawImage(
                image = imageBitmap,
                dstSize = IntSize(canvasWidth, canvasHeight)
            )
        }
    }
}
0
Laxmi kant On

you can use the DrawImageWithFixedSize composable to draw an image with a fixed width and height:

    @Composable
    fun DrawImageWithFixedSize(imageResId: Int, width: Dp, height: Dp) {
        val context = LocalContext.current
        val imageDrawable = remember(imageResId) {
            context.resources.getDrawable(imageResId, null)
        }

        val bitmap = remember(imageDrawable) {
            imageDrawable.toBitmap(
                width = (width.value * LocalDensity.current.density).roundToInt(),
                height = (height.value * LocalDensity.current.density).roundToInt()
            )
        }.asImageBitmap()

        Canvas(
            modifier = Modifier
                .fillMaxSize()
                .background(Color.White)
        ) {
            drawImage(image = bitmap)
        }
    }

Where :

    DrawImageWithFixedSize(
        imageResId = R.drawable.your_image,
        width = 200.dp,
        height = 150.dp
    )