Android: What is Source and Destination values in Porter Duff Mode

500 views Asked by At

I implemented a custom view. I'm drawing a bitmap using Porter Duff modes of Paint for having different effects on image in another view. My code flow is in below:

Layout:
<ImageView>
</ImageView>
<CustomView>
Constraint with the image view so that it lies on top in view group.
</CustomView>

Custom View:

onDraw(canvas)
{
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(bitmap, 0, 0, paint);
}

Now my question is, according to the documentation of PorterDuff, it mainly blends two images. I understand the source value is the bitmap that I'm drawing but I want to know which is the destination here? When I use DST mode, nothing is drawn in the custom view. Is the image in ImageView destination here? But how? These are two different views. How do these views communicate each other?

1

There are 1 answers

1
HFZ On

As you Already said, Views are separated and could not be blended with each others. But you could stack any number of bitmaps or drawables and draw the result on some view's canvas.

Destination is what is already drawn on canvas. You should not create additional CustomImageView inside an ImageView. Instead, extend ImageView class and just override the onDraw function.

Note that inside overrided onDraw you should first call super.onDraw(canvas); at the first line. By doing that, you first draw what image you define for the imageview (e.i. inside xml using app:srcCompat="..."). Now this image become your destination and you could blend it afterward.

The following code create an imageview that crop a circle in image:

First draw the the image and then DST_IN the circle.

DST_IN: Draw destination only where SRC is not transparent.

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.util.AttributeSet;

import androidx.appcompat.widget.AppCompatImageView;


public class CircleImageView extends AppCompatImageView {

    Paint paint;
    public CircleImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        setLayerType(View.LAYER_TYPE_HARDWARE,null);
        paint=new Paint();
        paint.setColor(Color.WHITE);
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
    }


    protected void onDraw(Canvas canvas){
        super.onDraw(canvas);
        canvas.drawCircle(getWidth()*0.5f,getHeight()*0.5f,getHeight()*0.25f,paint);
    }

}

EDIT:

If you draw directly on canvas add this line: setLayerType(View.LAYER_TYPE_HARDWARE,null); in the constructor of your custom view.