5

I have a dynamically generated bitmap in Android that I would like to feather from the top edge such that the border area would be fully transparent at the top and gradually change to fully opaque slightly below.

Create an evenly fully-transparent top edge

transparentPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
transparentPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT));
Shader shader = new LinearGradient(0, 0, 0, 20,
                    Color.TRANSPARENT, Color.TRANSPARENT, Shader.TileMode.CLAMP);
transparentPaint.setShader(shader);
// the bitmap is dynamically generated beforehand
Canvas c = new Canvas(bitmap);
c.drawRect(0, 0, bitmapWidth, 20, transparentPaint);

Alpha gradient instead of fully-transparent hole?

How would you achieve something like this:

enter image description here

[ Just the top edge in this case ]

Cel
  • 6,467
  • 8
  • 75
  • 110
  • Just noticed that your linear gradient is entirely transparent, it uses the same colors for start and end – Lumis Jan 05 '13 at 14:43
  • @Lumis yep, thats exactly the problem, i can create an entirely transparent edge with the code provided, but not an alpha gradient as shown in the image - how to do that? – Cel Jan 05 '13 at 17:42
  • you have to use any color on the top, like Color.BLACK then try various xFermodes – Lumis Jan 05 '13 at 18:36

3 Answers3

9

Have a look at this example: Make certain area of bitmap transparent on touch

Here is a way to do it with a gradient paint:

Paint framePaint = new Paint();
for(int i = 1; i < 5; i++){
   setFramePaint(framePaint, i, imageW, imageH);
   myCanvas.drawPaint(framePaint);
}

...

private void setFramePaint(Paint p, int side, float iw, float ih){
                // paint, side of rect, image width, image height

                p.setShader(null);
                p.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));

                float borderSize = 0.1f; //relative size of border
                //use the smaller image size to calculate the actual border size
                float bSize = (iw > ih)? ih * borderSize: ih * borderSize; 
                float g1x = 0;
                float g1y = 0;
                float g2x = 0;
                float g2y = 0;
                int c1 = 0, c2 = 0;

                if (side == 1){
                    //left
                    g1x = 0;
                    g1y = ih/2;
                    g2x = bSize;
                    g2y = ih/2;
                    c1 = Color.TRANSPARENT;
                    c2 = Color.BLACK;

                }else if(side == 2){
                    //top
                    g1x = iw/2;
                    g1y = 0;
                    g2x = iw/2;
                    g2y = bSize;
                    c1 = Color.TRANSPARENT;
                    c2 = Color.BLACK;


                }else if(side == 3){
                    //right
                    g1x = iw;
                    g1y = ih/2;
                    g2x = iw - bSize;
                    g2y = ih/2;
                    c1 = Color.TRANSPARENT;
                    c2 = Color.BLACK;


                }else if(side == 4){
                    //bottom
                    g1x = iw/2;
                    g1y = ih;
                    g2x = iw/2;
                    g2y = ih - bSize;
                    c1 = Color.TRANSPARENT;
                    c2 = Color.BLACK;
                }

                p.setShader(new LinearGradient(g1x, g1y, g2x, g2y, c1, c2, Shader.TileMode.CLAMP));

            }
Community
  • 1
  • 1
Lumis
  • 21,517
  • 8
  • 63
  • 67
  • Will this produce an alpha gradient? Rather than a fully transparent edge which i already have? – Cel Jan 05 '13 at 17:43
  • 1
    The idea here is that you can create a black blured rounded rectangle, slightly smaller that image selection, which then using xFermode will create transparent edges. The problem with your solution is that the corners will be processed two times, and will not be rounded. The blured rectange is a mask, if you are happy with the shape of the mask then the final result should look good. I have created some masks in FireWorks or PhotoShop then just resized them in my app, while other I have generated by code. – Lumis Jan 05 '13 at 18:43
  • i havent tested the code but i see what you mean now - thanks, this should work! – Cel Jan 05 '13 at 20:41
  • 1
    Actually, after hours of work, I have found that your idea with a transparent gradient is the best if you don't want to create a separate bitmap to create this effect. For example if you load the image into a bitmap and then apply this paint with DEST_IN, it works. With blured rectangles it is a bit more complicated. Check edit – Lumis Jan 12 '13 at 19:23
  • 1
    really appreciate you coming back to share your findings! woudl give more upvotes if i could! – Cel Jan 13 '13 at 12:34
  • youre having a bug... in line ```float bSize = (iw > ih)? ih * borderSize: ih * borderSize;``` i guess that should be ```float bSize = (iw > ih)? ih * borderSize: wh * borderSize;``` (```ih``` vs ```wh```) – Martin Mlostek Jan 05 '16 at 23:41
  • Works for me. Really helpful. Thanks a lot. – Saiful Islam Sajib Jun 30 '20 at 17:41
2

If you can accept white edges instead of transparent, try SCREEN mode. In PorterDuff.Mode.SCREEN mode, white pixels remain white and black pixels become invisible. Create an overlay bitmap where the edges are white fading into black in the middle and blend it with your image. This will create a bitmap with white edges fading into the photo in the middle.

Gunnar Karlsson
  • 28,350
  • 10
  • 68
  • 71
  • i would accept this as an answer but i do need fully transparent edges instead of white edges on the outside.. – Cel Jan 05 '13 at 17:33
-1

Romain Guy used a very similar fading as to what you want to achieve , only he also added rounded corners in addition to this effect

onkar
  • 4,427
  • 10
  • 52
  • 89
android developer
  • 114,585
  • 152
  • 739
  • 1,270
  • 1
    i dont see any alpha gradient in the link you provide? the question is about gradually fading out the image, not having a clear-cut crisp edge.. – Cel Jan 05 '13 at 20:38
  • 1
    have you tried the sample app and saw the original image compared to the one being shown ? i might be wrong , but it looks like the same (or similar) effect . – android developer Jan 05 '13 at 20:40
  • didnt check teh sample app as i assumed the image shown in the link would represent the app - ill have a look if lumis answer doesnt work. thanks! – Cel Jan 05 '13 at 20:44
  • yes , also try to disable the rounded corner so that the effect would be more visible ... – android developer Jan 05 '13 at 20:46