6

I am using this very common class to round corners:

   public static Bitmap getRoundedCornerBitmap(Bitmap bitmap, int pixels) {
        Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap
                .getHeight(), Config.ARGB_8888);
        Canvas canvas = new Canvas(output);

        final int color = 0xff424242;
        final Paint paint = new Paint();
        final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
        final RectF rectF = new RectF(rect);
        final float roundPx = pixels;

        paint.setAntiAlias(true);
        canvas.drawARGB(0, 0, 0, 0);
        paint.setColor(color);
        canvas.drawRoundRect(rectF, roundPx, roundPx, paint);

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

        return output;
    }

I'd like to modify it so that only Top Left corner is rounded. I can't find the parameter in the code that does this? Can someone assist?

TheLettuceMaster
  • 15,594
  • 48
  • 153
  • 259
  • This might help - http://developer.android.com/reference/android/graphics/drawable/shapes/RoundRectShape.html – Varun Jun 20 '13 at 23:44
  • @Varun I need a bit more info then this? The dev doc's aren't always friendly when you want something this specific. – TheLettuceMaster Jun 20 '13 at 23:58

6 Answers6

6

It's probably not the most efficient way to do this, but you could fill in the rounded off corners by painting on top of your current mask. You could start with the current code then use canvas.drawRect (right after the call to canvas.drawRoundRect) on the appropriate regions (the corners). I imagine something like this would round only the top left corner:

public static Bitmap getRoundedTopLeftCornerBitmap(Bitmap bitmap, int pixels) {
    Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap
            .getHeight(), Config.ARGB_8888);
    Canvas canvas = new Canvas(output);

    final int color = 0xff424242;
    final Paint paint = new Paint();
    final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
    final RectF rectF = new RectF(rect);
    final float roundPx = pixels;
    final Rect topRightRect = new Rect(bitmap.getWidth()/2, 0, bitmap.getWidth(), bitmap.getHeight()/2);
    final Rect bottomRect = new Rect(0, bitmap.getHeight()/2, bitmap.getWidth(), bitmap.getHeight());

    paint.setAntiAlias(true);
    canvas.drawARGB(0, 0, 0, 0);
    paint.setColor(color);
    canvas.drawRoundRect(rectF, roundPx, roundPx, paint);
    // Fill in upper right corner
    canvas.drawRect(topRightRect, paint);
    // Fill in bottom corners
    canvas.drawRect(bottomRect, paint);

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

    return output;
}

There's a bit of optimization you could do here if you feel like it, but I think it should work. The general idea definitely should. I haven't tried or tested this code though and it won't look right if pixels > bitmap.getWidth()/2 or pixels > bitmap.getHeight()/2. Then again, that was probably true before too.

kabuko
  • 36,028
  • 10
  • 80
  • 93
  • This did it, thanks! Do you think this will have performance effect on an image that is in every `listView`? Marking you correct as well. – TheLettuceMaster Jun 21 '13 at 16:56
  • 1
    I wouldn't imagine this has severe performance issues, though if you mean that it's in every `ListView` item then it might add up just enough to make things not quite smooth when scrolling. If this happens you'll have to do the usual tricks with asynchronous loading. Just give it a try and see how it feels before you try too hard to optimize. – kabuko Jun 21 '13 at 17:58
  • how would I go about taking a square image, rounding it, then extracting the upper right 1/4 of the image? – MCR Feb 12 '14 at 16:05
  • see http://stackoverflow.com/questions/21709388/imageview-subclass-to-make-rounded-right-corner – MCR Feb 12 '14 at 16:13
4
public static Bitmap getRoundedCornerBitmap(Bitmap bitmap, int topLeftX, int topLeftY, int topRightX, int topRightY, int bottomRightX, int bottomRightY, int bottomLeftX, int bottomLeftY) {
        final Paint paint = new Paint();
        final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
        Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(output);
        // the float array passed to this function defines the x/y values of the corners
        // it starts top-left and works clockwise
        // so top-left-x, top-left-y, top-right-x etc
        RoundRectShape rrs = new RoundRectShape(new float[]{topLeftX, topLeftY, topRightX, topRightY, bottomRightX, bottomRightY, bottomLeftX, bottomLeftY}, null, null);
        canvas.drawARGB(0, 0, 0, 0);
        paint.setAntiAlias(true);
        paint.setColor(0xFF000000);
        rrs.resize(bitmap.getWidth(), bitmap.getHeight());
        rrs.draw(canvas, paint);
        paint.setXfermode(new PorterDuffXfermode(android.graphics.PorterDuff.Mode.SRC_IN));
        canvas.drawBitmap(bitmap, rect, rect, paint);
        return output;
    }

Or you can see RoundRects.java source code - example that show how to produce round corners, available in SDK samples: http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android-apps/4.3_r2.1/com/example/android/apis/graphics/RoundRects.java/

user2131854
  • 137
  • 4
  • I don't quite understand your code. If I wanted to round an image then crop to it's top right 1/4, could I do that with this code? – MCR Feb 12 '14 at 15:57
3

this is for select corners:

