Back in February, Chris Banes’ two excellent blog posts (color matching part one and part two) demonstrated 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 dynamically colored UI elements, or a filter based on the dominant color of your bitmap. 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 dark
- vibrant light
- 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:
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.
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.