【问题标题】:Crop square image to circle - Programmatically将方形图像裁剪为圆形 - 以编程方式
【发布时间】:2013-03-22 13:36:55
【问题描述】:

我正在搜索过去的一天,但我没有成功。

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

我得到一个正方形的图像,我想裁剪四个角并使其成为圆形图像。有没有什么办法可以实现?

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

【问题讨论】:

  • 不确定我的头顶,但我想作为替代方法可能是创建一个 alpha 圆形图像,在原始图像顶部切出大小合适的孔。与使用 circle 类并进行适当的编辑相比,这并不理想,但如果您找不到所需的内容并需要快速解决,这是一种替代方法。

标签: android image android-canvas crop


【解决方案1】:

使用下面的函数在位图上画一个圆圈,然后将圆圈的位图设置为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;
    }

注意:除数必须是浮点数

【讨论】:

  • 很棒的功能,但是这条线做了什么:paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
  • @bebosh 这设置了位图的绘制模式(参见ssp.impulsetrain.com/porterduff.html)...或者您是在问为什么需要调用此方法?
  • 此自定义方法可以正常工作而不会出错,但会生成水平椭圆形的图像。使用 RoundedBitmapDrawableFactory 会产生一个完美的圆,仅供参考。
【解决方案2】:

在寻找了很多答案后,我想出了这个小技巧,它利用了 FrameLayout(将子视图叠加为堆栈)和椭圆形的笔画属性。这可以在 XML 中简单地完成,无需太多麻烦和第三方库。

  1. 在res/layout目录下新建Layout资源文件“circle_image.xml”。
  2. 在 circle_image.xml 中添加一个新的 FrameLayout 作为根视图。
  3. 创建一个 ImageView(基础/背景)来保存您想要裁剪为 FrameLayout 中的第一个子项的图像或图标。
  4. 创建一个 ImageView(蒙版/前景)来保存形状(将椭圆制成具有相同高度和宽度的 size 属性的圆形),将背景图像作为 FrameLayout 中的第二个/最后一个子对象进行掩蔽。

注意:

我们这里的想法是排除圆圈周围的区域并显示圆圈内可见的图像内容)

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

注意:

一个。 stoke 标记中指定的颜色(描边颜色)是我们裁剪图像周围的 MaskColor/BackgroundColor。因为我希望这种颜色与我的基本视图相同,即 cardView。我使用了相同的颜色“白色”。

b.宽度(笔划宽度)设置为一个很大的值,以至于它太厚了,中间有足够的空间容纳我们裁剪的图像。

c。在第 4 步中创建的 ImageView(顶部遮罩层)也通过指定一个比其父 FrameLayout 大得多的巨大尺寸来利用,使其扩展到 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>

【讨论】:

    【解决方案3】:

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

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

    我使用以下比例属性用新的位图填充我的 ImageView:

    <ImageView
        android:id="@+id/iv_photo"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_gravity="center"
        android:scaleType="fitXY" />
    

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        【解决方案5】:

        检索位图后,RoundedBitmapDrawableFactory 可用于从v4 Support Library 生成RoundedBitmapDrawable。然后可以将 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);
        

        【讨论】:

        • 非常感谢Godfrey,这个答案是最简单也是最好的答案。这应该是公认的答案!
        • 非常感谢,这对@Godfrey Duke 很有帮助
        【解决方案6】:
        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;
                }
            }
        }
        

        【讨论】:

        • 此代码将在每次调用 onDraw() 时重新创建剪切的位图。最好仅在源位图更改然后绘制它时创建对剪切的可绘制对象的引用。事实上,您也可能会丢失对源位图的引用。在绘图循环之外分配 Paint 也更好。
        • @greg7gkb 的建议会在我有时间的时候改进帖子
        【解决方案7】:

        这可以简单地在 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"/>
        

        【讨论】:

          猜你喜欢
          • 2012-03-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-01-08
          • 2018-12-31
          • 2012-02-28
          • 1970-01-01
          • 2016-05-01
          相关资源
          最近更新 更多