How to Use Images in Jetpack Compose?

Jetpack Compose Image

In this article, we’ll learn how to use images in Jetpack Compose with the help of examples.

Prerequisites:

First, create an empty Jetpack Compose project and open MainActivity. Next, create a MyUI() composable and call it from the onCreate() method. We will write our code in it.

MainActivity for Material 3 Jetpack Compose:

// add the following imports
import android.os.Bundle
import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.Image
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Search
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.BlurredEdgeTreatment
import androidx.compose.ui.draw.blur
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.core.content.ContextCompat
import androidx.core.graphics.drawable.toBitmap

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            YourProjectNameTheme {
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colorScheme.background
                ) {
                    Column(
                        modifier = Modifier.fillMaxSize(),
                        verticalArrangement = Arrangement.Center,
                        horizontalAlignment = Alignment.CenterHorizontally
                    ) {
                        MyUI()
                    }
                }
            }
        }
    }
}

@Composable
fun MyUI() {

}

MainActivity for the Material 2 version:

// add the following imports
import android.os.Bundle
import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.Image
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.*
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Search
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.BlurredEdgeTreatment
import androidx.compose.ui.draw.blur
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.core.content.ContextCompat
import androidx.core.graphics.drawable.toBitmap

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            YourProjectNameTheme(darkTheme = false) {
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colors.background
                ) {
                    Column(
                        modifier = Modifier.fillMaxSize(),
                        verticalArrangement = Arrangement.Center,
                        horizontalAlignment = Alignment.CenterHorizontally
                    ) {
                        MyUI()
                    }
                }
            }
        }
    }
}

@Composable
fun MyUI() {

}

Note: I am using the Material 3 Jetpack Compose. If you are working with Material 2, you may see a slightly different appearance, but the code will still work as expected.

Next, download the dog image. Select 640×462 size while downloading it. Change its name to dog.jpg and put it in the res > drawable folder.

Jetpack Compose provides Image API. If you are familiar with XML, it is the ImageView. In the Android Studio, start typing Image and select the one with the painter parameter. We will talk about the other overloads in a moment.

Jetpack Compose Image Painter

It looks like this:

@Composable
fun Image(
    painter: Painter,
    contentDescription: String?,
    modifier: Modifier = Modifier,
    alignment: Alignment = Alignment.Center,
    contentScale: ContentScale = ContentScale.Fit,
    alpha: Float = DefaultAlpha,
    colorFilter: ColorFilter? = null
)

painter – It is to draw the image on the screen.

contentDescription – It is a text that describes the image. Accessibility services (like screen readers) use this text. If you don’t want this behavior, pass null.

modifier – To modify the layout.

alignment – It aligns the image in the given bounds.

contentScale – It is used to scale the image. Look at the official docs for the visual guide.

alpha – Opacity of the image. 0f represents fully transparent and 1f represents fully opaque.

colorFilter – It modifies the individual pixels of the image.

Simple Image Example:

For a simple image, painter and contentDescription are mandatory. We can get the Painter object from the painterResource() method.

@Composable
fun painterResource(@DrawableRes id: Int): Painter

Here, id represents the drawable resource id (an integer) of the image.

painterResource currently supports the following drawable types:

  • AnimatedVectorDrawable
  • BitmapDrawable (PNG, JPG, WEBP)
  • ColorDrawable
  • VectorDrawable

Example:

@Composable
fun MyUI() {
    Image(
        painter = painterResource(id = R.drawable.dog),
        contentDescription = "Dog Image"
    )
}

Output:

Simple Image Example in Jetpack Compose

Image Size:

We can set the image size using the size() modifier.

@Composable
fun MyUI() {
    Image(
        modifier = Modifier.size(size = 200.dp),
        painter = painterResource(id = R.drawable.dog),
        contentDescription = "Dog Image"
    )
}

Output:

Image Size

Image Button:

We can create an image button by using the clickable modifier.

@Composable
fun MyUI() {
    val contextForToast = LocalContext.current.applicationContext

    Image(
        painter = painterResource(id = R.drawable.dog),
        contentDescription = "Dog Image",
        modifier = Modifier.clickable {
            Toast.makeText(contextForToast, "Click!", Toast.LENGTH_SHORT).show()
        }
    )
}

Output:

Image Button

Related: How to Remove the Ripple in Jetpack Compose?

Circular Image:

To make an image fit into a shape, use the built-in clip modifier. Jetpack Compose offers several shape APIs. We use the CircleShape to create a circle effect.

@Composable
fun MyUI() {
    Image(
        painter = painterResource(id = R.drawable.dog),
        contentDescription = null,
        modifier = Modifier
            .size(160.dp)
            .clip(CircleShape)
            .border(width = 2.dp, color = Color.Green, shape = CircleShape),
        contentScale = ContentScale.Crop
    )
}

Output:

Circular Image

Note: Instead of CircleShape, we can also pass RoundedCornerShape(percent = 50).

Image with Custom Aspect Ratio:

We can set a custom aspect ratio using the modifier’s aspectRatio() method.

@Composable
fun MyUI() {
    Image(
        painter = painterResource(id = R.drawable.dog),
        contentDescription = null,
        modifier = Modifier.aspectRatio(16f / 9f)
    )
}

Output:

custom aspect ratio

Image with Blur Effect:

Jetpack Compose provides blur modifier from the Android 12 and above. It looks like this:

@Stable
fun Modifier.blur(
    radiusX: Dp,
    radiusY: Dp,
    edgeTreatment: BlurredEdgeTreatment = BlurredEdgeTreatment.Rectangle,
): Modifier