public static Bitmap getRoundedCornerBitmap(Context context, Bitmap bitmap, float roundDip, boolean roundTL, boolean roundTR, boolean roundBL, boolean roundBR)
{
    try
    {

        Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Config.ARGB_8888);
        Canvas canvas = new Canvas(output);

        final int color = 0xff424242;
        final Paint paint = new Paint();
        final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
        final RectF rectF = new RectF(rect);
        final float roundPx = convertDipToPixel(roundDip, context);

        paint.setAntiAlias(true);
        canvas.drawARGB(0, 0, 0, 0);
        paint.setColor(color);
        canvas.drawRoundRect(rectF, roundPx, roundPx, paint);// draw round
                                                                // 4Corner

        if (!roundTL)
        {
            Rect rectTL = new Rect(0, 0, bitmap.getWidth() / 2, bitmap.getHeight() / 2);
            canvas.drawRect(rectTL, paint);
        }
        if (!roundTR)
        {
            Rect rectTR = new Rect(bitmap.getWidth() / 2, 0, bitmap.getWidth(), bitmap.getHeight() / 2);
            canvas.drawRect(rectTR, paint);
        }
        if (!roundBR)
        {
            Rect rectBR = new Rect(bitmap.getWidth() / 2, bitmap.getHeight() / 2, bitmap.getWidth(), bitmap.getHeight());
            canvas.drawRect(rectBR, paint);
        }
        if (!roundBL)
        {
            Rect rectBL = new Rect(0, bitmap.getHeight() / 2, bitmap.getWidth() / 2, bitmap.getHeight());
            canvas.drawRect(rectBL, paint);
        }

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

        return output;
    } catch (Exception e)
    {
    }
    return bitmap;
}
Sajad
  • 31
  • 1
1

This is more of a conceptual answer, but could you draw a rounded rectangle then layer two normal rectangles on top of the corner that you would like to be rounded?

Visual example

WeldFire
  • 194
  • 1
  • 3
  • 8
  • This is essentially what I did in my above answer although with slightly different dimensions for the shapes. – kabuko Jun 21 '13 at 17:56
0

In case you needed to draw (on canvas) a round rect with different radii for different corners, you can use this:

private void drawAsymmetricRoundRect(Canvas canvas, RectF rectF, float[] radii, Paint paint) {
    float topLeftX = rectF.left + radii[0];
    float topLeftY = rectF.top + radii[0];
    float topRightX = rectF.right - radii[1];
    float topRightY = rectF.top + radii[1];
    float bottomRightX = rectF.right - radii[2];
    float bottomRightY = rectF.bottom - radii[2];
    float bottomLeftY = rectF.bottom - radii[3];
    float bottomLeftX = rectF.left + radii[3];
    RectF topLeftCorner = new RectF(rectF.left, rectF.top, topLeftX + radii[0], topLeftY + radii[0]);
    RectF topRightCorner = new RectF(topRightX - radii[1], rectF.top, rectF.right, topRightY + radii[1]);
    RectF bottomRightCorner = new RectF(bottomRightX - radii[2], bottomRightY - radii[2], rectF.right, rectF.bottom);
    RectF bottomLeftCorner = new RectF(rectF.left, bottomLeftY - radii[3], bottomLeftX + radii[3], rectF.bottom);

    canvas.drawArc(topLeftCorner, 180, 90, true, paint);
    canvas.drawArc(topRightCorner, 270, 90, true, paint);
    canvas.drawArc(bottomRightCorner, 0, 90, true, paint);
    canvas.drawArc(bottomLeftCorner, 90, 90, true, paint);
    canvas.drawRect(topLeftX, rectF.top, topRightX, bottomLeftY < bottomRightY ? bottomLeftY : bottomRightY, paint); //top rect
    canvas.drawRect(topLeftX > bottomLeftX ? topLeftX : bottomLeftX, topRightY, rectF.right, bottomRightY, paint); //right rect
    canvas.drawRect(bottomLeftX, topLeftY > topRightY ? topLeftY : topRightY, bottomRightX, rectF.bottom, paint); //bottom rect
    canvas.drawRect(rectF.left, topLeftY, bottomRightX < topRightX ? bottomRightX : topRightX, bottomLeftY, paint); //left rect
}

float[] radii is a float array (length = 4), that stores sizes of radii of your corners (clockwise, starting from top-left corner => {topLeft, topRight, bottomRight, bottomLeft}).

Basically this approach draws 4 arcs (corners) and fills everything in between those corners with 4 rects.

IMPORTANT NOTE: I placed the initialization of corners RectFs within this method to reduce the complexity of posted code. Due to the fact that you will problably call this method from your onDraw() method, you should extract this part of the code, and place it where you init other Rects(as long as you're not initializing them in onDraw() as well :P).

Bartek Lipinski
  • 30,698
  • 10
  • 94
  • 132
0
Path clipPath = new Path();
RectF rect = new RectF(0, 0, this.getWidth(), this.getHeight());
clipPath.addRoundRect(rect, new float[]{radius, radius, 0, 0, 0, 0, 0, 0}, 
Path.Direction.CW);
canvas.clipPath(clipPath);

This code produces image with rounded top left corner - each pair of float parameters describe angle for each corner

Key function is:

public void addRoundRect(RectF rect, float[] radii, Direction dir)

in Path class

Description from doc:

Add a closed round-rectangle contour to the path. Each corner receives two radius values [X, Y]. The corners are ordered top-left, top-right, bottom-right, bottom-left

@param rect The bounds of a round-rectangle to add to the path

@param radii Array of 8 values, 4 pairs of [X,Y] radii

@param dir The direction to wind the round-rectangle's contour