Extracting colors from images: Integrating Picasso and Palette
Since the day it was presented, the Material Design specification brought a new meaning for colors inside applications. It is not enough to pick colors and highlight components, now is mandatory to create meaning and a good environment for colors. Images also became a big highlight as main content. I think there is no better way to create a great user experience than matching colors from interface components with the colors from images of our applications. We can do this loading good quality images using Picasso library and adjusting colors of our interface using Palette extraction colors ability.
Special thanks to Unsplash’s great API that allows the obtaining of high quality random images for free.
We will start including libraries in the build.gradle file from our application. For color extracting, we will use the class Palette from the official Android Support Library. This will allow the application to be compatible with several versions from Android. We will also import Picasso library into our project.
The next step is to create the layout for our activity. This layout will contain the displayed image and TextViews to display the extracted colors. The ImageView has fixed dimensions, defined from the dimens.xml file. More about that in a few lines.
Now that we have a layout defined, let’s load some random images using Picasso. In a simple way, let’s add some lines into onCreate of our activity.
Don’t forget that Picasso has an image cache in memory while the activity is alive. To force a new download, stop the application or force the activity destruction.
The problem in this code is that we have no access to the loaded image. The library downloads the image, resize it and define sets it into the ImageView in a totally automated way. To allow us to handle the downloaded image and extract it’s colors, lets change some lines of code. Instead of loading the image into the ImageView, we will load it into a custom target. This way, we will have access to the bitmap, making easier to extract it’s colors.
Now we can handle the bitmap inside the method onBitmapLoaded. We can extract it’s colors and then set the bitmap as image source in our ImageView. But not that fast. Changing the target of image loading has another consequence: Picasso now has no dimensions to resize the image. When the loading target is an ImageView, Picasso can resize the bitmap with it’s dimensions. A custom target has no dimensions, so the bitmap we receive as parameter has the original size. Can you see the problem now? Yes, huge memory problems and possible problems with the color extraction. For that reason, we have some more lines of code. We must call resize and centerCrop to reduce the image before processing it. For resizing, the parameters used will be extracted from dimens.xml, same parameters used as ImageView dimensions.
Finally we can extract images’s colors. We can create a new instance from Palette class using the method from, using our bitmap as parameter. A new color set will be generated with the method generate. This process can take some time, so it will be executed in an asynchronous way, avoiding main thread blocks.
When the process finishes, we will have a palette with multiple combinations. We can use the method getVibrandSwatch to obtain a set of vibrant colors or the method getMutedSwatch to obtain a set of more discreet colors. I suggest you to explore the multiple methods from Palette to compare the color sets and check the one that matches your use case. Don’t forget that the sets can be null, since an image may have no vibrant colors, for example. In my sample, I used the extracted colors to change the background and TextViews’ text colors to show how the extracted colors are. Below are some of the results, runing in Android 4.4.4 (the compatibility seems to work :) ).
The full project can be found in GitHub.