radiusX – Radius of the blur along the x axis.

radiusY – Radius of the blur along the y axis.

edgeTreatment – It decides how to render pixels outside of bounds of the image.

There are two options for edgeTreatment:

1. BlurredEdgeTreatment(shape) – It doesn’t blur the pixels outside the bounds of the image. As a result, the edges of the image appear sharp.

2. BlurredEdgeTreatment.Unbounded – It is used for blurring pixels outside the bounds of the image. As a result, the edges of the image appear blurred.

Examples:

Using BlurredEdgeTreatment(shape):

@Composable
fun MyUI() {
    Image(
        painter = painterResource(id = R.drawable.dog),
        contentDescription = null,
        modifier = Modifier
            .size(size = 160.dp)
            .blur(
                radiusX = 10.dp,
                radiusY = 10.dp,
                edgeTreatment = BlurredEdgeTreatment(shape = RoundedCornerShape(percent = 5))
            ),
        contentScale = ContentScale.Crop
    )
}

Output:

Blur image shape

Using BlurredEdgeTreatment.Unbounded:

@Composable
fun MyUI() {
    Image(
        painter = painterResource(id = R.drawable.dog),
        contentDescription = null,
        modifier = Modifier
            .size(size = 160.dp)
            .blur(
                radiusX = 10.dp,
                radiusY = 10.dp,
                edgeTreatment = BlurredEdgeTreatment.Unbounded
            ),
        contentScale = ContentScale.Crop
    )
}

Output:

blur image unbounded

Note: As I mentioned, the blur effect is only supported on Android 12 and above. If you use this Modifier on older versions, it results in no action.

Don’t worry. I found the following two libraries that support the blur effect on all Android versions:

  1. Cloudy – github.com/skydoves/Cloudy
  2. xBlur – github.com/x3rocode/xblur-compose/tree/main

Loading Image from a URL:

We can use the Coil library for loading images from a URL. First, add the internet permission in the AndroidManifest file.

<?xml version="1.0" encoding="utf-8"?>
<manifest>
 ...
    <uses-permission android:name="android.permission.INTERNET" />
 ...
</manifest>

Next, add the following dependency in the app-level gradle file.

implementation("io.coil-kt:coil-compose:2.4.0")

Paste the following imports in the MainActivity:

import coil.compose.rememberAsyncImagePainter
import coil.compose.rememberImagePainter

Coil provides rememberAsyncImagePainter() method to load an image from a URL.

Example:

@Composable
fun MyUI() {
    val asyncPainter =
        rememberAsyncImagePainter("http://semicolonspace.com/wp-content/uploads/2023/02/forest.jpg")

    Image(
        painter = asyncPainter,
        contentDescription = null
    )
}

Output:

Loading Image from URL

Related: How to Check Internet Connection in Android Programmatically?

Setting Image as Background for Box or Card:

It’s easy to set the image as the background for Box or Card. First, add an Image in the Box, then add the content.

@Composable
fun MyUI() {
    Box(modifier = Modifier.size(size = 200.dp)) {
        // add the image
        Image(
            modifier = Modifier.size(size = 200.dp),
            painter = painterResource(id = R.drawable.dog),
            contentDescription = "Dog Image"
        )
        // add the content on the image here
        Column(
            modifier = Modifier
                .fillMaxSize(),
            verticalArrangement = Arrangement.Center,
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            Text(
                text = "Hello!",
                color = Color.White,
                fontSize = 26.sp,
                fontWeight = FontWeight.Bold
            )
        }
    }
}

Output:

Setting Image as Background for Box or Card

Related: Custom Switch Using the Box API

Image composable comes with two additional overloads, one that includes an imageVector parameter and another with a bitmap parameter. Let’s look at them.

Image() with imageVector parameter:

It helps us to draw image vectors.

@Composable
@NonRestartableComposable
fun Image(
    imageVector: ImageVector,
    contentDescription: String?,
    modifier: Modifier = Modifier,
    alignment: Alignment = Alignment.Center,
    contentScale: ContentScale = ContentScale.Fit,
    alpha: Float = DefaultAlpha,
    colorFilter: ColorFilter? = null
)

Example:

@Composable
fun MyUI() {
    Image(
        imageVector = Icons.Default.Search,
        contentDescription = null,
        modifier = Modifier.size(size = 100.dp)
    )
}

Output:

Image with imageVector parameter

Related: Icons in Jetpack Compose

Image() with bitmap Parameter:

It helps us to draw bitmap objects.

@Composable
@NonRestartableComposable
fun Image(
    bitmap: ImageBitmap,
    contentDescription: String?,
    modifier: Modifier = Modifier,
    alignment: Alignment = Alignment.Center,
    contentScale: ContentScale = ContentScale.Fit,
    alpha: Float = DefaultAlpha,
    colorFilter: ColorFilter? = null,
    filterQuality: FilterQuality = DefaultFilterQuality
)

There is an extra parameter called filterQuality. It is the sampling algorithm applied to the bitmap when it is scaled and drawn into the destination.

Example:

@Composable
fun MyUI() {
    val context = LocalContext.current
    val bitmap = ContextCompat.getDrawable(context, R.drawable.dog)?.toBitmap()
        ?.asImageBitmap()!!

    Image(
        bitmap = bitmap,
        contentDescription = null,
        modifier = Modifier.size(size = 100.dp)
    )
}

Output:

Image bitmap in Jetpack Compose

This is all about displaying images in Jetpack Compose. I hope you have learned something new. If you have any doubts, comment below.

For more information, look at the Android docs.

Related Articles:

Leave a Comment