johanneskueber.com

Getting the color palette of an image with Coil in Android

#android#coil#kotlin#library#snippet

For part of my applications I wanted to load an image into an activity. Based on the images main colors, I wanted to adjust the UI of the activity. Loading of the image is the easy part. This can be done via a number of libraries. At the time of writing, the most prominent libraries are: Picasso and Glide. Lately however, there is a new library which targets Kotlin specifically: Coil (see coil-kt.github.io/coil/).

I was an avid user of Glide in my projcet before, but I became somehow tired of it (especially GlideModules). And since I am curious I wanted to try something new: lets use Coil.

However, to fit my requirements, I need a way to extract the colors of the loaded images in order to align the UI colors with the colors from the loaded image. Googles term for most prominent colors is Palette. And since the palette functionality is provided by Google Android Platte Library, the only change required is gathering the source bitmap for palette creation. With using Glide, this can be done using a request listener or even a dedicated library. For Coil, I did not find a libray and no request listeners. Instead, Coil offers Transformations.

The Idea

The idea is simple and always the same - no matter which library you are using:

  1. load the image using coil
  2. extract a bitmap via a transformation using coil
  3. create a platte from the extracted bitmap
  4. extract the required colors from the palette

The Code

The following snippet can be placed anywhere in the source code. I currently use it in my abstract base activity class, all activities in my application inherit from. It can therefor directly access parts of the layout and I do not need to pass those reference to the transformation. Another idea would be to place it somewhere separate. All references to the ImageView, the url to be loaded and the layout parameters to be altered would be needed to be passed to the function. Another solution could include returning the palette. As you can see below, I chose dirtiest, but quickest solution.

banner.load(url) {
    transformations(object: Transformation {
        override fun key() = "paletteTransformer"

        override suspend fun transform(pool: BitmapPool, input: Bitmap): Bitmap {

            val p = Palette.from(input).generate()

            toolbar_layout.setStatusBarScrimColor(p.getDarkVibrantColor(0))

            toolbar_layout.setExpandedTitleTextAppearance(R.style.text_title)

            val swatch = p.vibrantSwatch
            if (swatch != null) {
                toolbar_layout.setContentScrimColor(swatch.rgb)
                toolbar_layout.setCollapsedTitleTextColor(swatch.titleTextColor)
            }

            return input
        }

    })
}

Some details:

The Result

As you can see, the change is really short and really simple. In my app, the image is loaded and the colors of the toolbar are set dynamically based on the image shown. Since the color palette for the movies differs, the toolbar color also changes. Star Wars and Captain Marvel were chosen as an example. Their color palette is not hugely different - but you can see the result.

This is what the final product looks like:


stat /blog/android-coil-palette/

2019-12-12: Initial publication of the article
2019-12-18: Added sample videos to show the effect of dynamic colors
2019-01-08: Removal of minor typos