CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-com-github-bumptech-glide--glide

A fast and efficient open source media management and image loading framework for Android that wraps media decoding, memory and disk caching, and resource pooling into a simple and easy to use interface.

Pending
Overview
Eval results
Files

transformations.mddocs/

Glide Image Transformations System

The Glide transformations system provides powerful image manipulation capabilities through a flexible and extensible architecture. Built around the BitmapTransformation base class, it includes comprehensive built-in transformations for common operations like cropping and scaling, plus a robust framework for creating custom transformations and combining multiple effects.

BitmapTransformation Base Class

The foundation of Glide's transformation system is the abstract BitmapTransformation class, which provides the structure for all bitmap-based transformations.

public abstract class BitmapTransformation implements Transformation<Bitmap> {
    /**
     * Transforms the given bitmap
     * @param pool BitmapPool for recycling bitmaps
     * @param toTransform The bitmap to transform
     * @param outWidth Desired output width
     * @param outHeight Desired output height
     * @return Transformed bitmap
     */
    protected abstract Bitmap transform(
        BitmapPool pool,
        Bitmap toTransform,
        int outWidth,
        int outHeight
    );

    /**
     * Updates the cache key for this transformation
     * @param messageDigest The digest to update
     */
    @Override
    public abstract void updateDiskCacheKey(MessageDigest messageDigest);

    /**
     * Transforms the resource
     * @param context Application context
     * @param resource The resource to transform
     * @param outWidth Target width
     * @param outHeight Target height
     * @return Transformed resource
     */
    @Override
    public final Resource<Bitmap> transform(
        Context context,
        Resource<Bitmap> resource,
        int outWidth,
        int outHeight
    );
}

Built-in Transformations

Cropping Transformations

Essential cropping transformations for different scaling behaviors:

/**
 * Centers and crops the image to fill the target dimensions
 * Crops excess pixels from the larger dimension
 */
public class CenterCrop extends BitmapTransformation {
    /**
     * Gets singleton instance
     */
    public static CenterCrop get() {
        // Implementation returns singleton instance
    }
}

/**
 * Centers the image within target bounds without cropping
 * Scales to fit completely within dimensions
 */
public class CenterInside extends BitmapTransformation {
    public static CenterInside get() {
        // Implementation returns singleton instance
    }
}

/**
 * Scales image to fit target dimensions exactly
 * Centers the image and adds letterboxing if needed
 */
public class FitCenter extends BitmapTransformation {
    public static FitCenter get() {
        // Implementation returns singleton instance
    }
}

/**
 * Crops image into a perfect circle
 * Centers and crops to square, then applies circular mask
 */
public class CircleCrop extends BitmapTransformation {
    public static CircleCrop get() {
        // Implementation returns singleton instance
    }
}

Corner and Shape Transformations

Specialized transformations for shape modifications:

/**
 * Rounds the corners of the bitmap
 */
public class RoundedCorners extends BitmapTransformation {
    private final int roundingRadius;
    
    /**
     * Creates rounded corners transformation
     * @param roundingRadius Radius for rounding in pixels
     */
    public RoundedCorners(int roundingRadius) {
        this.roundingRadius = roundingRadius;
    }

    @Override
    protected Bitmap transform(
        BitmapPool pool,
        Bitmap toTransform,
        int outWidth,
        int outHeight
    ) {
        // Implementation transforms bitmap with rounded corners
    }

    @Override
    public boolean equals(Object other) {
        // Implementation compares transformations
    }
    
    @Override
    public int hashCode() {
        // Implementation returns hash code
    }
    
    @Override
    public void updateDiskCacheKey(MessageDigest messageDigest) {
        // Implementation updates cache key
    }
}

/**
 * Rotates the bitmap by specified degrees
 */
public class Rotate extends BitmapTransformation {
    private final int degrees;
    
    /**
     * Creates rotation transformation
     * @param degrees Degrees to rotate (multiple of 90)
     */
    public Rotate(int degrees) {
        this.degrees = degrees;
    }

    @Override
    protected Bitmap transform(
        BitmapPool pool,
        Bitmap toTransform,
        int outWidth,
        int outHeight
    ) {
        // Implementation rotates bitmap
    }

