ImageBitmap vs ImageVector

The two most common kinds of image formats are raster and vector images.

A raster graphic format contains pixels: tiny individual squares that contain a color (made up of red, green, blue, and alpha values). When placing a lot of pixels together, a very detailed image can be formed, such as a photograph. A raster graphic has a fixed resolution (fixed number of pixels). This means that when you increase the size of the image, it loses detail, and pixelation can occur. Examples of raster graphic formats are JPEG, PNG, and WEBP.

JPEG file example
Figure 1: JPEG file example

Vector images, on the other hand, are scalable mathematical representations of a visual element on screen. A vector is a set of commands describing how to draw the image on screen- for instance, a line, point, or fill. When scaling a vector on screen, it will not lose quality as the mathematical formula will maintain the relationship between the different commands. A good example of ImageVector are the Material Symbols, as they can all be defined with mathematical formulas.

Vector example (file extensions are .xml or defined in Kotlin code)
Figure 2: Vector example (file extensions are .xml or defined in Kotlin code)

ImageBitmap

In Compose, a raster image (often referred to as a Bitmap) can be loaded up into an ImageBitmap instance, and a BitmapPainter is what is responsible for drawing the bitmap to screen.

For simple use cases, the painterResource() can be used which takes care of creating an ImageBitmap and returns a Painter object (in this case - a BitmapPainter):

Image(
    painter = painterResource(id = R.drawable.dog),
    contentDescription = stringResource(id = R.string.dog_content_description)
)

If you require further customization (for instance a custom painter implementation) and need access to the ImageBitmap itself, you can load it in the following way:

val imageBitmap = ImageBitmap.imageResource(R.drawable.dog)

ImageVector

A VectorPainter is responsible for drawing an ImageVector to screen. ImageVector supports a subset of SVG commands. Not all images can be represented as vectors (for example, the photos you take with your camera cannot be transformed into a vector).

You can create a custom ImageVector either by importing an existing vector drawable XML file (imported into Android Studio using the import tool) or implementing the class and issuing path commands manually.

For simple use cases, the same way in which painterResource() works for the ImageBitmap class, it also works for ImageVectors, returning a VectorPainter as the result. painterResource() handles the loading of VectorDrawables and BitmapDrawables into VectorPainter and BitmapPainter respectively. To load a VectorDrawable into an image, use:

Image(
    painter = painterResource(id = R.drawable.baseline_shopping_cart_24),
    contentDescription = stringResource(id = R.string.shopping_cart_content_desc)
)

If you’d require further customization and need to access to the ImageVector itself, you can load it in the following way:

val imageVector = ImageVector.vectorResource(id = R.drawable.baseline_shopping_cart_24)