Glide bitmap transformations

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