    @Override
    public boolean equals(Object other) {
        // Implementation compares transformations
    }
    
    @Override
    public int hashCode() {
        // Implementation returns hash code
    }
}

MultiTransformation Class

Combine multiple transformations into a single operation for complex effects:

/**
 * Applies multiple transformations in sequence
 */
public class MultiTransformation<T> implements Transformation<T> {
    private final Transformation<T>[] transformations;
    
    /**
     * Creates multi-transformation from varargs
     * @param transformations Transformations to combine
     */
    @SafeVarargs
    public MultiTransformation(Transformation<T>... transformations) {
        this.transformations = transformations;
    }
    
    /**
     * Creates multi-transformation from collection
     * @param transformationList Collection of transformations
     */
    public MultiTransformation(Collection<Transformation<T>> transformationList) {
        this.transformations = transformationList.toArray(new Transformation[0]);
    }

    @Override
    public Resource<T> transform(
        Context context,
        Resource<T> resource,
        int outWidth,
        int outHeight
    ) {
        // Implementation applies transformations in sequence
    }

    @Override
    public boolean equals(Object other) {
        // Implementation compares transformations
    }
    
    @Override
    public int hashCode() {
        // Implementation returns hash code
    }
    
    @Override
    public void updateDiskCacheKey(MessageDigest messageDigest) {
        // Implementation updates cache key
    }
}

Custom Transformation Creation

Basic Custom Transformation

Create custom transformations by extending BitmapTransformation:

public class GrayscaleTransformation extends BitmapTransformation {
    
    @Override
    protected Bitmap transform(
        BitmapPool pool,
        Bitmap toTransform,
        int outWidth,
        int outHeight
    ) {
        int width = toTransform.getWidth();
        int height = toTransform.getHeight();
        
        Bitmap bitmap = pool.get(width, height, Bitmap.Config.ARGB_8888);
        bitmap.setHasAlpha(false);
        
        Canvas canvas = new Canvas(bitmap);
        Paint paint = new Paint();
        paint.setAntiAlias(true);
        
        ColorMatrix colorMatrix = new ColorMatrix();
        colorMatrix.setSaturation(0f);
        paint.setColorFilter(new ColorMatrixColorFilter(colorMatrix));
        
        canvas.drawBitmap(toTransform, 0f, 0f, paint);
        
        return bitmap;
    }
    
    @Override
    public void updateDiskCacheKey(MessageDigest messageDigest) {
        messageDigest.update("grayscale_transformation".getBytes(StandardCharsets.UTF_8));
    }
    
    @Override
    public boolean equals(Object other) {
        return other instanceof GrayscaleTransformation;
    }
    
    @Override
    public int hashCode() {
        return "grayscale_transformation".hashCode();
    }
}

Parameterized Custom Transformation

Create transformations with configurable parameters:

public class BlurTransformation extends BitmapTransformation {
    private final int radius;
    private final int sampling;
    
    public BlurTransformation() {
        this(15, 1);
    }
    
    public BlurTransformation(int radius, int sampling) {
        this.radius = radius;
        this.sampling = sampling;
    }
    
    @Override
    protected Bitmap transform(
        BitmapPool pool,
        Bitmap toTransform,
        int outWidth,
        int outHeight
    ) {
        int width = toTransform.getWidth();
        int height = toTransform.getHeight();
        int scaledWidth = width / sampling;
        int scaledHeight = height / sampling;
        
        Bitmap scaledBitmap = pool.get(scaledWidth, scaledHeight, Bitmap.Config.ARGB_8888);
        
        Canvas canvas = new Canvas(scaledBitmap);
        canvas.scale(1f / sampling, 1f / sampling);
        Paint paint = new Paint();
        paint.setFlags(Paint.FILTER_BITMAP_FLAG);
        canvas.drawBitmap(toTransform, 0f, 0f, paint);
        
        // Apply blur effect
        Bitmap blurredBitmap = applyBlur(scaledBitmap, radius);
        
        return Bitmap.createScaledBitmap(blurredBitmap, width, height, true);
    }
    
    private Bitmap applyBlur(Bitmap bitmap, int radius) {
        // Implementation would use RenderScript or other blur algorithm
        return bitmap;
    }
    
