About

Transformations in Glide take a resource, mutate it, and return the mutated resource. Typically transformations are used to crop, or apply filters to Bitmaps, but they can also be used to transform animated GIFs, or even custom resource types.

Built in types

Glide includes a number of built in transformations, including:

Applying Transformations

Transformations are applied using the RequestOptions class:

Default Transformations

RequestOptions options = new RequestOptions();
options.centerCrop();

Glide.with(fragment)
    .load(url)
    .apply(options)
    .into(imageView);

Most built in transformations also have static imports for a more fluent API. For example, you can apply a FitCenter transformation using a static method:

import static com.bumptech.glide.request.RequestOptions.fitCenterTransform;

Glide.with(fragment)
    .load(url)
    .apply(fitCenterTransform())
    .into(imageView);

If you’re using the generated API the transformation methods are inlined, so it’s even easier:

GlideApp.with(fragment)
  .load(url)
  .fitCenter()
  .into(imageView);

For more information on using RequestOptions, see the Options wiki page.

Multiple Transformations.

By default, each subsequent call to transform() or any specific transform method (fitCenter(), centerCrop(), bitmapTransform() etc) will replace the previous transformation.

To instead apply multiple transformations to a single load, use the MultiTransformation class or the shortcut .transforms() method.

With the generated API:

GlideApp.with(fragment)
  .load(url)
  .transform(new MultiTransformation(new FitCenter(), new YourCustomTransformation())
  .into(imageView);

Or with the shortcut method and the generated API:

GlideApp.with(fragment)
  .load(url)
  .transforms(new FitCenter(), new YourCustomTransformation())
  .into(imageView);

The order in which you pass transformations to MultiTransformation’s constructor determines the order in which the transformations are applied.

Custom transformations.

Although Glide provides a variety of built in Transformation implementations, you may also implement your own custom Transformations if you need additional functionality.

BitmapTransformation

If you only need to transform Bitmaps, it’s best to start by subclassing BitmapTransformation. BitmapTransformation takes care of a few of the basic things for you, including extracting recycling the original Bitmap if your Transformation returns a new modified Bitmap.

A simple implementation might look something like this:

public class FillSpace extends BitmapTransformation {
    private static final String ID = "com.bumptech.glide.transformations.FillSpace";
    private static final byte[] ID_BYTES = ID.getBytes(Charset.forName("UTF-8"));

    @Override
    public Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {
        if (toTransform.getWidth() == outWidth && toTransform.getHeight() == outHeight) {
            return toTransform;
        }

        return Bitmap.createScaledBitmap(toTransform, outWidth, outHeight, /*filter=*/ true);
    }

    @Override
    public boolean equals(Object o) {
      return o instanceof FillSpace;
    }

    @Override
    public int hashCode() {
      return ID.hashCode();
    }

    @Override
    public void updateDiskCacheKey(MessageDigest messageDigest) {
      messageDigest.update(ID_BYTES);
    }
}

Although your Transformation will almost certainly do something more sophisticated than our example, it should contain the same basic elements and method overrides.

Required methods

In particular, note that there are three methods that you must implement for any Transformation subclass, including BitmapTransformation in order for disk and memory caching to work correctly:

  1. equals()
  2. hashCode()
  3. updateDiskCacheKey

If your Transformation takes no arguments, it’s often easy to just use a static final String containing the fully qualified package name as an id that can form the basis of hashCode() and can be used to update the MessageDigest passed to updateDiskCacheKey(). If your Transformation does take arguments that affect the way the Bitmap is transformed, they must be included in these three methods as well.

For example, Glide’s RoundedCorners Transformation accepts an int that determines the radius of the rounded corners. Its implementations of equals(), hashCode() and updateDiskCacheKey looks like this:

  @Override
  public boolean equals(Object o) {
    if (o instanceof RoundedCorners) {
      RoundedCorners other = (RoundedCorners) o;
      return roundingRadius == other.roundingRadius;
    }
    return false;
  }

  @Override
  public int hashCode() {
    return Util.hashCode(ID.hashCode(),
        Util.hashCode(roundingRadius));
  }

  @Override
  public void updateDiskCacheKey(MessageDigest messageDigest) {
    messageDigest.update(ID_BYTES);

    byte[] radiusData = ByteBuffer.allocate(4).putInt(roundingRadius).array();
    messageDigest.update(radiusData);
  }

The original String id remains as well, but the roundingRadius is included in all three methods as well. The updateDiskCacheKey method here also demonstrates how you can use ByteBuffer to including primitive arguments in your updateDiskCacheKey implementation.

Don’t forget equals()/hashCode()!

It’s worth re-iterating one more time that it’s essential that you implement equals() and hashCode() for memory caching to work correctly. Unfortunately BitmapTransformation and Transformation implementations will compile if those methods are not overridden, but that doesn’t mean they work correctly. We’re exploring options for making using the default equals() and hashCode methods a compile time error in future versions of Glide.

Special Behavior in Glide

Re-using Transformations

Transformations are meant to be stateless. As a result, it should always be safe to re-use a Transformation instance for multiple loads. It’s usually good practice to create a Transformation once and then pass it in to multiple loads.

Automatic Transformations for ImageViews

When you start a load into an ImageView in Glide, Glide may automatically apply either FitCenter or CenterCrop, depending on the ScaleType of the view. If the scale type is CENTER_CROP, Glide will automatically apply the CenterCrop transformation. If the scale type is FIT_CENTER or CENTER_INSIDE, Glide will automatically apply the FitCenter transformation.

You can always override the default transformation by applying a RequestOptions with a Transformation set. In addition, you can ensure no Transformation is automatically applied using dontTransform().

Custom resources

Because Glide 4.0 allows you to specify a super type of the resource you’re going to decode, you may not know exactly what type of transformation to apply. For example, when you use asDrawable() (or just with() since asDrawable() is the default) to ask for a Drawable resource, you may get either the BitmapDrawable subclass, or the GifDrawable subclass.

To ensure any Transformation you add to your RequestOptions is applied, Glide adds your Transformation to a map keyed on the resource class you provide to transform(). When a resource is successfully decoded , Glide uses the map to retrieve a corresponding Transformation.

Glide can apply Bitmap Transformations to BitmapDrawable, GifDrawable, and Bitmap resources, so typically you only need to write and apply Bitmap Transformations. However, if you add additional resource types you may need to consider sub-classing RequestOptions and always applying a Transformation for your custom resource type in addition to the built in Bitmap Transformations.