Home » Android » Android Mask bitmap on canvas gen a black space

Android Mask bitmap on canvas gen a black space

Posted by: admin June 15, 2020 Leave a comment

Questions:

I have a mask bitmap with a half is red color and ones is transparent like this
https://www.dropbox.com/s/931ixef6myzusi0/s_2.png

I want to use mask bitmap to draw content on canvas only visible in red area, code like this:

Paint paint = new Paint();


public void draw(Canvas canvas) {
// draw content here
  ...

//and mask bitmap here
  paint.setXfermode(new PorterDuffXfermode(android.graphics.PorterDuff.Mode.DST_IN));
  canvas.drawBitmap(maskBitmap, 0, 0, paint);

}

The result as my expecting (content only visible in red area, BUT THE TRANSPARENT AREA BECOME BLACK IS PROBLEM!)

this image result :https://www.dropbox.com/s/mqj48992wllfkiq/s_2%20copy.png
Anyone help me???

How to&Answers:

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

Answer:

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

Answer:

Bitmap finalMasking = stackMaskingProcess(imageBitmap, bitmapMasking);


private Bitmap stackMaskingProcess(Bitmap _originalBitmap, Bitmap _maskingBitmap) {
        try {
            if (_originalBitmap != null)
            {
                int intWidth = _originalBitmap.getWidth();
                int intHeight = _originalBitmap.getHeight();
                resultMaskBitmap = Bitmap.createBitmap(intWidth, intHeight, Bitmap.Config.ARGB_8888);
                getMaskBitmap = Bitmap.createScaledBitmap(_maskingBitmap, intWidth, intHeight, true);
                Canvas mCanvas = new Canvas(resultMaskBitmap);
                Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
                paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
                mCanvas.drawBitmap(_originalBitmap, 0, 0, null);
                mCanvas.drawBitmap(getMaskBitmap, 0, 0, paint);
                paint.setXfermode(null);
                paint.setStyle(Paint.Style.STROKE);
            }
        } catch (OutOfMemoryError o) {
            o.printStackTrace();
        }
        return resultMaskBitmap;
    }

Answer:

I like the approach from Er. Praful Parmar’s answer but for me it did not quite work as expected. I had problems, because some scaling was going on without intention.
My Bitmaps had a different density than my device and this messed things up.

Also I wanted to reduce the creation of Objects, so I moved the Paint object to a constant for reuse.

So here is my utils method:

  public static final//
  Bitmap createWithMask(final Bitmap img, final Bitmap mask) {
    final Bitmap result = Bitmap.createBitmap(img.getWidth(), img.getHeight(),
        Bitmap.Config.ARGB_8888);
    result.setDensity(originalBitmap.getDensity()); // to avoid scaling if density of 'img' is different form the default on your device
    final Canvas canvas = new Canvas(result);
    canvas.drawBitmap(img, 0, 0, null);
    canvas.drawBitmap(mask, 0, 0, PAINT_FOR_MASK);
    return result;
  }//end-method

  private static final Paint PAINT_FOR_MASK = createPaintForMask();

  private static final//
  Paint createPaintForMask() {
    final Paint paint = new Paint();
    paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
    return paint;
  }//end-method