Various bitmap transformations that can be used with Glide to manipulate bitmaps.
They can be used like so:
Glide.with(context)
.load(image)
.transform(MyTransformation())
.into(imageView)
Or, to chain multiple transformations, like so:
Glide.with(context)
.load(image)
.apply(
RequestOptions.bitmapTransform(
MultiTransformation(
FirstTranformation(),
SecondTransformation(),
ThirdTransformation()
)
)
)
.into(imageView)
BlurTransformation
This uses renderscript to efficiently blur the image. Because renderscript has a hardcoded limit to the blur radius of 25 pixels, this method uses multiple passes to achieve a stronger blur effect. Note that this is also a heavier operation.
class BlurTransformation(context: Context, @Px private val radiusPx: Float) : BitmapTransformation() {
private val rs: RenderScript = RenderScript.create(context)
override fun transform(
pool: BitmapPool,
toTransform: Bitmap,
outWidth: Int,
outHeight: Int
): Bitmap {
val blurredBitmap = toTransform.copy(Bitmap.Config.ARGB_8888, true)
// Allocate memory for Renderscript to work with
val input = Allocation.createFromBitmap(
rs,
blurredBitmap,
Allocation.MipmapControl.MIPMAP_FULL,
Allocation.USAGE_SHARED
)
val output = Allocation.createTyped(rs, input.type)
// Load up an instance of the specific script that we want to use.
val script = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs))
script.setInput(input)
// Set the blur radius
// Note: 25 is the absolute maximum. Renderscript will crash internally on anything > 25 pixels
var radius = radiusPx
while (radius > 0) {
script.setRadius(min(radius, 25f))
// Start the ScriptIntrinisicBlur
script.forEach(output)
// Copy the output to the blurred bitmap
output.copyTo(blurredBitmap)
script.setInput(output)
radius -= 25
}
return blurredBitmap
}
override fun updateDiskCacheKey(messageDigest: MessageDigest) {
messageDigest.update("blur transformation".toByteArray())
}
}
PaddingTransformation
This one only makes sense in conjunction with the BlurTransformation
, because otherwise you’d be better off adding padding and a background color to the ImageView
itself. However, if you want to make enough room for the blur, and possibly blur a background color instead of transparency, you can use this one to prepare the bitmap for the blur.
class PaddingTransformation(@Px val padding: Int, @ColorInt val color: Int) :
BitmapTransformation() {
override fun transform(
pool: BitmapPool,
toTransform: Bitmap,
outWidth: Int,
outHeight: Int
): Bitmap {
val temp = toTransform.copy(Bitmap.Config.ARGB_8888, true)
// Create another image slightly larger
val paddedBitmap =
Bitmap.createBitmap(temp.width + 2 * padding, temp.height + 2 * padding, temp.config)
paddedBitmap.eraseColor(color)
val canvas = Canvas(paddedBitmap)
// Draw input bitmap on top
canvas.drawBitmap(temp, padding.toFloat(), padding.toFloat(), null)
temp.recycle()
return paddedBitmap
}
override fun updateDiskCacheKey(messageDigest: MessageDigest) {
messageDigest.update("padded $color".toByteArray())
}
}
Imports
Imports used in the above examples:
import android.content.Context
import android.graphics.Bitmap
import android.graphics.Canvas
import android.renderscript.Allocation
import android.renderscript.Element
import android.renderscript.RenderScript
import android.renderscript.ScriptIntrinsicBlur
import androidx.annotation.ColorInt
import androidx.annotation.Px
import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool
import com.bumptech.glide.load.resource.bitmap.BitmapTransformation
import java.security.MessageDigest
import kotlin.math.min