2

I'm drawing a globe by rendering Paths. The edge of the globe is very sharp and I'd like to soften the edge to make it more visually appealing.

For performance, I'm not doing hidden line removal. I'm just calculating whether each point on the Path is visible (the side of the globe the user is viewing) and drawing the Path out to the nearest corner. To hide this, I draw a Bitmap over the entire view then punch a hole through to see the globe.

To soften the edge, I'm trying to create a ring with a radial gradient transparency. This method creates the mask:

 private void createMask(int width, int height, double radius) {

        if(radius==0){return;}

        if (mask != null) {
            mask.recycle();
        }

        mask = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_4444);

        // create a RadialGradient
        RadialGradient gradient = new android.graphics.RadialGradient(
                kHorizontalOffset, kVerticalOffset,
                30f, 0x00FF0000, 0xFFFF0000,
                android.graphics.Shader.TileMode.CLAMP);


        // TODO move to init()
        Paint p = new Paint();
        p.setShader(gradient);
        //p.setColor(0xFF000000);
        p.setColor(0xFFFF0000);
        p.setStrokeWidth(20f);
        p.setStrokeCap(Paint.Cap.ROUND);
        p.setStyle(Paint.Style.STROKE);
        p.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OVER));

        Canvas maskCanvas = new Canvas(mask);
        maskCanvas.drawColor(Color.BLACK);

        final RectF rect = new RectF();
        rect.set((float)(kHorizontalOffset - radius + 50), (float)(kVerticalOffset - radius + 50),
                (float)(kHorizontalOffset + radius - 50), (float)(kVerticalOffset + radius - 50));

        // draw transparent circle using the maskPaint
        maskCanvas.drawCircle(kHorizontalOffset, this.getHeight() - kVerticalOffset, (float) radius, maskPaint);

        // draw the radial gradient ring
        maskCanvas.drawArc(rect, -90, 360, false, p);

    }

My problem is that no matter what PortDuff.Mode I use, I always get a solid ring (or no ring) as in this example, where the ring is offset from the edge and coloured red so that I can see what's going on.

enter image description here

Any ideas on how to make this work?

Simon
  • 14,407
  • 8
  • 46
  • 61

2 Answers2

1

I think the problem is how you set your color.

The color components are (alpha,R,G,B), each one is from 0 to 255 so when you write 0xFFFF0000. the alpha value set the amount of transparency. so when you set the alpha to be FF, it means that is fully opaque while 00 is fully transparent. so try to change the alpha value.. maybe something like 0x70FF0000

Elior
  • 3,178
  • 6
  • 37
  • 67
  • Thanks for your answer, but I know how alpha works. I need a radial transparency to get a faded look around the edge. – Simon Apr 21 '13 at 17:28
  • @Simon maybe this will help http://stackoverflow.com/questions/8481322/create-a-radial-gradient-programmatically – Elior Apr 21 '13 at 19:27
  • Well, I found an answer using a different approach, but I appreciate you've spent time on this. +1. Thanks. – Simon Apr 21 '13 at 19:37
1

I found a better solution, and ended up with a smaller, faster method which does exactly what I want. What's not to like?

private void createMask(int width, int height, double radius) {

    if(radius==0){return;}

    if (mask != null) {
        mask.recycle();
    }

    mask = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_4444);

    Canvas maskCanvas = new Canvas(mask);
    maskCanvas.drawColor(Color.BLACK);

    maskPaint.setMaskFilter(new BlurMaskFilter(30, BlurMaskFilter.Blur.INNER));
    maskCanvas.drawCircle(kHorizontalOffset, this.getHeight() - kVerticalOffset, (float) radius, maskPaint);

}

The key to this is the BlurMaskFilter applied to the paint to blur the inside of whatever region it is used to paint, in this case the circle. It has just the subtle effect I was looking for:

enter image description here

Simon
  • 14,407
  • 8
  • 46
  • 61