25

i was searching for past one day and i was not successful .

i get the image from API , and i download it to a bitmap file using the following code .

private Bitmap DownloadImage(String URL) 
    {
        Bitmap bitmap = null;
        InputStream in = null;
        try 
        {
            in = OpenHttpConnection(URL);
            bitmap = BitmapFactory.decodeStream(in);
            in.close();
        }
        catch (IOException e1) 
        {
            e1.printStackTrace();
        }
        return bitmap;
    }

    private InputStream OpenHttpConnection(String urlString) throws IOException 
    {
        InputStream in = null;
        int response = -1;

        URL url = new URL(urlString);
        URLConnection conn = url.openConnection();

        if (!(conn instanceof HttpURLConnection))
            throw new IOException("Not an HTTP connection");

        try 
        {
            HttpURLConnection httpConn = (HttpURLConnection) conn;
            httpConn.setAllowUserInteraction(false);
            httpConn.setInstanceFollowRedirects(true);
            httpConn.setRequestMethod("GET");
            httpConn.connect();

            response = httpConn.getResponseCode();
            if (response == HttpURLConnection.HTTP_OK) 
            {
                in = httpConn.getInputStream();
            }
        }
        catch (Exception ex) 
        {
            throw new IOException("Error connecting");
        }
        return in;
    }

And i get the image as a square and i want to crop the four corners and make it to circular image . Is there any possible way to achieve ?

Any related answers are welcomed . Thanks in advance .

Loktar
  • 34,764
  • 7
  • 90
  • 104
VIGNESH
  • 2,023
  • 8
  • 31
  • 46
  • Not sure off the top of my head, but I suppose as alternative approach could be to create an alpha circle image with the hole cut out sized on top of the original image. This is not ideal compared to working with a circle class and doing the appropriate edits, but an alternative if you don't find what you are looking for and need a quick resolution. – Jay Snayder Apr 01 '13 at 13:19

7 Answers7

22

Once the bitmap is retrieved RoundedBitmapDrawableFactory can be used to generate a RoundedBitmapDrawable from the v4 Support Library. That Drawable can then be applied to an ImageView or directly drawn to a Canvas.

// Create the RoundedBitmapDrawable.
RoundedBitmapDrawable roundDrawable = RoundedBitmapDrawableFactory.create(getResources(), bitmap);
roundDrawable.setCircular(true);

// Apply it to an ImageView.
ImageView imageView = (ImageView)findViewById(R.id.imageView);
imageView.setImageDrawable(roundDrawable);

// Alternatively, draw it to an canvas (e.g. in onDraw where a Canvas is available).
// setBounds since there's no View handling size and positioning.
roundDrawable.setBounds(left, top, right, bottom);
roundDrawable.draw(canvas);
Godfrey Duke
  • 1,505
  • 16
  • 19
21
public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        DrawingView dv = new DrawingView(this);
        setContentView(dv);
    }

    class DrawingView extends View {
        Bitmap bitmap;

        public DrawingView(Context context) {
            super(context);
            bitmap = BitmapFactory.decodeResource(context.getResources(),
                    R.drawable.glossy_overlay);

        }

        @Override
        public void onDraw(Canvas canvas) {
            Paint paint = new Paint();
            // paint.setColor(Color.CYAN);
            canvas.drawBitmap(getclip(), 30, 20, paint);
        }

        public Bitmap getclip() {
            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());

            paint.setAntiAlias(true);
            canvas.drawARGB(0, 0, 0, 0);
            // paint.setColor(color);
            canvas.drawCircle(bitmap.getWidth() / 2,
                    bitmap.getHeight() / 2, bitmap.getWidth() / 2, paint);
            paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
            canvas.drawBitmap(bitmap, rect, rect, paint);
            return output;
        }
    }
}
Gopal Gopi
  • 11,101
  • 1
  • 30
  • 43
Raghunandan
  • 132,755
  • 26
  • 225
  • 256
  • 2
    This code will re-create the clipped bitmap every time onDraw() is called. Better to create a reference to the clipped drawable only when the source bitmap changes and then draw that. In fact, you can lose the reference to the source bitmap as well. Also better to allocate Paint outside of the drawing loop. – greg7gkb Mar 12 '15 at 00:27
  • @greg7gkb suggestion taken will improve the post when i have time – Raghunandan Mar 12 '15 at 04:49
