在 Android 中如何从位图中裁剪圆形区域

我有一个位图,我想从这个位图裁剪一个圆形区域。圆圈外的所有像素都应该是透明的。我怎么能这么做?

enter image description here

103755 次浏览

不知道这是不是编程问题,但是..。

最简单的解决方案是在源位图中使外部区域透明。否则,您将不得不计算哪些像素位于圆之外,并相应地设置 alpha (对于完全透明,alpha = 0)。

经过长时间的头脑风暴,我找到了解决办法

public Bitmap getCroppedBitmap(Bitmap bitmap) {
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.drawRoundRect(rectF, roundPx, roundPx, paint);
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);
//Bitmap _bmp = Bitmap.createScaledBitmap(output, 60, 60, false);
//return _bmp;
return output;
}

@ Gene 对上面的答案做了一个评论,建议使用 clipPath作为裁剪图像为圆形的一个选项。

以下是一个干净利落的实施方案:

    public static Bitmap GetBitmapClippedCircle(Bitmap bitmap) {


final int width = bitmap.getWidth();
final int height = bitmap.getHeight();
final Bitmap outputBitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888);


final Path path = new Path();
path.addCircle(
(float)(width / 2)
, (float)(height / 2)
, (float) Math.min(width, (height / 2))
, Path.Direction.CCW);


final Canvas canvas = new Canvas(outputBitmap);
canvas.clipPath(path);
canvas.drawBitmap(bitmap, 0, 0, null);
return outputBitmap;
}

这可以添加到实用程序类中。

从矩形生成圆

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

这也可以很容易地在 xml 中完成,而不需要裁剪实际的位图,您只需要创建一个圆形图像掩码,并将其放置在实际的图像上。下面是我使用的一段代码:

Xml

<?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"/>

Your _ layout.xml (如果不需要,忽略“ android: scaleType = “ fitXY”)

<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


<dimen name="icon">36dp</dimen>
<dimen name="icon_mask">55dp</dimen>

enter image description here

输出图片查看:

希望,它可能对某些人有用! ! ! :)

你可以使用这个代码,它将工作

public Bitmap getRoundedShape(Bitmap scaleBitmapImage) {
int targetWidth = 110;
int targetHeight = 110;
Bitmap targetBitmap = Bitmap.createBitmap(targetWidth,
targetHeight,Bitmap.Config.ARGB_8888);


Canvas canvas = new Canvas(targetBitmap);
Path path = new Path();
path.addCircle(((float) targetWidth - 1) / 2,
((float) targetHeight - 1) / 2,
(Math.min(((float) targetWidth),
((float) targetHeight)) / 2),
Path.Direction.CCW);


canvas.clipPath(path);
Bitmap sourceBitmap = scaleBitmapImage;
canvas.drawBitmap(sourceBitmap,
new Rect(0, 0, sourceBitmap.getWidth(),
sourceBitmap.getHeight()),
new Rect(0, 0, targetWidth, targetHeight), new Paint(Paint.FILTER_BITMAP_FLAG));
return targetBitmap;
}

我建议添加 bitmap.recycle(),如果您不再需要它,它将防止 OutOfMemory 错误。

我认为这个解决方案更适合任何类型的矩形,改变像素大小,如果你想要的图像小或大:

public static Bitmap getCircleBitmap(Bitmap bm) {


int sice = Math.min((bm.getWidth()), (bm.getHeight()));


Bitmap bitmap = ThumbnailUtils.extractThumbnail(bm, sice, sice);


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


Canvas canvas = new Canvas(output);


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


paint.setAntiAlias(true);
paint.setDither(true);
paint.setFilterBitmap(true);
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(color);
canvas.drawOval(rectF, paint);


paint.setColor(Color.BLUE);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth((float) 4);
paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
canvas.drawBitmap(bitmap, rect, rect, paint);


return output;
}

你可以使用 可绘制的圆形位图制作图像视图循环

here is the code for achieving roundedImageview:

ImageView profilePic=(ImageView)findViewById(R.id.user_image);


//get bitmap of the image
Bitmap imageBitmap=BitmapFactory.decodeResource(getResources(),  R.drawable.large_icon);
RoundedBitmapDrawable roundedBitmapDrawable=RoundedBitmapDrawableFactory.create(getResources(), imageBitmap);


//setting radius
roundedBitmapDrawable.setCornerRadius(50.0f);
roundedBitmapDrawable.setAntiAlias(true);
profilePic.setImageDrawable(roundedBitmapDrawable);

对于想要矩形中心的人(我) ,在切割之前添加以下内容:

    public static Bitmap cropBitmapToBlock(Bitmap bitmap) {
if (bitmap.getWidth() >= bitmap.getHeight()){
return Bitmap.createBitmap(
bitmap,
bitmap.getWidth()/2 - bitmap.getHeight()/2,
0,
bitmap.getHeight(),
bitmap.getHeight()
);
}else{
return Bitmap.createBitmap(
bitmap,
0,
bitmap.getHeight()/2 - bitmap.getWidth()/2,
bitmap.getWidth(),
bitmap.getWidth()
);
}
}

位图作物中心

你可以使用这个代码,它将工作

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


final int color = Color.RED;
final Paint paint = new Paint();
final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
final RectF rectF = new RectF(rect);


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


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


bitmap.recycle();


return output;
}

基于[ Jachumbelechao Unto Mantekilla ]的回答,这个代码对于寻找 Kotlin 解决方案的人来说就像一种魅力:

fun cropCircleFromBitmap(originalBitmap: Bitmap): Bitmap {
val size = Math.min(originalBitmap.width, originalBitmap.height)
val bitmap = ThumbnailUtils.extractThumbnail(originalBitmap, size, size)
var output = Bitmap.createBitmap(bitmap.width, bitmap.height, Bitmap.Config.ARGB_8888)
val canvas = Canvas(output)
val paint = Paint()
val rect = Rect(0, 0, bitmap.width, bitmap.height)
val rectF = RectF(rect)
paint.isAntiAlias = true
paint.isDither = true
paint.isFilterBitmap = true
canvas.drawARGB(0, 0, 0, 0)
paint.color = 0xffff0000.toInt()
canvas.drawOval(rectF, paint)
paint.color = Color.BLUE
paint.style = Paint.Style.STROKE
paint.strokeWidth = 4f
paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_IN);
canvas.drawBitmap(bitmap, rect, rect, paint)
return output
}

现在,正确答案:

private Bitmap getCroppedBitmap(Bitmap bitmap, Integer cx, Integer cy, Integer radius) {
int diam = radius << 1;
Bitmap targetBitmap = Bitmap.createBitmap(diam, diam, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(targetBitmap);
final int color = 0xff424242;
final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(color);
canvas.drawCircle(radius, radius, radius, paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(bitmap, -cx+radius, -cy+radius, paint);
return targetBitmap;
}

下面是使用扩展方法的 Kotlin 变体

/**
* Creates new circular bitmap based on original one.
*/
fun Bitmap.getCircularBitmap(config: Bitmap.Config = Bitmap.Config.ARGB_8888): Bitmap {
// circle configuration
val circlePaint = Paint().apply { isAntiAlias = true }
val circleRadius = Math.max(width, height) / 2f


// output bitmap
val outputBitmapPaint = Paint(circlePaint).apply { xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_IN) }
val outputBounds = Rect(0, 0, width, height)
val output = Bitmap.createBitmap(width, height, config)


return Canvas(output).run {
drawCircle(circleRadius, circleRadius, circleRadius, circlePaint)
drawBitmap(this@getCircularBitmap, outputBounds, outputBounds, outputBitmapPaint)
output
}
}

Kotin 函数

 fun getRoundedCornerBitmap(bitmap: Bitmap, pixels: Int): Bitmap {
val output = Bitmap.createBitmap(bitmap.width, bitmap.height, Bitmap.Config.ARGB_8888)
val canvas = Canvas(output)


val color = -0xbdbdbe
val paint = Paint()
val rect = Rect(0, 0, bitmap.width, bitmap.height)
val rectF = RectF(rect)
val roundPx = pixels.toFloat()


paint.isAntiAlias = true
canvas.drawARGB(0, 0, 0, 0)
paint.color = color
canvas.drawRoundRect(rectF, roundPx, roundPx, paint)


paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_IN)
canvas.drawBitmap(bitmap, rect, rect, paint)


return output
}

用这个代码来命名

 holder.itemFriendImage.setImageBitmap(ImageConverter.getRoundedCornerBitmap(bitmap,600))
**Jst Add this to your image Id and get the circuler image.**


imgUserProfile.setImageBitmap(getCircularCenterCropBitmap(bitmap, (int) (150 * denisty)));


Method:-


public void Bitmap getCircularCenterCropBitmap(Bitmap originalBmp, int diameter) {
Bitmap resizedBmp = BitmapUtils.getScaledCroppedBitmap(originalBmp, diameter, diameter);
return BitmapUtils.getRoundedCircularBitmap(resizedBmp, diameter / 2);
}

我认为最简单的解决方案是为你的 Bitmap 创建一个 BitmapShader,把它传递给你的油漆对象,然后简单地调用一些东西,比如画布

for example

Paint p = new Paint();
p.setShader(new BitmapShader(myBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));
canvas.drawCircle(getWidth() / 2, getHeight() / 2, getHeight() / 2, p);

https://github.com/hdodenhof/CircleImageView也是这样做的, 你可以在这里阅读源代码: Https://github.com/hdodenhof/circleimageview/blob/master/circleimageview/src/main/java/de/hdodenhof/circleimageview/circleimageview.java

对于 Kotlin:

private fun getCircularBitmap(bitmap: Bitmap): Bitmap? {
val output = Bitmap.createBitmap(
bitmap.width,
bitmap.height, Bitmap.Config.ARGB_8888
)
val canvas = Canvas(output)
val color = -0xbdbdbe
val paint = Paint()
val rect = Rect(0, 0, bitmap.width, bitmap.height)
paint.isAntiAlias = true
canvas.drawARGB(0, 0, 0, 0)
paint.color = color
canvas.drawCircle(
(bitmap.width / 2).toFloat(), (bitmap.height / 2).toFloat(), (
bitmap.width / 2).toFloat(), paint
)
paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_IN)
canvas.drawBitmap(bitmap, rect, rect, paint)
return output
}

Kotlin 输入 Ext.kt

 private fun Bitmap.getCircledBitmap(): Bitmap {
val output = Bitmap.createBitmap(this.width, this.height, Bitmap.Config.ARGB_8888)
val canvas = Canvas(output)
val paint = Paint()
val rect = Rect(0, 0, this.width, this.height)
paint.isAntiAlias = true
canvas.drawARGB(0, 0, 0, 0)
canvas.drawCircle(this.width / 2f, this.height / 2f, this.width / 2f, paint)
paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_IN)
canvas.drawBitmap(this, rect, rect, paint)
return output
}