【Android】自定义View那点事(三)ColorFilter篇

前言

前面学习Xfermode的使用,我们可以自定义各种不同样式的View,本节我们学习关于颜色处理相关的内容。现在很多图片处理软件都具有滤镜功能,选择不同风格滤镜可以改变图片色彩呈现不同风格。Android开发文档中提供了相应的API供开发者使用,这样我们自己可以实现图片滤镜效果。这节我们主要讲ColorMatrixColorFilterColorMatrixColorFilter通过ColorMatrix设置4*5的矩阵变换RGBA参数调整颜色。

色彩科普

在开始如何调整图片颜色之前,我们先了解一下关于色彩方面的知识。Ps:理论知识来源于度娘

  • 色相

色相是色彩的首要特征,是区别各种不同色彩的最准确的标准。事实上任何黑白灰以外的颜色都有色相的属性,而色相也就是由原色、间色和复色来构成的。色相,色彩可呈现出来的质地面貌。自然界中各个不同的色相是无限丰富的,如紫红、银灰、橙黄等。色相即各类色彩的相貌称谓。

  • 色调

色调指的是一幅画中画面色彩的总体倾向,是大的色彩效果。这种在不同颜色的物体上,笼罩着某一种色彩,使不同颜色的物体都带有同一色彩倾向,这样的色彩现象就是色调。

  • 灰度

灰度使用黑色调表示物体,即用黑色为基准色,不同的饱和度的黑色来显示图像。 每个灰度对象都具有从 0%(白色)到100%(黑色)的亮度值。使用黑白或灰度扫描仪生成的图像通常以灰度显示。

  • 对比度

对比度指的是一幅图像中明暗区域最亮的白和最暗的黑之间不同亮度层级的测量,差异范围越大代表对比越大,差异范围越小代表对比越小,好的对比率120:1就可容易地显示生动、丰富的色彩,当对比率高达300:1时,便可支持各阶的颜色。但对比率遭受和亮度相同的困境,现今尚无一套有效又公正的标准来衡量对比率,所以最好的辨识方式还是依靠使用者眼睛。

  • 饱和度

饱和度可定义为彩度除以明度,与彩度同样表征彩色偏离同亮度灰色的程度。注意,与彩度完全不是同一个概念。但由于其和彩度决定的是出现在人眼里的同一个效果,所以才会出现视彩度与饱和度为同一概念的情况。

主角ColorMatrix

ColorMatrix通过设置4*5的矩阵数值改变图片的颜色和透明度。我们来看看官方文档的描述。No picture,say the JJ,来上图。

Paste_Image.png

可以看到4*5矩阵每一行的运算结果分别代表RGBA的最终的数值,以及它们取值范围在0-255之间。而每一行最后一个数值代表偏移量,例如想让R增加100偏移量,则将矩阵数组第四个数值设置为100。
ColorMatrix的reset()方法可以看到,颜色矩阵RGBA的初始情况。

Paste_Image.png

美图滤镜效果

  • 原图
Paste_Image.png
|1,0,0,0,0|
|0,1,0,0,0|
|0,0,1,0,0|
|0,0,0,1,0|
  • 泛黄矩阵
Paste_Image.png
|1,0,0,0,100|
|0,1,0,0,100|
|0,0,1,0,0|
|0,0,0,1,0|
  • 偏红矩阵
Paste_Image.png
|2,0,0,0,0|
|0,1,0,0,0|
|0,0,1,0,0|
|0,0,0,1,0|
  • 底片矩阵
Paste_Image.png
|-1,0,0,0,255|
|0,-1,0,0,255|
|0,0,-1,0,255|
|0,0,0,1,0|

主要代码

开发流程简介
1.获取图片资源draweBitmap
2.canvasBitmap获取draweBitmap用于创建画布canvas的大小
3.ColorMatrix设置颜色矩阵,ColorMatrixColorFilter加载ColorMatrix,paint设置ColorMatrixColorFilter
4.canvas使用paint绘制draweBitmap
5.imageView加载canvasBitmap
主视图部分

public class ColorFilterView extends LinearLayout{

 
    ImageView imageView;
    Button btnSetting;
    Bitmap draweBitmap;
    Bitmap canvasBitmap;
    Canvas canvas;
    Paint paint;
    float[] ColorMatrixFloat = new float[20];
    ColorMatrixDialog colorMatrixDialog;
    public ColorFilterView(Context context) {
        super(context);
        initView(context);
    }
    public ColorFilterView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView(context);
    }
    private void initView(final Context context) {
        this.setOrientation(VERTICAL);

        imageView = new ImageView(context);
        BitmapFactory.Options option = new BitmapFactory.Options();
        DisplayMetrics displayMetrics = new DisplayMetrics();
        ((Activity)context).getWindow().getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
        draweBitmap = Utils.CompressImage(context, R.drawable.meizi,option,displayMetrics);
        canvasBitmap = Bitmap.createBitmap(option.outWidth,option.outHeight, Bitmap.Config.ARGB_8888);
        addView(imageView);
        
        canvas = new Canvas(canvasBitmap);
        paint = new Paint();
        canvas.drawBitmap(draweBitmap,0,0,paint);
        imageView.setImageBitmap(canvasBitmap);

        btnSetting = new Button(context);
        btnSetting.setText("MatrixSeeting");
        btnSetting.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                colorMatrixDialog = new ColorMatrixDialog(context,ColorMatrixFloat);
                colorMatrixDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
                    @Override
                    public void onDismiss(DialogInterface dialog) {
                        changeMatrix(ColorMatrixFloat);
                    }
                });
                colorMatrixDialog.show();
            }
        });
        addView(btnSetting); 
    }
    private void changeMatrix(float[]  color){

        ColorMatrix colorMatrix = new ColorMatrix();
        colorMatrix.set(color);
        ColorMatrixColorFilter colorMatrixColorFilter = new ColorMatrixColorFilter(colorMatrix);
        paint.setColorFilter(colorMatrixColorFilter);
        canvas.drawBitmap(draweBitmap,0,0,paint);
        imageView.setImageBitmap(canvasBitmap);
    }

}

