Android PorterDuff not working as expected
Asked Answered
W

1

8

I am trying to use Android's PorterDuff to draw a shadow that will only appear where there is something below it (not where the background image is transparent) and I am having great difficulty getting it to work. I have written the following code to test the various PorterDuff.Modes and they do not seem to be working as described here:

https://developer.android.com/reference/android/graphics/PorterDuff.Mode.html

From that page, I would say the effect I'm looking for is SRC_ATOP.

Here is the code I am using, and below it an image of the result:

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.support.v4.content.ContextCompat;
import android.view.View;

public class PorterDuffTest extends View {
    private int mTexWidth;
    private int mTexHeight;
    private Bitmap dstBmp;

    PorterDuffTest(Context c) {
        super(c);

        dstBmp = BitmapFactory.decodeResource(c.getResources(), R.drawable.src);
        mTexWidth = dstBmp.getWidth();
        mTexHeight = dstBmp.getHeight();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //canvas.drawRGB(255, 255, 255);

        canvas.save();
        canvas.translate(40.0f, 40.0f);

            //COLUMN 1
        drawBlendedBitmap(canvas, PorterDuff.Mode.DARKEN);
        drawBlendedBitmap(canvas, PorterDuff.Mode.LIGHTEN);
        drawBlendedBitmap(canvas, PorterDuff.Mode.OVERLAY);
        drawBlendedBitmap(canvas, PorterDuff.Mode.ADD);

        canvas.restore();

        canvas.save();
        canvas.translate(40.0f + mTexWidth + 40.0f, 40.0f);

            //COLUMN 2
        drawBlendedBitmap(canvas, PorterDuff.Mode.CLEAR);
        drawBlendedBitmap(canvas, PorterDuff.Mode.MULTIPLY);
        drawBlendedBitmap(canvas, PorterDuff.Mode.SCREEN);
        drawBlendedBitmap(canvas, PorterDuff.Mode.XOR);
        drawBlendedBitmap(canvas, PorterDuff.Mode.OVERLAY);

        canvas.restore();

        canvas.save();
        canvas.translate(40.0f + mTexWidth + 40.0f + mTexWidth + 40.0f, 40.0f);

            //COLUMN 3
        drawBlendedBitmap(canvas, PorterDuff.Mode.SRC);
        drawBlendedBitmap(canvas, PorterDuff.Mode.SRC_OUT);
        drawBlendedBitmap(canvas, PorterDuff.Mode.SRC_IN);
        drawBlendedBitmap(canvas, PorterDuff.Mode.SRC_ATOP);
        drawBlendedBitmap(canvas, PorterDuff.Mode.SRC_OVER);
        canvas.restore();

        canvas.save();
        canvas.translate(40.0f + mTexWidth + 40.0f + mTexWidth + 40.0f + mTexWidth + 40.0f, 40.0f);

            //COLUMN 4
        drawBlendedBitmap(canvas, PorterDuff.Mode.DST);
        drawBlendedBitmap(canvas, PorterDuff.Mode.DST_IN);
        drawBlendedBitmap(canvas, PorterDuff.Mode.DST_OUT);
        drawBlendedBitmap(canvas, PorterDuff.Mode.DST_ATOP);
        drawBlendedBitmap(canvas, PorterDuff.Mode.DST_OVER);

        canvas.restore();
    }

    private void drawBlendedBitmap(Canvas canvas, PorterDuff.Mode mode) {
        Paint paint = new Paint();
        canvas.drawBitmap(dstBmp, 0.0f, 0.0f, paint);

        paint.setXfermode(new PorterDuffXfermode(mode));
        paint.setColor(ContextCompat.getColor(getContext(), R.color.tileBlue));
        canvas.drawRect(15, 15, 135, 135, paint);

        canvas.translate(0.0f, 40.0f + mTexHeight);
    }
}

PorterDuff result

I have been playing with this for a number of hours now and I'm really struggling to make any progress, so any help would be greatly appreciated. Thank you in advance!

Whatley answered 13/7, 2017 at 11:35 Comment(2)
As an option: the position and size of the figure and the square do not match. They must be exactly aligned with each other and match in size.Hurling
Also : // необходимо для корректной работы if (android.os.Build.VERSION.SDK_INT >= 11) { setLayerType(View.LAYER_TYPE_SOFTWARE, null); }Hurling
R
0

Some Porter Duff modes are not compatible with the hardware accelerated drawing process of the modern Android

You can still use them if you disable the hardware acceleration before drawing on your Canvas

override fun onDraw(canvas: Canvas) {
    super.onDraw(canvas)
    setLayerType(LAYER_TYPE_SOFTWARE, null)
    // Your custom drawing here
}

And in most cases it works pretty fast

Rhizobium answered 21/8, 2022 at 12:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.