裁剪方形图像到圆圈 - 以编程方式

时间:2013-04-01 13:10:31

标签: android image android-canvas crop

我正在寻找过去的一天而且我没有成功。

我从API获取图像,然后使用以下代码将其下载到位图文件。

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;
    }

我将图像作为正方形,我想裁剪四个角并使其成为圆形图像。有没有可能实现的方法?

欢迎任何相关的答案。提前谢谢。

7 个答案:

答案 0 :(得分:20)

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;
        }
    }
}

答案 1 :(得分:18)

检索位图后,RoundedBitmapDrawableFactory可用于从RoundedBitmapDrawable生成v4 Support Library。然后,Drawable可以应用于ImageView或直接提取到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);

答案 2 :(得分:15)

使用函数blow在位图上绘制圆圈,然后将带圆圈的位图设置为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() / 2, bitmap.getHeight() / 2,
            bitmap.getWidth() / 2, paint);
    paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
    canvas.drawBitmap(bitmap, rect, rect, paint);
    return output;
}

答案 3 :(得分:2)

Roman Nurik建议直接使用着色器来做这样的事情,并使用自定义绘图。

我稍微更改了代码以制作椭圆形图像并进行自我测试。效果和表现非常好:

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);
}
}

答案 4 :(得分:0)

这可以在xml中完成,请在此处查看我的答案: 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"/>

答案 5 :(得分:0)

我尝试了上述解决方案,但对我来说都没有用。这是因为我的手机摄像头不能拍摄正方形图像,而只能拍摄矩形图像。因此,我在@actsai解决方案中进行了一些更改,以始终采用较小的尺寸,然后将图像裁剪成一个圆圈:

func dec<T: Decodable>(from: URL, decodable: T.Type, result: (T) -> Void) { 
    // your Alamofire logic
    let data = try JSONDecoder().decode(popedList, from: result!)
    result(data)
}

我使用以下scale属性将新的位图填充到ImageView中:

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;
}

答案 6 :(得分:0)

在寻找了很多答案之后,我想到了一个小技巧,该技巧利用了FrameLayout(将子视图叠加成一个堆栈)和椭圆形的stroke属性。这可以用XML轻松完成,而无需太多麻烦和第三方库。

  1. 在res / layout目录下创建新的布局资源文件“ circle_image.xml”。
  2. 在circle_image.xml中添加新的FrameLayout作为根视图。
  3. 创建一个ImageView(基础/背景)以保存要裁剪的Image或Icon作为FrameLayout中的第一个孩子。
  4. 创建一个ImageView(遮罩/前景)以容纳将背景图像作为FrameLayout内部的第二个/最后一个孩子遮住的形状(椭圆形,具有具有相同高度和宽度的size属性的圆形)。

注意:

我们的想法是排除圆周围的区域,并显示圆内部可见的图像内容。

  1. 在res / drawable目录下创建新的Drawable资源文件“ circle_mask.xml”。
  2. 在circle_mask.xml中使用android:shape =“ oval”添加新形状。
  3. 为形状添加尺寸标签,以指定高度和宽度,该高度和宽度必须相等(使其变为圆形),并且必须与其父级FrameLayout的高度和宽度匹配。
  4. 为形状添加实体标签以指定圆内的透明度。 10.为该形状添加笔触标签,以便有一个特定宽度的环(android:width),其颜色由android:color属性指定。

注意:

a。笔划标签中指定的颜色(笔划颜色)是裁剪图像周围的 MaskColor / BackgroundColor 。因为我希望此颜色与我的基本视图(即cardView)的颜色相同。我使用了相同的颜色“白色”。

b。宽度(笔划宽度)设置为很大的值,以至于太厚,无法在中心放置裁剪的图像。

c。还可以通过指定一个比其父级FrameLayout大得多的巨大尺寸来利用在步骤4中创建的ImageView(顶部蒙版层),从而使其在FrameLayout尺寸之外进行扩展。这会用较大的笔触宽度环填充我们感兴趣的遮罩区域。

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