设置颜色矩阵Dialog

public class ColorMatrixDialog extends Dialog {

    RecyclerView recyclerView;
    List<EditText> editTextList = new ArrayList<>();
    float[] colors;
    Button btnOk;
    public ColorMatrixDialog(Context context,float[] colors) {
        super(context);
        init(context);
        this.colors = colors;
    }

    public ColorMatrixDialog(Context context, int themeResId) {
        super(context, themeResId);
        init(context);
    }
    private void init(Context context){
        LinearLayout linearLayout = new LinearLayout(context);
        linearLayout.setOrientation(LinearLayout.VERTICAL);
        recyclerView = new RecyclerView(context);
        recyclerView.setLayoutManager(new GridLayoutManager(context,5));
        recyclerView.setAdapter(new EditextAdapter());
        linearLayout.addView(recyclerView);
        btnOk = new Button(context);
        btnOk.setText("OK");
        btnOk.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int num = 0;
                for(EditText editText : editTextList){
                    try {
                        String value = editText.getText().toString();
                        float floatValue = Float.valueOf(value);
                        colors[num] = floatValue;
                    }catch (NumberFormatException e){
                        e.printStackTrace();
                    }
                    num++;
                }
                dismiss();
            }
        });
        linearLayout.addView(btnOk);
        addContentView(linearLayout,new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
    }
    class EditextAdapter extends RecyclerView.Adapter<EditTextViewHolder>{

        @Override
        public EditTextViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            EditText editText = new EditText(parent.getContext());
            LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                    ViewGroup.LayoutParams.WRAP_CONTENT);
            layoutParams.weight = 1;
            editText.setLayoutParams(layoutParams);
            editText.setGravity(View.TEXT_ALIGNMENT_CENTER);
            editText.setInputType(InputType.TYPE_CLASS_NUMBER|InputType.TYPE_NUMBER_FLAG_DECIMAL|InputType.TYPE_NUMBER_FLAG_SIGNED);
            editTextList.add(editText);
            return new EditTextViewHolder(editText);
        }

        @Override
        public void onBindViewHolder(EditTextViewHolder holder, int position) {
            holder.editText.setText("0");
        }

        @Override
        public int getItemCount() {
            return 20;
        }
    }
    class EditTextViewHolder extends RecyclerView.ViewHolder{
        EditText editText;
        public EditTextViewHolder(View itemView) {
            super(itemView);
            editText = (EditText)itemView;
        }
    }
}

补充内容

除了使用颜色矩阵改变,在官方文档中还可以看到ColorMatrix另外几个方法

Paste_Image.png
Paste_Image.png
Paste_Image.png

这三个方法分别设置饱和度、亮度、色相。

  • 演示代码
private void changeRGBA(){
        float R = (rSeekBar.getProgress() -127) * 1.0f /127 * 180;
        float G = gSeekBar.getProgress() * 1.0f / 127;
        float B = bSeekBar.getProgress() * 1.0f / 127;

        //色相
        ColorMatrix colorMatrixRotate = new ColorMatrix();
        colorMatrixRotate.setRotate(0,R);
        colorMatrixRotate.setRotate(1,R);
        colorMatrixRotate.setRotate(2,R);
        //饱和度
        ColorMatrix colorMatrixSaturation = new ColorMatrix();
        colorMatrixSaturation.setSaturation(G);
        //亮度
        ColorMatrix colorMatrixScale = new ColorMatrix();
        colorMatrixScale.setScale(B,B,B,1);

        ColorMatrix colorMatrix = new ColorMatrix();
        colorMatrix.postConcat(colorMatrixRotate);
        colorMatrix.postConcat(colorMatrixSaturation);
        colorMatrix.postConcat(colorMatrixScale);
        ColorMatrixColorFilter colorMatrixColorFilter = new ColorMatrixColorFilter(colorMatrix);
        paint.setColorFilter(colorMatrixColorFilter);
        canvas.drawBitmap(draweBitmap,0,0,paint);
        imageView.setImageBitmap(canvasBitmap);
    }
  • 效果展示
620019632-5815ffd94819e_articlex.gif
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,905评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,140评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,791评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,483评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,476评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,516评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,905评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,560评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,778评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,557评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,635评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,338评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,925评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,898评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,142评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,818评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,347评论 2 342

推荐阅读更多精彩内容