关于图片的混合模式

ComposeShader、BitmapShader
用法参考网址:https://blog.csdn.net/iispring/article/details/50500106
先来看一张图,这个是从APIDemo中粘贴的代码运行出来的,路径:

/Users/huozhenpeng/Library/Android/sdk/samples/android-23/legacy/ApiDemos/src/com/example/android/apis/graphics/Xformodes.java

关于图片的混合模式_第1张图片
image.png

这个是运用ComposeShader的demo效果,就是两张图片在不同混合模式下产生的效果,实现这个效果有两个地方需要注意

先绘制目标图像(dst),然后设置ComposeShader,再绘制原图像(src),源像素(src)在Canvas中对应位置上的像素称作目标像素

两张图片是覆盖绘制

什么意思呢?
示例中,dst是黄色圆形,src是蓝色矩形,但是dst这张图片代表的区域(大小)不只是黄色区域


关于图片的混合模式_第2张图片
image.png

dst和src是宽高相同的两张图片,只是dst在左上部分画了个黄色圆形,src在右下部分画了个蓝色矩形

看下代码:

package com.dongnao.ffmpegmusic;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.os.Build;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi;
import android.util.AttributeSet;
import android.view.View;

/**
 * 作者 huozhenpeng
 * 日期 2018/9/14
 * 邮箱 [email protected]
 */

public class PorterView extends View {
    public PorterView(Context context) {
        this(context,null);
    }

    public PorterView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs,-1);
    }

    public PorterView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private Paint paint;
    private void init()
    {
        paint=new Paint(Paint.ANTI_ALIAS_FLAG);

    }

    private int width;
    private int height;
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        width=w;
        height=h;
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawColor(Color.WHITE);
        canvas.saveLayer(0,0,width,height,paint);
        canvas.drawBitmap(createDstBitmap(),0,0,paint);
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
        canvas.drawBitmap(createSrcBitmap(),0,0,paint);
        paint.setXfermode(null);
        canvas.restore();
    }

    private Bitmap createDstBitmap()
    {
        Bitmap bitmap= Bitmap.createBitmap(width,height, Bitmap.Config.ARGB_8888);
        Canvas canvas=new Canvas();
        canvas.setBitmap(bitmap);
        Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
        p.setColor(0xFFFFCC44);
        canvas.drawCircle(width/4,height/4,width/4,p);
        return bitmap;
    }

    private Bitmap createSrcBitmap()
    {
        Bitmap bitmap= Bitmap.createBitmap(width,height, Bitmap.Config.ARGB_8888);
        Canvas canvas=new Canvas();
        canvas.setBitmap(bitmap);
        Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);

        p.setColor(0xFF66AAFF);

        canvas.drawRect(width/4,height/4,width*3/4,height*3/4,p);
        return bitmap;
    }
}

显示的效果:


关于图片的混合模式_第3张图片
image.png
实现一张圆形图片

这个应用场景蛮多的,比如说app中的头像啊什么的
实现这个功能也有两种做法:
第一种用ComposeShader,第二种用BitmapShader

利用ComposeShader

原理就是,先绘制一个圆形的bitmap,设置ComposeShader为SRC_IN,再绘制一个图片(要裁剪为圆形的图片,比如头像啦)

package com.dongnao.ffmpegmusic;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ComposeShader;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.Shader;
import android.os.Build;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi;
import android.util.AttributeSet;
import android.view.View;

/**
 * 作者 huozhenpeng
 * 日期 2018/9/14
 * 邮箱 [email protected]
 */

public class PorterView2 extends View {
    public PorterView2(Context context) {
        this(context,null);
    }

    public PorterView2(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs,-1);
    }

    public PorterView2(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private Paint paint;
    private void init()
    {
        paint=new Paint(Paint.ANTI_ALIAS_FLAG);

    }

    private int width;
    private int height;
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        width=w;
        height=h;
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawColor(Color.WHITE);
        canvas.saveLayer(0,0,width,height,paint);
        canvas.drawBitmap(createDstBitmap(),0,0,paint);
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
        canvas.drawBitmap(createSrcBitmap(),0,0,paint);
        paint.setXfermode(null);
        canvas.restore();
    }

    private Bitmap createDstBitmap()
    {
        Bitmap bitmap= Bitmap.createBitmap(width,height, Bitmap.Config.ARGB_8888);
        Canvas canvas=new Canvas();
        canvas.setBitmap(bitmap);


        Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
        p.setColor(0xFFFFCC44);
        canvas.drawCircle(width/2,height/2,width/2,p);
        return bitmap;
    }

    private Bitmap createSrcBitmap()
    {
        Bitmap bitmap= Bitmap.createBitmap(width,height, Bitmap.Config.ARGB_8888);
        Canvas canvas=new Canvas();
        canvas.setBitmap(bitmap);
        Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
        Bitmap source=BitmapFactory.decodeResource(getResources(),R.mipmap.a);
        //图片有时候会太小,一般会给设置BitmapShader
        p.setShader(new BitmapShader(source, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT));
        canvas.drawRect(0,0,width,height,p);

        return bitmap;
    }

    private Bitmap createSrcBitmap2()
    {
        Bitmap bitmap= Bitmap.createBitmap(width,height, Bitmap.Config.ARGB_8888);
        Canvas canvas=new Canvas();
        canvas.setBitmap(bitmap);
        Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
        Bitmap source=BitmapFactory.decodeResource(getResources(),R.mipmap.a);

        Rect rectSrc=new Rect(0,0,source.getWidth(),source.getHeight());
        Rect rectDst=new Rect(0,0,width,height);

        canvas.drawBitmap(source,rectSrc,rectDst,p);

        return bitmap;
    }
}

注意我们一般用createSrcBitmap2(),就是为了防止实际要裁剪的图片过大或者过小。
看下效果
createSrcBitmap()


关于图片的混合模式_第4张图片
image.png

createSrcBitmap2()


关于图片的混合模式_第5张图片
image.png
利用BitmapShader

利用BitmapShader就比较简单了,原理是利用BitmapShader填充画笔,然后用画笔绘制圆形

package com.dongnao.ffmpegmusic;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.Shader;
import android.os.Build;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi;
import android.util.AttributeSet;
import android.view.View;

/**
 * 作者 huozhenpeng
 * 日期 2018/9/14
 * 邮箱 [email protected]
 */

public class PorterView3 extends View {
    public PorterView3(Context context) {
        this(context,null);
    }

    public PorterView3(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs,-1);
    }

    public PorterView3(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private Paint paint;
    private void init()
    {
        paint=new Paint(Paint.ANTI_ALIAS_FLAG);
        Bitmap source=BitmapFactory.decodeResource(getResources(),R.mipmap.a);
        paint.setShader(new BitmapShader(source, Shader.TileMode.MIRROR, Shader.TileMode.MIRROR));

    }

    private int width;
    private int height;
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        width=w;
        height=h;
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawColor(Color.WHITE);
        canvas.drawCircle(width/2,height/2,width/2,paint);
    }

}

这种情况需要src比较大时才会呈现比较好的效果,而且一般会使用bitmapShader.setLocalMatrix(shaderMatrix)对bitmapShader做变换,开源库CircleImageView就是这么做的。

你可能感兴趣的:(关于图片的混合模式)