A look at the Palette class

Back in February, Chris Banes’ two excellent blog posts (color matching part one and part two) showed us how can we extract the dominant colors from a bitmap. This can be a powerful asset to the user experience of your app: think about a dynamically colored ActionBar (and also the status bar in L), or a filter based on the dominant color of your bitmap. For example, the current version of iTunes paints the background with the most frequent color of the albumarts, resulting in a really cool user experience. The Palette class from the new Support Library announced at Google I/O does the same.



Currently there is no official documentation, you can refer to this article for some info on the features. The class itself can extract the dominant colors from a bitmap, including these prominent colors:

vibrant

vibrant dark

vibrant light

muted

muted dark

muted light

To understand what this means, here are some examples. The first column contains the colors from a generate() call with a number of six (note 1: sorted by the default order; note 2: I encountered an issue with one of the pictures where a param of 6 only resulted in 5 colors, so I generated 7 colors and used the first six results). The second column contains the prominent colors. For the first one I used ‘The Starry Night’ by Vincent van Gogh: A picture of the Carina Nebula: Nighthawks by Edward Hopper:

Including Palette from the Support Library

The first step is including the library in your project. You can do this with the following Gradle dependency:

compile 'com.android.support:palette-v7:+'

Palette in action

A Palette instance can be generated with static object methods, either with the generate() or the generateAsync() function. The difference between them is that with generate() the developer has to take care of the wrapping it into an async thread, since this is a potentially long running operation which shouldn’t run on the UI thread. On the other side, the generateAsync() takes a PaletteAsyncListener instance as parameter, which has an onGenerated() callback, called when the palette generation is completed. The following example uses the latter.

Palette.generateAsync(BitmapFactory.decodeResource(getResources(), R.drawable.test), new Palette.PaletteAsyncListener() { @Override public void onGenerated(Palette palette) { // do something with the colors recyclerView.setAdapter(new RecyclerAdapter(palette)); } });

Note that if you want to extract all six prominent colors, you’ll have to have a parameter larger than or equal to six. You can also specify how many colors should be generated – by default, this number is 15. The resulting Palette instance contains PaletteItems, which represent colors, with their RGB and HSL representation and population. The getPalette() method returns the whole list, however this is not ordered by population. You can also retrieve the prominent colors, discussed above.

While bitmap operations usually take some time, the generate method appeared almost instantaneous, so I wanted to support this with some measurements. The following was made on a Nexus 5 running the L dev preview, with the help of the TimingLogger class, with closing the app after each run. Each result represents the average of 5 measurements. Unsurprisingly, the time is proportional to the resolution and the number of required colors.

picture resolution 1 color 5 colors 15 colors Starry Night 2560 × 1600 28.6 ms 31.6 ms 44 ms Carina nebula 800 × 1280 19 ms 23.2 ms 26.2 ms Nighthawks 6000 × 3274 25 ms 31.4 ms 33.4 ms

In conclusion, the Palette is an awesome tool to improve UX with dynamic, content-based colors. The performance impact is small (at least on a relatively high-end device), and the benefits look great, especially with the new theme and animation possibilities in the L dev preview.