Pick colors from Images by Palette in Android

    Android Lollipop has bring us a lot of new APIs through Material design technology. One of the defining features of Material design is the use of color to compliment and emphasize content on the screen. Today, I would like to present a new library called Palette which can help you to pick colors from an image dynamically. For example if you are building an image intensive app, where user experience is of prime importance you can use Palette to extract colors from the image on screen. Further these colors could be used at prominent spaces on your screen to blend the image into your app screen. Now days a lot of effort is being spent on building a good user experience for android apps. This Palette library is something completely new which could revolutionize the user experience in Android apps.
    As we think, extracting colors from an image is very much complicated but now with Palette library, it become very simple to pick relevant colors from it. Now, let's take a studying in it!

Importing Palette

    To get started, you will need to import the palette support library into your project by including the following line in the dependencies node of your application level build.gradle file:
compile 'com.android.support:palette-v7:24.1.1'

Generating Palette from Bitmap

    There are two ways to make a Palette object from Bitmap. This can be done using the Palette.Builder either synchronously by calling the generate() method without any parameters, or asynchronously by calling generate(Palette.PaletteAsyncListener listener). Because it can take time to create the Palette, it is recommended that the synchronous method only be called from a background thread.
Code may be like this:
Bitmap bitmap = BitmapFactory.decodeResource( getResources(), R.drawable.hanoi_capital);
Palette.from(imageBitmap).generate(new PaletteAsyncListener() {
    public void onGenerated(Palette p) {
        // Use generated palette
    }
});

Swatches

    Contained within each Palette is a set of Swatch objects that will allow you to work with specific color profiles and a list of visible colors from the image. When an image is used to generate a Palette we can optionally specify the number of Swatches we want from that image. In case we don’t specify the number (like this example), 16 Swatches would be returned. But, there are some important Swatches which have name:
  • Vibrant: called Palette.getVibrantSwatch() method to get it.
  • Vibrant dark: called getDarkVibrantSwatch()  to get it.
  • Vibrant light: called getLightVibrantSwatch()  to get it.
  • Mute: called getMutedSwatch()  to get it.
  • Muted dark: called getDarkMutedSwatch()  to get it.
  • Muted light: called getLightMutedSwatch() to get it.
    There are some important methods in the Swatch class:
  • getRgb(): Returns the color in RGB value.
  • getPopulation(): return the quantity of pixels represented by this swatch.
  • getTitleTextColor(): returns the title color in RGB value. A color in contrast with the Swatch color, safe to use on top of swatch as title text color.
  • getBodyTextColor(): Returns an appropriate color to use for any 'body' text which is displayed over this Swatch color. This color is guaranteed to have sufficient contrast.

The sample project

    Now, I provide an example project about using this library on Android UI. Firstly, declaring a main activity layout simple like this:
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:orientation="vertical"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="info.devexchanges.androidpalette.MainActivity">

    <ImageView
        android:src="@drawable/hanoi_capital"
        android:layout_width="match_parent"
        android:layout_height="300dp"
        android:scaleType="fitXY"
        android:text="Hello World!" />

    <ListView
        android:layout_marginTop="@dimen/activity_horizontal_margin"
        android:id="@+id/list_color"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
</LinearLayout>
    And it's Java code:
MainActivity.java
package info.devexchanges.androidpalette;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.graphics.Palette;
import android.widget.ListView;

public class MainActivity extends AppCompatActivity {

    private ListView listView;
    private SwatchesAdapter swatchesAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);
        listView = (ListView) findViewById(R.id.list_color);

        swatchesAdapter = new SwatchesAdapter(this);
        listView.setAdapter(swatchesAdapter);

        //get bitmap from drawable resource
        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.hanoi_capital);

        //generating Palette from this bitmap
        Palette.from(bitmap).generate(new Palette.PaletteAsyncListener() {

            @Override
            public void onGenerated(Palette palette) {
                for (Palette.Swatch swatch : palette.getSwatches()) {
                    swatchesAdapter.add(swatch);
                }
                swatchesAdapter.sortSwatches();
                swatchesAdapter.notifyDataSetChanged();
            }
        });
    }
}
    As you can see, I display the Swatches collection into a ListView, so this is it's adapter:
SwatchesAdapter.java
package info.devexchanges.androidpalette;

import android.content.Context;
import android.support.v7.graphics.Palette;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;

import java.util.Comparator;

public class SwatchesAdapter extends ArrayAdapter {

    public SwatchesAdapter(Context context) {
        super(context, 0);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder;
        if (convertView == null) {
            holder = new ViewHolder();
            convertView = LayoutInflater.from(getContext()).inflate(R.layout.color_item, parent, false);
            holder.view = (TextView) convertView.findViewById(R.id.view);
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }

        holder.view.setBackgroundColor(getItem(position).getRgb());
        holder.view.setTextColor(getItem(position).getBodyTextColor());
        holder.view.setText(String.format("Population: %d", getItem(position).getPopulation()));

        return convertView;
    }

    public void sortSwatches() {
        sort(new Comparator() {
            @Override
            public int compare(Palette.Swatch lhs, Palette.Swatch rhs) {
                return rhs.getPopulation() - lhs.getPopulation();
            }
        });
    }

    public class ViewHolder {
        TextView view;
    }
}
    Running this activity, we have this output:

Conclusions

    Through this post, you have learned one more widget in Material design technology, which can help us extracting swatches of color from a bitmap. This will allow you to customize your user interface elements, such as backgrounds and text, so that they compliment images within your application. To deep understanding about this API, you can read the official document from Google to learn more! Thanks for reading!

Share


Previous post
« Prev Post
Next post
Next Post »