17

use the function below to draw a circle on bitmap and then set the circled bitmap to imageView

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

        final Paint paint = new Paint();
        final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());

        paint.setAntiAlias(true);
        canvas.drawARGB(0, 0, 0, 0);
        canvas.drawCircle(bitmap.getWidth() / 2f, bitmap.getHeight() / 2f,
            bitmap.getWidth() / 2f, paint);
        paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
        canvas.drawBitmap(bitmap, rect, rect, paint);
        return output;
    }

Note: Dividing numbers must be float

AgentP
  • 6,261
  • 2
  • 31
  • 52
actsai
  • 178
  • 1
  • 6
  • Great function, but what this line do: paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN)); – bebosh Jan 14 '15 at 14:11
  • @bebosh this sets the drawing mode for the bitmap (see http://ssp.impulsetrain.com/porterduff.html)... or are you asking why the call to this method is required? – greg7gkb Apr 20 '15 at 03:01
  • This custom method works fine without errors but produces an image that is a horizontal oval. Using RoundedBitmapDrawableFactory produces a perfect circle, just FYI. – JamisonMan111 Feb 28 '17 at 05:13
2

Roman Nurik propose a very direct use of shaders to do things like that, with a custom drawable.

I change the code a bit to make an oval image and tested myself. The effect and performance are really good:

public  class StreamDrawable extends Drawable {
private static final boolean USE_VIGNETTE = true;

private final RectF mRect = new RectF();
private final BitmapShader mBitmapShader;
private final Paint mPaint;
private final int mMargin;

public StreamDrawable(Bitmap bitmap, int margin) {

    mBitmapShader = new BitmapShader(bitmap,
            Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);

    mPaint = new Paint();
    mPaint.setAntiAlias(true);
    mPaint.setShader(mBitmapShader);

    mMargin = margin;
}

@Override
protected void onBoundsChange(Rect bounds) {
    super.onBoundsChange(bounds);
    mRect.set(mMargin, mMargin, bounds.width() - mMargin, bounds.height() - mMargin);

    if (USE_VIGNETTE) {
        RadialGradient vignette = new RadialGradient(
                mRect.centerX(), mRect.centerY() * 1.0f / 0.7f, mRect.centerX() * 1.3f,
                new int[] { 0, 0, 0x7f000000 }, new float[] { 0.0f, 0.7f, 1.0f },
                Shader.TileMode.CLAMP);

        Matrix oval = new Matrix();
        oval.setScale(1.0f, 0.7f);
        vignette.setLocalMatrix(oval);

        mPaint.setShader(
                new ComposeShader(mBitmapShader, vignette, PorterDuff.Mode.SRC_OVER));
    }
}

@Override
public void draw(Canvas canvas) {
    canvas.drawOval(mRect, mPaint);
}

@Override
public int getOpacity() {
    return PixelFormat.TRANSLUCENT;
}

@Override
public void setAlpha(int alpha) {
    mPaint.setAlpha(alpha);
}

@Override
public void setColorFilter(ColorFilter cf) {
    mPaint.setColorFilter(cf);
}
}
Illegal Argument
  • 10,090
  • 2
  • 44
  • 61
Renascienza
  • 1,647
  • 1
  • 13
  • 16
0

This can be simply done in xml, Please see my answer here: https://stackoverflow.com/a/18287979/665930

<RelativeLayout
            android:id="@+id/icon_layout"
            android:layout_width="@dimen/icon_mask"
            android:layout_height="@dimen/icon_mask"
            android:layout_alignParentLeft="true"
            android:layout_alignParentTop="true" >

            <ImageView
                android:id="@+id/icon"
                android:layout_width="@dimen/icon"
                android:layout_height="@dimen/icon"
                android:layout_centerInParent="true"
                android:scaleType="fitXY" >
            </ImageView>

            <ImageView
                android:id="@+id/icon_mask"
                android:layout_width="@dimen/icon_mask"
                android:layout_height="@dimen/icon_mask"
                android:layout_centerInParent="true"
                android:background="@drawable/circle"
                android:scaleType="fitXY" >
            </ImageView>


 </RelativeLayout>


<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval" >
    <gradient android:startColor="#00FFFFFF" android:endColor="#00FFFFFF"
        android:angle="270"/>
     <stroke android:width="10dp" android:color="#FFAAAAAA"/>
Community
  • 1
  • 1
Ash
  • 1,391
  • 15
  • 20
0

I tried the solutions above but none worked well for me. This is because my phone camera don't take square image but just rectangle images. So, I make some changes in the @actsai solution to always take the minor dimension and then crop the image in a circle:

public static Bitmap getBitmapClip(Bitmap bitmap) {
    int maxLenth = bitmap.getWidth() <= bitmap.getHeight() ? bitmap.getWidth() : bitmap.getHeight();
    Bitmap output = Bitmap.createBitmap(maxLenth,
            maxLenth, Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(output);

    final Paint paint = new Paint();
    final Rect rect = new Rect(0, 0, maxLenth, maxLenth);

    paint.setAntiAlias(true);
    canvas.drawARGB(0, 0, 0, 0);
    canvas.drawCircle(maxLenth / 2, maxLenth / 2,
            maxLenth / 2, paint);
    paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
    canvas.drawBitmap(bitmap, rect, rect, paint);
    return output;
}

I used the following scale property to fill my ImageView with the new bitmap:

<ImageView
    android:id="@+id/iv_photo"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_gravity="center"
    android:scaleType="fitXY" />
Ângelo Polotto
  • 8,463
  • 2
  • 36
  • 37
0

After hunting lot of answers I came up with this small hack which exploits FrameLayout(overlays child views as a stack) and stroke attribute of oval-shape. This can be done simply in XML without much hassle and third party libraries.

  1. Create new Layout resource file "circle_image.xml" under res/layout directory.
  2. Add a new FrameLayout as the root view in the circle_image.xml.
  3. Create an ImageView (base/background) to hold your Image or Icon which you want to crop as the first child in the FrameLayout.
  4. Create an ImageView (mask/foreground) to hold the shape(oval made into circle with size attribute having same height and width) that masks the background image as the second/last child inside the FrameLayout.

Note:

our idea here is to exclude the area around the circle and display the contents of the image that is visible inside the circle)

  1. Create new Drawable resource file "circle_mask.xml" under res/drawable directory.
  2. Add new shape with android:shape="oval" in the circle_mask.xml.
  3. Add size tag for the shape to specify height and width which must be equal(to make it a circle) and should match that of its parent FrameLayout.
  4. Add solid tag for the shape to specify the transparency inside the circle. 10.Add stroke tag for the shape so that there will be a ring of particular width(android:width) with the color specified by the android:color attribute.

Note:

a. The color(stroke color) specified in the stoke tag is the MaskColor/BackgroundColor around our cropped image. since I wanted this color to be same as that of my base view which was a cardView. I used the same color "white".

b. The width (stroke width) is set to a huge value such that it is too thick with enough space for our cropped image in the centre.

c. The ImageView(top mask layer) created in Step-4 is also exploited by specifying a huge dimension that is much larger than its parent FrameLayout making it expand outside the FrameLayout dimensions. This fills up the area which we are interested in masking with the color of large stroke width ring.

circle_image.xml

<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/icon_layout"
    android:layout_width="64dp"
    android:layout_height="64dp">

    <ImageView
        android:id="@+id/iv_profile_pic"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:src="@drawable/ic_launcher_background"
        android:contentDescription="TODO"/>


    <ImageView
        android:layout_width="90dp"
        android:layout_height="90dp"
        android:layout_gravity="center"
        android:background="@drawable/circle"
        android:scaleType="fitXY" >
    </ImageView>
</FrameLayout>

circle_mask.xml

<?xml version="1.0" encoding="utf-8"?>
<shape
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="oval">
    <size android:width="64dp"
        android:height="64dp"/>
    <solid android:color="@android:color/transparent"/>
    <stroke
        android:width="18dp"
        android:color="@android:color/white" />
</shape>

Oval(circle) shape and final image

mahee96
  • 705
  • 6
  • 15