I was playing around with Bitmaps masking and occasionally found an interesting issue when trying to draw ALPHA_8
bitmap mask with PorterDuff.Mode.DST_IN
Paint. It just doesn't work, at least on Android 6.x and 5.x.
Here is my sample drawable code:
public class MaskedDrawablePorterDuffDstIn extends Drawable {
private Bitmap mPictureBitmap;
private Bitmap mMaskBitmap;
private Bitmap mBufferBitmap;
private Canvas mBufferCanvas;
private final Paint mPaintDstIn = new Paint();
public MaskedDrawablePorterDuffDstIn() {
mPaintDstIn.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
}
@Override
public void draw(Canvas canvas) {
if (mPictureBitmap == null || mMaskBitmap == null) {
return;
}
mBufferCanvas.drawBitmap(mPictureBitmap, 0, 0, null);
mBufferCanvas.drawBitmap(mMaskBitmap, 0, 0, mPaintDstIn);
canvas.drawBitmap(mBufferBitmap, 0, 0, null);
}
@Override
protected void onBoundsChange(Rect bounds) {
super.onBoundsChange(bounds);
final int width = bounds.width();
final int height = bounds.height();
if (width <= 0 || height <= 0) {
return;
}
mBufferBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
mBufferCanvas = new Canvas(mBufferBitmap);
}
...
When mMaskBitmap
has ARGB_8888
config it works just fine. But when I use ALPHA_8
it doesn't. The picture is not masked at all in that case.
Here is how I load resources in the Activity:
private void loadImages() {
mPictureBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.picture);
mMaskBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.mask_circle).extractAlpha();
}
Please note the .extractAlpha()
which is giving me the ALPHA_8
bitmap.
Here is how I use the Drawable:
public void setDrawablePDDstIn(View view) {
MaskedDrawablePorterDuffDstIn maskedDrawable = new MaskedDrawablePorterDuffDstIn();
maskedDrawable.setPictureBitmap(mPictureBitmap);
maskedDrawable.setMaskBitmap(mMaskBitmap);
mImageView.setImageDrawable(maskedDrawable);
}
What is even more interesting, when I try an alternative approach, drawing the mask first and then drawing the picture with SRC_IN
Paint - it works fine again, even with ALPHA_8
mask:
public class MaskedDrawablePorterDuffSrcIn extends Drawable {
private Bitmap mPictureBitmap;
private Bitmap mMaskBitmap;
private Bitmap mBufferBitmap;
private Canvas mBufferCanvas;
private final Paint mPaintSrcIn = new Paint();
public MaskedDrawablePorterDuffSrcIn() {
mPaintSrcIn.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
}
@Override
public void draw(Canvas canvas) {
if (mPictureBitmap == null || mMaskBitmap == null) {
return;
}
mBufferCanvas.drawBitmap(mMaskBitmap, 0, 0, null);
mBufferCanvas.drawBitmap(mPictureBitmap, 0, 0, mPaintSrcIn);
//dump the buffer
canvas.drawBitmap(mBufferBitmap, 0, 0, null);
}
...
Here is a link to the whole project I experimented with at GitHub. It contains both non-working and working solution, feel free to play with.
Anyone has an idea why combination of DST_IN
and ALPHA_8
doesn't work as expected?