资讯专栏INFORMATION COLUMN

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

huayeluoliuhen / 2298人阅读

摘要:自然界中各个不同的色相是无限丰富的,如紫红银灰橙黄等。色相即各类色彩的相貌称谓。灰度灰度使用黑色调表示物体即用黑色为基准色,不同的饱和度的黑色来显示图像。饱和度饱和度可定义为彩度除以明度,与彩度同样表征彩色偏离同亮度灰色的程度。

前言

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

色彩科普

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

色相

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

色调

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

灰度

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

对比度

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

饱和度

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

主角ColorMatrix

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


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

美图滤镜效果

原图

|1,0,0,0,0|
|0,1,0,0,0|
|0,0,1,0,0|
|0,0,0,1,0|

泛黄矩阵

|1,0,0,0,100|
|0,1,0,0,100|
|0,0,1,0,0|
|0,0,0,1,0|

偏红矩阵

|2,0,0,0,0|
|0,1,0,0,0|
|0,0,1,0,0|
|0,0,0,1,0|

底片矩阵

|-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 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{

        @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另外几个方法

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

演示代码

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);
    }

效果展示

xsoftlab.net/reference/android/graphics/ColorMatrixColorFilter.html

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/13308.html

相关文章

  • Android定义View点事(一)基础

    摘要:所以对于开发者来说自定义可以实现多种多样的需求效果。那这次我们就来说说关于自定义的实现。通过获取的画布,使用在上绘制内容。 前言 在Android开发中经常会遇到特殊的需求要求开发者实现独特的视图UI。所以对于开发者来说自定义View可以实现多种多样的需求效果。那这次我们就来说说关于自定义View的实现。 View绘制原理 View的绘制是在方法onDraw中实现的。通过获取View的...

    gplane 评论0 收藏0
  • Android定义View点事(二)Xfermode

    摘要:在图层绘制结束之后再使用恢复保存的原图层内容。绘制圆形图片绘制微信聊天图片主程序实例化并加载图片资源实例化圆形并加载图片资源实例化聊天并加载图片资源最后的效果呈现写在最后这节主要学习模式并通过几个简单例子实践了一下。 回顾 上一节我们学会了使用Canvas和Paint实现自定义View的绘制,我们已经知道如何简单实现自定义View的方法。这一节我们主要来说说Paint的setXferm...

    seanHai 评论0 收藏0
  • Android8.0适配点事(一)

    最近有小伙伴说,7.0适配整了一波,现在又要来适配8.0,真是一波未平一波又起   但是作为开发者来说,学无止境,不跟上时代的步伐,肯定会被时代所淘汰...   话说Android P已经在路上了,你准备好了吗?      适配属性    1、通知渠道(Channeld) 当然,适配8.0的第一步自然是把targeSdk升级到26,在8.0中所有通知的实现都需要提供通知渠道,否则,所有通知在8.0...

    TZLLOG 评论0 收藏0
  • Android攻略

    摘要:但是,还有一需求点击断句我们需要判断用户的点击,定位到所点击的整句话,然后再将整句内容带来了哪些新东西今年的上谷歌发布了新版本的,但是我们并没有从中得到多少信息,只有一篇非常简陋的博客。 Android自定义View播放Gif动画 GIF是一种很常见的动态图片格式,在Android中它的使用场景非常多,大到启动页动画、小到一个Loading展示,都可以用GIF动画来完成,使用也很方便,...

    zhisheng 评论0 收藏0
  • 移动端开发:架构点事

    摘要:移动精英开发社群的第期,也是围绕架构这个话题进行讨论。本次我们希望结合实际开发中遇到的问题,来聊聊移动端的架构设计。这样的模式改进一些,可能会更适合移动端架构。潘卫杰之前我们公司移动端的大项目就是插座式开发的,批量出各个行业的。 此前,58 同城的技术委员会执行主席沈剑在 OneAPM 的技术公开课上分享过一个主题,「好的架构不是设计出来的,而是演技出来的」。因为对很多创业公司而言,随...

    KnewOne 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<