    @Override
    public void updateDiskCacheKey(MessageDigest messageDigest) {
        messageDigest.update(("blur_" + radius + sampling).getBytes(StandardCharsets.UTF_8));
    }
    
    @Override
    public boolean equals(Object other) {
        return other instanceof BlurTransformation && 
               ((BlurTransformation) other).radius == radius && 
               ((BlurTransformation) other).sampling == sampling;
    }
    
    @Override
    public int hashCode() {
        return Objects.hash("blur_transformation", radius, sampling);
    }
}

Usage Examples

Single Transformations

Apply individual transformations to image requests:

// Center crop transformation
Glide.with(context)
    .load(imageUrl)
    .centerCrop()
    .into(imageView);

// Rounded corners
Glide.with(context)
    .load(imageUrl)
    .transform(new RoundedCorners(16))
    .into(imageView);

// Circle crop
Glide.with(context)
    .load(imageUrl)
    .circleCrop()
    .into(imageView);

// Custom transformation
Glide.with(context)
    .load(imageUrl)
    .transform(new GrayscaleTransformation())
    .into(imageView);

Multiple Transformations

Combine multiple transformations for complex effects:

// Using MultiTransformation
Glide.with(context)
    .load(imageUrl)
    .transform(
        new MultiTransformation<Bitmap>(
            new CenterCrop(),
            new RoundedCorners(20)
        )
    )
    .into(imageView);

// Multiple custom transformations
Glide.with(context)
    .load(imageUrl)
    .transform(
        new MultiTransformation<Bitmap>(
            new CenterCrop(),
            new BlurTransformation(25, 1),
            new GrayscaleTransformation()
        )
    )
    .into(imageView);

// Using varargs syntax
Glide.with(context)
    .load(imageUrl)
    .transform(
        new CenterCrop(),
        new RoundedCorners(12),
        new GrayscaleTransformation()
    )
    .into(imageView);

RequestOptions with Transformations

Apply transformations through RequestOptions for reusability:

RequestOptions thumbnailOptions = new RequestOptions()
    .transform(
        new MultiTransformation<Bitmap>(
            new CenterCrop(),
            new RoundedCorners(8)
        )
    )
    .override(200, 200);

RequestOptions profileImageOptions = new RequestOptions()
    .circleCrop()
    .placeholder(R.drawable.default_avatar)
    .error(R.drawable.avatar_error);

// Apply to multiple requests
Glide.with(context)
    .load(thumbnailUrl)
    .apply(thumbnailOptions)
    .into(thumbnailView);

Glide.with(context)
    .load(profileUrl)
    .apply(profileImageOptions)
    .into(profileView);

Advanced Transformation Scenarios

Conditional Transformations

Apply different transformations based on conditions:

public class ConditionalTransformationActivity extends AppCompatActivity {
    
    public void loadImageWithConditionalTransform(String imageUrl, boolean isProfile) {
        Transformation<Bitmap> transformation;
        if (isProfile) {
            transformation = new MultiTransformation<Bitmap>(
                new CenterCrop(),
                new CircleCrop()
            );
        } else {
            transformation = new MultiTransformation<Bitmap>(
                new CenterCrop(),
                new RoundedCorners(12)
            );
        }
        
        Glide.with(this)
            .load(imageUrl)
            .transform(transformation)
            .into(imageView);
    }
}

Transformation Caching

Optimize performance with proper cache key implementation:

public class ColorFilterTransformation extends BitmapTransformation {
    private final ColorMatrix colorMatrix;
    private final String id;
    
    public ColorFilterTransformation(ColorMatrix colorMatrix) {
        this.colorMatrix = colorMatrix;
        this.id = "color_filter_" + System.currentTimeMillis();
    }
    
    @Override
    protected Bitmap transform(
        BitmapPool pool,
        Bitmap toTransform,
        int outWidth,
        int outHeight
    ) {
        Bitmap bitmap = pool.get(toTransform.getWidth(), toTransform.getHeight(), toTransform.getConfig());
        
        Canvas canvas = new Canvas(bitmap);
        Paint paint = new Paint();
        paint.setColorFilter(new ColorMatrixColorFilter(colorMatrix));
        canvas.drawBitmap(toTransform, 0f, 0f, paint);
        
        return bitmap;
    }
    
