Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ImageView ColorFilter on non tranparent pixels. Clip

I have an ImageView with bitmap in it. This bitmap has alpha channel and transparent pixels. When i try to use ColorFiter with Mode.OVERLAY (since honeycomb) - provided color overlay the whole imageview (whole rect), but i want only to overlay non transparent pixels. How can i clip the imageview's canvas to perform filter where i want ?

UPDATED

I have grey image in png:

enter image description here

When i try to use MODE_ATOP i get:

enter image description here

When i use OVERLAY i get:

enter image description here

And what i want to get:

enter image description here

like image 378
dilix Avatar asked Oct 27 '25 03:10

dilix


2 Answers

There's probably a more efficient way to do this (maybe by creating a ColorMatrixColorFilter to approximate it), but since Mode.OVERLAY appear to be hard to simplify otherwise, here's some sample code that should implement what you want:

public class MyActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        final ImageView imageView = new ImageView(this);
        setContentView(imageView);

        final Paint paint = new Paint();
        Canvas c;

        final Bitmap src = BitmapFactory.decodeResource(getResources(),
                android.R.drawable.sym_def_app_icon);
        final int overlayColor = Color.RED;

        final Bitmap bm1 = Bitmap.createBitmap(src.getWidth(), src.getHeight(), Config.ARGB_8888);
        c = new Canvas(bm1);
        paint.setColorFilter(new PorterDuffColorFilter(overlayColor, PorterDuff.Mode.OVERLAY));
        c.drawBitmap(src, 0, 0, paint);

        final Bitmap bm2 = Bitmap.createBitmap(src.getWidth(), src.getHeight(), Config.ARGB_8888);
        c = new Canvas(bm2);
        paint.setColorFilter(new PorterDuffColorFilter(overlayColor, PorterDuff.Mode.SRC_ATOP));
        c.drawBitmap(src, 0, 0, paint);

        paint.setColorFilter(null);
        paint.setXfermode(new AvoidXfermode(overlayColor, 0, Mode.TARGET));
        c.drawBitmap(bm1, 0, 0, paint);

        imageView.setImageBitmap(bm2);
    }

}

In short, we draw the source bitmap and color using the OVERLAY mode, and then using a secondary bitmap (composited using SRC_ATOP mode), we combine it using AvoidXfermode to not draw over the transparent pixels.

Original image:

original image

Result:

result

like image 197
Joe Avatar answered Oct 29 '25 22:10

Joe


You can use the Overlay mode and then clip out the area that used to be transparent with the same bitmap using DST_ATOP xFerMode. https://developer.android.com/reference/android/graphics/PorterDuff.Mode

private fun applyFilterToImage() {

    val bitmapCopy = Bitmap.createBitmap(originalImage.width, originalImage.height, Bitmap.Config.ARGB_8888)
    val canvas = Canvas(bitmapCopy)

    val rnd = java.util.Random()
    val randomColor = Color.rgb(rnd.nextInt(256), rnd.nextInt(256), rnd.nextInt(256))

    val paint = Paint()
    val porterDuffMode = PorterDuff.Mode.OVERLAY
    paint.colorFilter = PorterDuffColorFilter(randomColor, porterDuffMode)

    val maskPaint = Paint()
    maskPaint. xfermode = PorterDuffXfermode(PorterDuff.Mode.DST_ATOP)

    canvas.drawBitmap(originalImage, 0f, 0f, paint)

    canvas.drawBitmap(originalImage, 0f, 0f, maskPaint) //clips out the background that used to be transparent.

    imageView.setImageBitmap(bitmapCopy)
}

MarkerColorChangeGIF

like image 21
jameseronious Avatar answered Oct 29 '25 20:10

jameseronious



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!