Home » Android » Android – Is it possible to declare an alpha mask directly within layer-list XML definition?

Android – Is it possible to declare an alpha mask directly within layer-list XML definition?

Posted by: admin April 23, 2020 Leave a comment

Questions:

A newbie question

I have this layers.xml that I use as a source for an ImageView.
And two images, mask.png and image.jpg

layers.xml:

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <bitmap  android:src="@drawable/image" android:gravity="center"/>
    </item>
    <item>
        <bitmap  android:src="@drawable/mask" android:gravity="center"/>
    </item>
</layer-list>

ImageView:

<ImageView
 android:id="@+id/img_B"
 android:layout_width="fill_parent"
 android:layout_height="fill_parent"
 android:src="@drawable/layers"/>

At the moment the output is just the png over the image.
I would like the png to act as a mask, clipping the image using the png alpha channel like so:
enter image description here

Is that possible directly within the xml, or do I have to do it by code?

Thanks for your advice 😉

update:
at the moment I achieved my goal using code to replace the entire ImageView

ImageView img = (ImageView) findViewById(imgID);

Canvas canvas = new Canvas();
Bitmap mainImage = BitmapFactory.decodeResource(getResources(), R.drawable.img);
Bitmap mask = BitmapFactory.decodeResource(getResources(), R.drawable.mask);
Bitmap result = Bitmap.createBitmap(mainImage.getWidth(), mainImage.getHeight(), Bitmap.Config.ARGB_8888);

canvas.setBitmap(result);
Paint paint = new Paint();
paint.setFilterBitmap(false);

canvas.drawBitmap(mainImage, 0, 0, paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
canvas.drawBitmap(mask, 0, 0, paint);
paint.setXfermode(null);

img.setImageBitmap(result);
img.invalidate();
How to&Answers:

Put your mask image in the folder drawable-nodpi.

Otherwise, the scaling will be wrong.

Here’s some example code from an app. After the camera it adds a mask.

public void onActivityResult(int requestCode, int resultCode, Intent data)
  {
  if (requestCode == REQUEST_IMAGE_CAPTURE) // && resultCode == RESULT_OK )
    {

    try
      {
      Bitmap cameraBmp = MediaStore.Images.Media.getBitmap(
          State.mainActivity.getContentResolver(),
          Uri.fromFile(Utils.tempFileForAnImage())
                                );

      cameraBmp = ThumbnailUtils.extractThumbnail(cameraBmp, 256, 256);

      Matrix m = new Matrix();
      m.postRotate(Utils.neededRotation(Utils.tempFileForAnImage()));
      // NOTE incredibly useful trick for cropping/resizing square
      // http://stackoverflow.com/a/17733530/294884

      cameraBmp = Bitmap.createBitmap(cameraBmp,
          0, 0, cameraBmp.getWidth(), cameraBmp.getHeight(),
          m, true);


      // so, cameraBmp is now a Bitmap.  Let's add the mask!!
      // see Shiomi Schwartz's original!! http://stackoverflow.com/questions/8630365

      Bitmap mask = BitmapFactory.decodeResource(
            getResources(),
            R.drawable.mask_android_256);
      // NOTE THE MASK ** MUST ** BE IN YOUR nodpi folder

      Bitmap result = Bitmap.createBitmap( 256,256, Bitmap.Config.ARGB_8888);

      Canvas cc = new Canvas();
      cc.setBitmap(result);

      Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
      paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));

      cc.drawBitmap(cameraBmp, 0, 0, null);
      cc.drawBitmap(mask, 0,0, paint);

      // so, cameraBmp is now a Bitmap but it has been masked



      yourImageViewForTheUser.setImageBitmap(result);

      // make a "baos" ... we want PNG in this case ..
      ByteArrayOutputStream baos = new ByteArrayOutputStream();
      result.compress(Bitmap.CompressFormat.PNG, 0, baos);

      imageBytesRESULT = baos.toByteArray();
      // typically you want the result as image bytes, example to send to Parse

      } catch (FileNotFoundException e)
      {
      e.printStackTrace();
      } catch (IOException e)
      {
      e.printStackTrace();
      }

    return;
    }

  }

Answer:

.png files can have a alpha channel included when you create them and Android can use that to isolate the image as you explain.

Create an extra channel in GIMP or Photoshop or whatever image editor you use. This will be a monochrome channel (256 shades of white to black). Make a selection of the section you want to mask OUT click on the alpha channel and fill the selection area with black. Invert the selection, still in the alpha channel, and fill it with white. Save and export .png file as 24 bit with alpha (effectively 32 bit). Your file should render correctly.