Android - 从正方形位图中剪切出一个圆形

17
我试图使用以下代码从一个正方形位图中剪切一个圆形。
        Canvas canvas=new Canvas(bitmapimg );
        int circleXCoord = bitmapimg .getWidth() / 2;
        int circleYCoord = bitmapimg .getHeight() / 2;
        int circleRadius = bitmapimg .getWidth() / 2;

        Rect rect = new Rect(circleXCoord - circleRadius, circleYCoord - circleRadius, circleXCoord + circleRadius, circleYCoord + circleRadius);

        int width = rect.width();
        int height = rect.height();

        Paint paint = new Paint();
        paint.setStyle(Paint.Style.STROKE);
        paint.setColor(Color.BLUE);
        canvas.drawRect(rect, paint);
        canvas.drawBitmap(bitmapimg , rect, rect, paint);
        Path p = new Path();
        p.addCircle(circleXCoord, circleYCoord, width / 2F, Path.Direction.CW);
        canvas.clipPath(p, Region.Op.DIFFERENCE);
        canvas.drawColor(0, PorterDuff.Mode.CLEAR);

这个想法是在画布上附加一个正方形(矩形)位图,然后剪裁成圆形路径。清除矩形和圆形之间的差异(使其透明)。

该代码在Android 4上运行良好,但在Android 2.3.3设备上,差异区域会显示为黑色而不是透明。

我是否漏掉了什么或者 PorterDuff.Mode.CLEAR 在 gingerbread 版本中不被支持?有没有更好的方法在Android中从正方形中切出一个圆形?

3个回答

40
似乎 PorterDuff.Mode.Clear 在 Gingerbread 上不起作用。
使用以下代码解决问题(从正方形中剪切圆形):
 public Bitmap BitmapCircularCroper(Bitmap bitmapimg){
    Bitmap output = Bitmap.createBitmap(bitmapimg.getWidth(),
            bitmapimg.getHeight(), Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(output);

    final int color = 0xff424242;
    final Paint paint = new Paint();
    final Rect rect = new Rect(0, 0, bitmapimg.getWidth(),
            bitmapimg.getHeight());

    paint.setAntiAlias(true);
    canvas.drawARGB(0, 0, 0, 0);
    paint.setColor(color);
    canvas.drawCircle(bitmapimg.getWidth() / 2,
            bitmapimg.getHeight() / 2, bitmapimg.getWidth() / 2, paint);
    paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
    canvas.drawBitmap(bitmapimg, rect, rect, paint);
    return output;

}

为什么我的圆形位图周围的透明区域显示为黑色? - Ram

5
import android.graphics.PorterDuff.Mode;
import android.graphics.Bitmap.Config;

public static Bitmap getCircularBitmap(Bitmap bitmap) 
{
    Bitmap output;

    if (bitmap.getWidth() > bitmap.getHeight()) {
        output = Bitmap.createBitmap(bitmap.getHeight(), bitmap.getHeight(), Config.ARGB_8888);
    } else {
        output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getWidth(), 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());

    float r = 0;

    if (bitmap.getWidth() > bitmap.getHeight()) {
        r = bitmap.getHeight() / 2;
    } else {
        r = bitmap.getWidth() / 2;
    }

    paint.setAntiAlias(true);
    canvas.drawARGB(0, 0, 0, 0);
    paint.setColor(color);
    canvas.drawCircle(r, r, r, paint);
    paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
    canvas.drawBitmap(bitmap, rect, rect, paint);

    return output;
}

3
对于仍在关注此问题的人,这个答案将会导致一些问题。
1.) 在此实例中创建的画布将没有硬件加速。即使您的Paint对象具有反锯齿功能,但画布不会。这将导致在您决定在onDraw()调用中将其绘制回原始画布时出现伪影。
2.) 这需要更多的资源。您必须创建第二个Bitmap(可能会导致OOM),以及第二个Canvas和所有不同的修改。
请查看Romain Guy的答案。您可以创建一个BitmapShader,然后创建一个RoundRect,从而获得一个圆形。您只需要知道您的RectF的尺寸,以便它可以正确确定圆形。
这意味着如果您知道中心点(x,y)和半径,就可以轻松确定RectF。
left = x - radius;
top = y - radius;
right = x + radius;
bottom = y + radius;

这意味着使用下面发布的解决方案,你只需要在屏幕上绘制一次,其余所有操作都在离屏缓冲区中完成。
最佳解决方案在这里找到: http://www.curious-creature.com/2012/12/11/android-recipe-1-image-with-rounded-corners/
BitmapShader shader;
shader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);

Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setShader(shader);

RectF rect = new RectF(0.0f, 0.0f, width, height);

// rect contains the bounds of the shape
// radius is the radius in pixels of the rounded corners
// paint contains the shader that will texture the shape
canvas.drawRoundRect(rect, radius, radius, paint);

非常有用的是将圆形照片绘制为通知的大图标,这必须是位图。谢谢。 - androidguy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接