Android Mask bitmap on canvas gen a black space

Here is a solution which helped me to implement masking:

public void draw(Canvas canvas) {
        Bitmap original = BitmapFactory.decodeResource(getContext().getResources(),R.drawable.original_image);
        Bitmap mask = BitmapFactory.decodeResource(getContext().getResources(),R.drawable.mask_image);

        //You can change original image here and draw anything you want to be masked on it.

        Bitmap result = Bitmap.createBitmap(mask.getWidth(), mask.getHeight(), Config.ARGB_8888);
        Canvas tempCanvas = new Canvas(result);
        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setXfermode(new PorterDuffXfermode(Mode.DST_IN));
        tempCanvas.drawBitmap(original, 0, 0, null);
        tempCanvas.drawBitmap(mask, 0, 0, paint);
        paint.setXfermode(null);

        //Draw result after performing masking
        canvas.drawBitmap(result, 0, 0, new Paint());
}

The mask should be a white image with transparency.
It will work like this:
original image + mask = result image


Same answer as @Sergey Pekar give but I have updated it in Kotlin.

enter image description here

fun ImageView.getMaskBitmap(imageUrl: String? = null, mContent: Int, mMaskedImage : Int) {
    runOnBackground {
        // if you have https image url then use below line
        //val original: Bitmap = BitmapFactory.decodeStream(URL(imageUrl).openConnection().getInputStream())

        // if you have png or jpg image then use below line
        val original: Bitmap = BitmapFactory.decodeResource(resources, mContent)

        val mask = BitmapFactory.decodeResource(resources, mMaskedImage) // mMaskedImage Your masking image
        val result: Bitmap = Bitmap.createBitmap(mask.width, mask.height, Bitmap.Config.ARGB_8888, true)
        val tempCanvas = Canvas(result)
        val paint = Paint(Paint.ANTI_ALIAS_FLAG)
        paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.DST_IN)
        tempCanvas.apply {
            drawBitmap(original, 0f, 0f, null)
            drawBitmap(mask, 0f, 0f, paint)
        }
        paint.xfermode = null

        //Draw result after performing masking
        runOnBackground(onMainThread = {
            this.apply {
                setImageBitmap(result)
                scaleType = ImageView.ScaleType.FIT_CENTER
            }
        })
    }
}

Github Demo


I encountered the same problem in my custom view and instead of decoding the bitmap from a resource, I had created the original bitmap and the masking bitmap from the scratch via canvas.draw*() methods (since both the original and mask are basic shapes). I was getting the blank opaque space instead of a transparent one. I fixed it by setting a hardware layer to my view.

View.setLayerType(LAYER_TYPE_HARDWARE, paint);

More info on why this is to be done here: https://stackoverflow.com/a/33483016/4747587