    @Override
    public void updateDiskCacheKey(MessageDigest messageDigest) {
        messageDigest.update(id.getBytes(StandardCharsets.UTF_8));
    }
    
    @Override
    public boolean equals(Object other) {
        return other instanceof ColorFilterTransformation && 
               ((ColorFilterTransformation) other).colorMatrix.equals(colorMatrix);
    }
    
    @Override
    public int hashCode() {
        return Objects.hash(id, colorMatrix);
    }
}

Performance Optimization

Optimize transformations for memory and performance:

public class OptimizedRoundedCornersTransformation extends BitmapTransformation {
    private final int radius;
    
    // Cache paint and path objects to avoid allocation
    private final Paint paint;
    private final Path path;
    
    public OptimizedRoundedCornersTransformation(int radius) {
        this.radius = radius;
        this.paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        this.paint.setShader(null);
        this.path = new Path();
    }
    
    @Override
    protected Bitmap transform(
        BitmapPool pool,
        Bitmap toTransform,
        int outWidth,
        int outHeight
    ) {
        int width = toTransform.getWidth();
        int height = toTransform.getHeight();
        
        Bitmap bitmap = pool.get(width, height, Bitmap.Config.ARGB_8888);
        bitmap.setHasAlpha(true);
        
        Canvas canvas = new Canvas(bitmap);
        
        // Reuse path object
        path.reset();
        path.addRoundRect(
            new RectF(0f, 0f, (float) width, (float) height),
            (float) radius,
            (float) radius,
            Path.Direction.CW
        );
        
        canvas.clipPath(path);
        canvas.drawBitmap(toTransform, 0f, 0f, paint);
        
        return bitmap;
    }
    
    @Override
    public void updateDiskCacheKey(MessageDigest messageDigest) {
        messageDigest.update(("optimized_rounded_corners_" + radius).getBytes());
    }
    
    @Override
    public boolean equals(Object other) {
        return other instanceof OptimizedRoundedCornersTransformation && 
               ((OptimizedRoundedCornersTransformation) other).radius == radius;
    }
    
    @Override
    public int hashCode() {
        return Objects.hash("optimized_rounded_corners", radius);
    }
}

Best Practices

Transformation Guidelines

  1. Memory Management: Always use the provided BitmapPool to recycle bitmaps
  2. Cache Keys: Implement proper updateDiskCacheKey() for cache invalidation
  3. Equality: Override equals() and hashCode() for proper comparison
  4. Immutability: Keep transformations immutable and thread-safe
  5. Performance: Cache expensive objects like Paint and Path instances

Common Patterns

// Reusable transformation options
public class TransformationPresets {
    public static final RequestOptions PROFILE_IMAGE = new RequestOptions()
        .circleCrop()
        .placeholder(R.drawable.default_avatar)
        .override(100, 100);
    
    public static final RequestOptions THUMBNAIL = new RequestOptions()
        .centerCrop()
        .transform(new RoundedCorners(8))
        .override(200, 200);
    
    public static final RequestOptions BANNER = new RequestOptions()
        .centerCrop()
        .transform(new RoundedCorners(16));
}

// Apply transformations conditionally
public void loadWithStyle(String url, ImageStyle style) {
    RequestOptions options;
    switch (style) {
        case PROFILE:
            options = TransformationPresets.PROFILE_IMAGE;
            break;
        case THUMBNAIL:
            options = TransformationPresets.THUMBNAIL;
            break;
        case BANNER:
            options = TransformationPresets.BANNER;
            break;
        default:
            options = new RequestOptions();
    }
    
    Glide.with(context)
        .load(url)
        .apply(options)
        .into(imageView);
}

This comprehensive transformation system allows for both simple built-in effects and complex custom transformations, providing the flexibility needed for any image manipulation scenario while maintaining optimal performance and memory management.

Install with Tessl CLI

npx tessl i tessl/maven-com-github-bumptech-glide--glide

docs

caching-strategies.md

error-handling-debugging.md

index.md

modules-configuration.md

request-configuration.md

request-management.md

targets-loading.md

transformations.md

transitions-animations.md

tile.json