使用Palette类提取图片的颜色信息

原文:http://qichaochen.github.io/2014/11/16/105-Android-5.0-Palette-01/ 

在Material Design设计中很重要的一部分内容是应用中图片颜色和文字颜色需要和主题相匹配,比如下面在这个应用:

文本的颜色根据不同图片动态进行对应适配(也许你会说,如果全部用白色文本多省事,何必这么麻烦呢?额…可以脑补一下高富帅和矮矬穷的区别)

那么在应用程序中如何提取图片的颜色信息呢?可以提取多少种颜色信息呢? 在最新的Support Library v21提供了Palette类可以很方便的实现这个需求。

下面看一下提取图片颜色信息的步骤和注意事项:

1.首先需要添加Palette的依赖

在build.gralde的dependencies添加appcomat v7和palette-v7依赖

dependencies {
    //...其他依赖
    compile 'com.android.support:appcompat-v7:21.0.0'
    compile 'com.android.support:palette-v7:21.+'
}

添加完成后需要同步一下Gradle,同步成功后就可以使用Palette类了。

2.创建Palette对象

官方提供了四种根据Bitmap对象来创建Palette对象的方法,具体分别如下:

两种同步方法:

// 最好在加载图片线程中使用
// 默认调色板大小(16).
Palette p = Palette.generate(bitmap);
//设置调色板大小(24)
Palette p = Palette.generate(bitmap, 24);

两种异步方法:

// 简单快速的实现方法,内部使用AsyncTask
// 但是可能不是最优的方法(因为有线程的切换)
// 默认调色板大小(16).
Palette.generateAsync(bitmap, new Palette.PaletteAsyncListener() {
    @Override
    public void onGenerated(Palette palette) {
        // palette为生成的调色板
    }
});
// 设置调色板大小(24)
Palette.generateAsync(bitmap, 24, new Palette.PaletteAsyncListener() {
    @Override
    public void onGenerated(Palette palette) {
        // palette为生成的调色板
    }
});

调色板的大小值越大,生成的调色板的时间越长,数值越小,得到的颜色信息也越少,调色板的大小最好根据图片类型来决定,比如:

  • 联系人头像:最优值24~32

  • 风景图:8-16

当然默认是16,大多数情况下都可以取得很好的效果。

3.使用Palette对象

生成了Palette对象后就可以尝试获取六种不同的色板,具体如下:

1. Palette.Swatch s1 = Palette.getVibrantSwatch(); //充满活力的色板
2. Palette.Swatch s2 = Palette.getDarkVibrantSwatch(); //充满活力的暗色类型色板
3. Palette.Swatch s3 = Palette.getLightVibrantSwatch(); //充满活力的亮色类型色板
4. Palette.Swatch s4 = Palette.getMutedSwatch(); //黯淡的色板
5. Palette.Swatch s5 = Palette.getDarkMutedSwatch(); //黯淡的暗色类型色板(翻译过来没有原汁原味的赶脚啊!)
6. Palette.Swatch s6 = Palette.getLightMutedSwatch(); //黯淡的亮色类型色板

可以根据需求自由选择色板类型(充满活力和或充满活力暗色类型色板应该是大部分开发经常使用的),有了色板就可以根据色板来获取具体颜色信息,在Swatch色板中提供了五种颜色信息,分别如下:

1. getPopulation(): the number of pixels represented by this swatch
2. getRgb(): the RGB value of this color.
3. getHsl(): the HSL value of this color.
4. getBodyTextColor(): the RGB value of a text color which can be displayed on top of this color.
5. getTitleTextColor(): the RGB value of a text color which can be displayed on top of this color.

示例代码如下:

Palette.Swatch swatch = palette.getVibrantSwatch();
TextView titleView = ...;
if (swatch != null) {
    titleView.setBackgroundColor(swatch.getRgb());
    titleView.setTextColor(swatch.getTitleTextColor()); //设置文本颜色

请注意必须对swatch进行是否为null判断,因为如果面板无法找到相匹配的标准色,那么然后将返回null,不进行判断将会出现空指针异常。

最后附上三个测试效果图和完整代码。

完整代码:

package io.github.qichaochen.android50;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.graphics.Palette;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.ImageView;
public class MainActivity extends ActionBarActivity {
    private ImageView image, iv1, iv2, iv3, iv4, iv5, iv6;
    private Palette palette;
    private Palette.Swatch s1,s2,s3,s4,s5,s6;
    private int index = 0;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        iv1 = (ImageView) findViewById(R.id.iv1);
        iv2 = (ImageView) findViewById(R.id.iv2);
        iv3 = (ImageView) findViewById(R.id.iv3);
        iv4 = (ImageView) findViewById(R.id.iv4);
        iv5 = (ImageView) findViewById(R.id.iv5);
        iv6 = (ImageView) findViewById(R.id.iv6);
        image = (ImageView) findViewById(R.id.image);
        GetPalette(R.drawable.a11);
    }
    private void GetPalette(int imageId) {
        image.setImageResource(imageId);
        //使用默认的调色板大小(16)
        Palette.generateAsync(BitmapFactory.decodeResource(getResources(), imageId), new Palette.PaletteAsyncListener() {
            @Override
            public void onGenerated(Palette palette) {
                s1 = palette.getVibrantSwatch();
                s2 = palette.getDarkVibrantSwatch();
                s3 = palette.getLightVibrantSwatch();
                s4 = palette.getMutedSwatch();
                s5 = palette.getDarkMutedSwatch();
                s6 = palette.getLightMutedSwatch();
                if (s1 != null) {
                    iv1.setBackgroundColor(s1.getRgb());
                    s1.getPopulation();
                }
                if (s2 != null) {
                    iv2.setBackgroundColor(s2.getRgb());
                }
                if (s3 != null) {
                    iv3.setBackgroundColor(s3.getRgb());
                }
                if (s4 != null) {
                    iv4.setBackgroundColor(s4.getRgb());
                }
                if (s5 != null) {
                    iv5.setBackgroundColor(s5.getRgb());
                }
                if (s6 != null) {
                    iv6.setBackgroundColor(s6.getRgb());
                }
            }
        });
    }
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu_main,menu);
        return true;
    }
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if (item.getItemId() == R.id.action_settings){
            index++;
            if (index%3 == 0){
                GetPalette(R.drawable.a11);
            } else if (index % 3 == 1){
                GetPalette(R.drawable.a12);
            } else if (index % 3 == 2){
                GetPalette(R.drawable.a13);
            }
        }
        return true;
    }
}

参考: