diff --git a/library/src/main/java/com/bumptech/glide/load/resource/bitmap/GranularRoundedCorners.java b/library/src/main/java/com/bumptech/glide/load/resource/bitmap/GranularRoundedCorners.java new file mode 100644 index 0000000000..b454a80008 --- /dev/null +++ b/library/src/main/java/com/bumptech/glide/load/resource/bitmap/GranularRoundedCorners.java @@ -0,0 +1,69 @@ +package com.bumptech.glide.load.resource.bitmap; + +import android.graphics.Bitmap; +import androidx.annotation.NonNull; +import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; +import com.bumptech.glide.util.Util; +import java.nio.ByteBuffer; +import java.security.MessageDigest; + +/** A {@link BitmapTransformation} which has a different raddius for each corner of a bitmap. */ +public final class GranularRoundedCorners extends BitmapTransformation { + private static final String ID = "com.bumptech.glide.load.resource.bitmap.GranularRoundedCorners"; + private static final byte[] ID_BYTES = ID.getBytes(CHARSET); + + private final float topLeft; + private final float topRight; + private final float bottomRight; + private final float bottomLeft; + + /** Provide the radii to round the corners of the bitmap. */ + public GranularRoundedCorners( + float topLeft, float topRight, float bottomRight, float bottomLeft) { + this.topLeft = topLeft; + this.topRight = topRight; + this.bottomRight = bottomRight; + this.bottomLeft = bottomLeft; + } + + @Override + protected Bitmap transform( + @NonNull BitmapPool pool, @NonNull Bitmap toTransform, int outWidth, int outHeight) { + return TransformationUtils.roundedCorners( + pool, toTransform, topLeft, topRight, bottomRight, bottomLeft); + } + + @Override + public boolean equals(Object o) { + if (o instanceof GranularRoundedCorners) { + GranularRoundedCorners other = (GranularRoundedCorners) o; + return topLeft == other.topLeft + && topRight == other.topRight + && bottomRight == other.bottomRight + && bottomLeft == other.bottomLeft; + } + return false; + } + + @Override + public int hashCode() { + int hashCode = Util.hashCode(ID.hashCode(), Util.hashCode(topLeft)); + hashCode = Util.hashCode(topRight, hashCode); + hashCode = Util.hashCode(bottomRight, hashCode); + return Util.hashCode(bottomLeft, hashCode); + } + + @Override + public void updateDiskCacheKey(@NonNull MessageDigest messageDigest) { + messageDigest.update(ID_BYTES); + + byte[] radiusData = + ByteBuffer.allocate(16) + .putFloat(topLeft) + .putFloat(topRight) + .putFloat(bottomRight) + .putFloat(bottomLeft) + .array(); + messageDigest.update(radiusData); + } +} diff --git a/library/src/main/java/com/bumptech/glide/load/resource/bitmap/TransformationUtils.java b/library/src/main/java/com/bumptech/glide/load/resource/bitmap/TransformationUtils.java index 91fdf2c53e..c663713917 100644 --- a/library/src/main/java/com/bumptech/glide/load/resource/bitmap/TransformationUtils.java +++ b/library/src/main/java/com/bumptech/glide/load/resource/bitmap/TransformationUtils.java @@ -7,6 +7,7 @@ import android.graphics.Color; import android.graphics.Matrix; import android.graphics.Paint; +import android.graphics.Path; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.graphics.RectF; @@ -472,9 +473,71 @@ public static Bitmap roundedCorners( * @throws IllegalArgumentException if roundingRadius, width or height is 0 or less. */ public static Bitmap roundedCorners( - @NonNull BitmapPool pool, @NonNull Bitmap inBitmap, int roundingRadius) { + @NonNull BitmapPool pool, @NonNull Bitmap inBitmap, final int roundingRadius) { Preconditions.checkArgument(roundingRadius > 0, "roundingRadius must be greater than 0."); + return roundedCorners( + pool, + inBitmap, + new DrawRoundedCornerFn() { + @Override + public void drawRoundedCorners(Canvas canvas, Paint paint, RectF rect) { + canvas.drawRoundRect(rect, roundingRadius, roundingRadius, paint); + } + }); + } + + /** + * Creates a bitmap from a source bitmap and rounds the corners, applying a potentially different + * [X, Y] radius to each corner. + * + *
This method does NOT resize the given {@link Bitmap}, it only rounds it's corners. + * To both resize and round the corners of an image, consider {@link + * com.bumptech.glide.request.RequestOptions#transform(Transformation[])} and/or {@link + * com.bumptech.glide.load.MultiTransformation}. + * + * @param inBitmap the source bitmap to use as a basis for the created bitmap. + * @param topLeft top-left radius + * @param topRight top-right radius + * @param bottomRight bottom-right radius + * @param bottomLeft bottom-left radius + * @return a {@link Bitmap} similar to inBitmap but with rounded corners. + */ + public static Bitmap roundedCorners( + @NonNull BitmapPool pool, + @NonNull Bitmap inBitmap, + final float topLeft, + final float topRight, + final float bottomRight, + final float bottomLeft) { + return roundedCorners( + pool, + inBitmap, + new DrawRoundedCornerFn() { + @Override + public void drawRoundedCorners(Canvas canvas, Paint paint, RectF rect) { + Path path = new Path(); + path.addRoundRect( + rect, + new float[] { + topLeft, + topLeft, + topRight, + topRight, + bottomRight, + bottomRight, + bottomLeft, + bottomLeft + }, + Path.Direction.CW); + canvas.drawPath(path, paint); + } + }); + } + + private static Bitmap roundedCorners( + @NonNull BitmapPool pool, @NonNull Bitmap inBitmap, DrawRoundedCornerFn drawRoundedCornerFn) { + // Alpha is required for this transformation. Bitmap.Config safeConfig = getAlphaSafeConfig(inBitmap); Bitmap toTransform = getAlphaSafeBitmap(pool, inBitmap); @@ -492,7 +555,7 @@ public static Bitmap roundedCorners( try { Canvas canvas = new Canvas(result); canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); - canvas.drawRoundRect(rect, roundingRadius, roundingRadius, paint); + drawRoundedCornerFn.drawRoundedCorners(canvas, paint, rect); clear(canvas); } finally { BITMAP_DRAWABLE_LOCK.unlock(); @@ -559,6 +622,12 @@ static void initializeMatrixForRotation(int exifOrientation, Matrix matrix) { } } + /** Convenience function for drawing a rounded bitmap. */ + private interface DrawRoundedCornerFn { + + void drawRoundedCorners(Canvas canvas, Paint paint, RectF rect); + } + private static final class NoLock implements Lock { @Synthetic