Transformations
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
Glide.with(fragment)
.load(url)
.fitCenter()
.into(imageView);
Or with RequestOptions
:
RequestOptions options = new RequestOptions();
options.centerCrop();
Glide.with(fragment)
.load(url)
.apply(options)
.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.
Glide.with(fragment)
.load(url)
.transform(new MultiTransformation(new FitCenter(), new YourCustomTransformation())
.into(imageView);
Or with the shortcut method:
Glide.with(fragment)
.load(url)
.transform(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 Transformation
s if you need additional functionality.
BitmapTransformation
If you only need to transform Bitmap
s, 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:
equals()
hashCode()
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
.