Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Drawing an outer shadow when drawing an image

I currently create a rounded version of an image in my app by drawing to a canvas. I would like to draw a faint outershadow around the image, but I cant quite get it right. I have 2 questions: 1. How can I draw an outer shadow (I can only seem to draw a shadow with a x or y offset) 2. How can I draw the shadow so that it does not have the artifacts shown in the attached image. Code:

![public Bitmap getRoundedCornerBitmap(Bitmap bitmap, float cornerRadius) {
        Bitmap output = Bitmap.createBitmap(bitmap.getWidth()+6, bitmap.getHeight() +6, Config.ARGB_8888);
        Canvas canvas = new Canvas(output);

        final int color = 0xff424242;
        int shadowRadius = getDipsFromPixel(3);
        final Rect imageRect = new Rect(shadowRadius, shadowRadius, bitmap.getWidth(), bitmap.getHeight());
        final RectF rectF = new RectF(imageRect);

        // This does not achieve the desired effect
        Paint shadowPaint = new Paint();
        shadowPaint.setAntiAlias(true);
        shadowPaint.setColor(Color.BLACK);
        shadowPaint.setShadowLayer((float)shadowRadius, 2.0f, 2.0f,Color.BLACK);
        canvas.drawOval(rectF, shadowPaint);

        canvas.drawARGB(0, 0, 0, 0);
        final Paint paint = new Paint();
        paint.setAntiAlias(true);
        paint.setColor(color);

        canvas.drawRoundRect(rectF, cornerRadius, cornerRadius, paint);

        paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
        canvas.drawBitmap(bitmap, imageRect, imageRect, paint);

        return output;
    }][1]

http://i.stack.imgur.com/d7DV6.png

This is an example of the effect I am trying to achieve: enter image description here

like image 512
RunLoop Avatar asked Jul 22 '13 09:07

RunLoop


People also ask

How do I add a shadow to an image in Photoshop?

Open the Layers panel by going to Window > Layers. Create two layers, one for your shadows and one for your highlights. (It doesn't matter which order you create them in.) On the “shadows” layer, you'll be drawing in black.


2 Answers

I wanted a similar effect, but on an AppWidget so unfortunately I couldn't use @EvelioTarazona's solution. This is what I came up with, it should work with a bitmap of any shape.

    final Bitmap src = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
    final Bitmap shadow = addShadow(src, src.getHeight(), src.getWidth(), Color.BLACK, 3, 1, 3);
    final ImageView iv = (ImageView)findViewById(R.id.image);
    iv.setImageBitmap(shadow);

Example with parameters size=3, dx=1, dy=3, color=BLACK

 public Bitmap addShadow(final Bitmap bm, final int dstHeight, final int dstWidth, int color, int size, float dx, float dy) {
    final Bitmap mask = Bitmap.createBitmap(dstWidth, dstHeight, Config.ALPHA_8);

    final Matrix scaleToFit = new Matrix();
    final RectF src = new RectF(0, 0, bm.getWidth(), bm.getHeight());
    final RectF dst = new RectF(0, 0, dstWidth - dx, dstHeight - dy);
    scaleToFit.setRectToRect(src, dst, ScaleToFit.CENTER);

    final Matrix dropShadow = new Matrix(scaleToFit);
    dropShadow.postTranslate(dx, dy);

    final Canvas maskCanvas = new Canvas(mask);
    final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
    maskCanvas.drawBitmap(bm, scaleToFit, paint);
    paint.setXfermode(new PorterDuffXfermode(Mode.SRC_OUT));
    maskCanvas.drawBitmap(bm, dropShadow, paint);

    final BlurMaskFilter filter = new BlurMaskFilter(size, Blur.NORMAL);
    paint.reset();
    paint.setAntiAlias(true);
    paint.setColor(color);
    paint.setMaskFilter(filter);
    paint.setFilterBitmap(true);

    final Bitmap ret = Bitmap.createBitmap(dstWidth, dstHeight, Config.ARGB_8888);
    final Canvas retCanvas = new Canvas(ret);
    retCanvas.drawBitmap(mask, 0,  0, paint);
    retCanvas.drawBitmap(bm, scaleToFit, null);
    mask.recycle();
    return ret;
}
like image 50
Nathan Schwermann Avatar answered Oct 29 '22 12:10

Nathan Schwermann


Here we go

http://i.imgur.com/cKi1ckX.png Yup I still dig the Nexus S

First of all, please stop masking bitmaps that way, you can accomplish this without allocating another Bitmap, checkout this blog post about how to draw rounded (and actually any shape) images.

Second using that Drawable you probably can figure out how to add your shadow, just make sure it does not get clipped, on 18+ you could use ViewOverlays for that, also keep in mind that there are several unsupported drawing operations for hardware accelerated layers, that includes setShadowLayer and BlurMaskFilter, if performance is not an issue for you, you can disable it as always:

if (SDK_INT >= HONEYCOMB) {
  view.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}

And use setShadowLayer as you were trying already:

somePaint.setShadowLayer(shadowSize, deltaX, deltaY, shadowColor);

For a sample please check the link at the end.

If you still want to be hardware accelerated you will have to fake it at risk of overdrawing, you could use a radial gradient or draw another oval blurring it yourself (as mentioned before can't use BlurMaskFilter) or use a pre-blurred Bitmap (more masking).

For such a subtle shadow I would rather just go flat if performance is required, the full sauce is in the banana stand.

Update: Starting L you can use real shadows.

like image 20
eveliotc Avatar answered Oct 29 '22 11:10

eveliotc