0
# Glide Image Transformations System
1
2
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.
3
4
## BitmapTransformation Base Class
5
6
The foundation of Glide's transformation system is the abstract `BitmapTransformation` class, which provides the structure for all bitmap-based transformations.
7
8
```java { .api }
9
public abstract class BitmapTransformation implements Transformation<Bitmap> {
10
/**
11
* Transforms the given bitmap
12
* @param pool BitmapPool for recycling bitmaps
13
* @param toTransform The bitmap to transform
14
* @param outWidth Desired output width
15
* @param outHeight Desired output height
16
* @return Transformed bitmap
17
*/
18
protected abstract Bitmap transform(
19
BitmapPool pool,
20
Bitmap toTransform,
21
int outWidth,
22
int outHeight
23
);
24
25
/**
26
* Updates the cache key for this transformation
27
* @param messageDigest The digest to update
28
*/
29
@Override
30
public abstract void updateDiskCacheKey(MessageDigest messageDigest);
31
32
/**
33
* Transforms the resource
34
* @param context Application context
35
* @param resource The resource to transform
36
* @param outWidth Target width
37
* @param outHeight Target height
38
* @return Transformed resource
39
*/
40
@Override
41
public final Resource<Bitmap> transform(
42
Context context,
43
Resource<Bitmap> resource,
44
int outWidth,
45
int outHeight
46
);
47
}
48
```
49
50
## Built-in Transformations
51
52
### Cropping Transformations
53
54
Essential cropping transformations for different scaling behaviors:
55
56
```java { .api }
57
/**
58
* Centers and crops the image to fill the target dimensions
59
* Crops excess pixels from the larger dimension
60
*/
61
public class CenterCrop extends BitmapTransformation {
62
/**
63
* Gets singleton instance
64
*/
65
public static CenterCrop get() {
66
// Implementation returns singleton instance
67
}
68
}
69
70
/**
71
* Centers the image within target bounds without cropping
72
* Scales to fit completely within dimensions
73
*/
74
public class CenterInside extends BitmapTransformation {
75
public static CenterInside get() {
76
// Implementation returns singleton instance
77
}
78
}
79
80
/**
81
* Scales image to fit target dimensions exactly
82
* Centers the image and adds letterboxing if needed
83
*/
84
public class FitCenter extends BitmapTransformation {
85
public static FitCenter get() {
86
// Implementation returns singleton instance
87
}
88
}
89
90
/**
91
* Crops image into a perfect circle
92
* Centers and crops to square, then applies circular mask
93
*/
94
public class CircleCrop extends BitmapTransformation {
95
public static CircleCrop get() {
96
// Implementation returns singleton instance
97
}
98
}
99
```
100
101
### Corner and Shape Transformations
102
103
Specialized transformations for shape modifications:
104
105
```java { .api }
106
/**
107
* Rounds the corners of the bitmap
108
*/
109
public class RoundedCorners extends BitmapTransformation {
110
private final int roundingRadius;
111
112
/**
113
* Creates rounded corners transformation
114
* @param roundingRadius Radius for rounding in pixels
115
*/
116
public RoundedCorners(int roundingRadius) {
117
this.roundingRadius = roundingRadius;
118
}
119
120
@Override
121
protected Bitmap transform(
122
BitmapPool pool,
123
Bitmap toTransform,
124
int outWidth,
125
int outHeight
126
) {
127
// Implementation transforms bitmap with rounded corners
128
}
129
130
@Override
131
public boolean equals(Object other) {
132
// Implementation compares transformations
133
}
134
135
@Override
136
public int hashCode() {
137
// Implementation returns hash code
138
}
139
140
@Override
141
public void updateDiskCacheKey(MessageDigest messageDigest) {
142
// Implementation updates cache key
143
}
144
}
145
146
/**
147
* Rotates the bitmap by specified degrees
148
*/
149
public class Rotate extends BitmapTransformation {
150
private final int degrees;
151
152
/**
153
* Creates rotation transformation
154
* @param degrees Degrees to rotate (multiple of 90)
155
*/
156
public Rotate(int degrees) {
157
this.degrees = degrees;
158
}
159
160
@Override
161
protected Bitmap transform(
162
BitmapPool pool,
163
Bitmap toTransform,
164
int outWidth,
165
int outHeight
166
) {
167
// Implementation rotates bitmap
168
}
169
170
@Override
171
public boolean equals(Object other) {
172
// Implementation compares transformations
173
}
174
175
@Override
176
public int hashCode() {
177
// Implementation returns hash code
178
}
179
}
180
```
181
182
## MultiTransformation Class
183
184
Combine multiple transformations into a single operation for complex effects:
185
186
```java { .api }
187
/**
188
* Applies multiple transformations in sequence
189
*/
190
public class MultiTransformation<T> implements Transformation<T> {
191
private final Transformation<T>[] transformations;
192
193
/**
194
* Creates multi-transformation from varargs
195
* @param transformations Transformations to combine
196
*/
197
@SafeVarargs
198
public MultiTransformation(Transformation<T>... transformations) {
199
this.transformations = transformations;
200
}
201
202
/**
203
* Creates multi-transformation from collection
204
* @param transformationList Collection of transformations
205
*/
206
public MultiTransformation(Collection<Transformation<T>> transformationList) {
207
this.transformations = transformationList.toArray(new Transformation[0]);
208
}
209
210
@Override
211
public Resource<T> transform(
212
Context context,
213
Resource<T> resource,
214
int outWidth,
215
int outHeight
216
) {
217
// Implementation applies transformations in sequence
218
}
219
220
@Override
221
public boolean equals(Object other) {
222
// Implementation compares transformations
223
}
224
225
@Override
226
public int hashCode() {
227
// Implementation returns hash code
228
}
229
230
@Override
231
public void updateDiskCacheKey(MessageDigest messageDigest) {
232
// Implementation updates cache key
233
}
234
}
235
```
236
237
## Custom Transformation Creation
238
239
### Basic Custom Transformation
240
241
Create custom transformations by extending `BitmapTransformation`:
242
243
```java
244
public class GrayscaleTransformation extends BitmapTransformation {
245
246
@Override
247
protected Bitmap transform(
248
BitmapPool pool,
249
Bitmap toTransform,
250
int outWidth,
251
int outHeight
252
) {
253
int width = toTransform.getWidth();
254
int height = toTransform.getHeight();
255
256
Bitmap bitmap = pool.get(width, height, Bitmap.Config.ARGB_8888);
257
bitmap.setHasAlpha(false);
258
259
Canvas canvas = new Canvas(bitmap);
260
Paint paint = new Paint();
261
paint.setAntiAlias(true);
262
263
ColorMatrix colorMatrix = new ColorMatrix();
264
colorMatrix.setSaturation(0f);
265
paint.setColorFilter(new ColorMatrixColorFilter(colorMatrix));
266
267
canvas.drawBitmap(toTransform, 0f, 0f, paint);
268
269
return bitmap;
270
}
271
272
@Override
273
public void updateDiskCacheKey(MessageDigest messageDigest) {
274
messageDigest.update("grayscale_transformation".getBytes(StandardCharsets.UTF_8));
275
}
276
277
@Override
278
public boolean equals(Object other) {
279
return other instanceof GrayscaleTransformation;
280
}
281
282
@Override
283
public int hashCode() {
284
return "grayscale_transformation".hashCode();
285
}
286
}
287
```
288
289
### Parameterized Custom Transformation
290
291
Create transformations with configurable parameters:
292
293
```java
294
public class BlurTransformation extends BitmapTransformation {
295
private final int radius;
296
private final int sampling;
297
298
public BlurTransformation() {
299
this(15, 1);
300
}
301
302
public BlurTransformation(int radius, int sampling) {
303
this.radius = radius;
304
this.sampling = sampling;
305
}
306
307
@Override
308
protected Bitmap transform(
309
BitmapPool pool,
310
Bitmap toTransform,
311
int outWidth,
312
int outHeight
313
) {
314
int width = toTransform.getWidth();
315
int height = toTransform.getHeight();
316
int scaledWidth = width / sampling;
317
int scaledHeight = height / sampling;
318
319
Bitmap scaledBitmap = pool.get(scaledWidth, scaledHeight, Bitmap.Config.ARGB_8888);
320
321
Canvas canvas = new Canvas(scaledBitmap);
322
canvas.scale(1f / sampling, 1f / sampling);
323
Paint paint = new Paint();
324
paint.setFlags(Paint.FILTER_BITMAP_FLAG);
325
canvas.drawBitmap(toTransform, 0f, 0f, paint);
326
327
// Apply blur effect
328
Bitmap blurredBitmap = applyBlur(scaledBitmap, radius);
329
330
return Bitmap.createScaledBitmap(blurredBitmap, width, height, true);
331
}
332
333
private Bitmap applyBlur(Bitmap bitmap, int radius) {
334
// Implementation would use RenderScript or other blur algorithm
335
return bitmap;
336
}
337
338
@Override
339
public void updateDiskCacheKey(MessageDigest messageDigest) {
340
messageDigest.update(("blur_" + radius + sampling).getBytes(StandardCharsets.UTF_8));
341
}
342
343
@Override
344
public boolean equals(Object other) {
345
return other instanceof BlurTransformation &&
346
((BlurTransformation) other).radius == radius &&
347
((BlurTransformation) other).sampling == sampling;
348
}
349
350
@Override
351
public int hashCode() {
352
return Objects.hash("blur_transformation", radius, sampling);
353
}
354
}
355
```
356
357
## Usage Examples
358
359
### Single Transformations
360
361
Apply individual transformations to image requests:
362
363
```java
364
// Center crop transformation
365
Glide.with(context)
366
.load(imageUrl)
367
.centerCrop()
368
.into(imageView);
369
370
// Rounded corners
371
Glide.with(context)
372
.load(imageUrl)
373
.transform(new RoundedCorners(16))
374
.into(imageView);
375
376
// Circle crop
377
Glide.with(context)
378
.load(imageUrl)
379
.circleCrop()
380
.into(imageView);
381
382
// Custom transformation
383
Glide.with(context)
384
.load(imageUrl)
385
.transform(new GrayscaleTransformation())
386
.into(imageView);
387
```
388
389
### Multiple Transformations
390
391
Combine multiple transformations for complex effects:
392
393
```java
394
// Using MultiTransformation
395
Glide.with(context)
396
.load(imageUrl)
397
.transform(
398
new MultiTransformation<Bitmap>(
399
new CenterCrop(),
400
new RoundedCorners(20)
401
)
402
)
403
.into(imageView);
404
405
// Multiple custom transformations
406
Glide.with(context)
407
.load(imageUrl)
408
.transform(
409
new MultiTransformation<Bitmap>(
410
new CenterCrop(),
411
new BlurTransformation(25, 1),
412
new GrayscaleTransformation()
413
)
414
)
415
.into(imageView);
416
417
// Using varargs syntax
418
Glide.with(context)
419
.load(imageUrl)
420
.transform(
421
new CenterCrop(),
422
new RoundedCorners(12),
423
new GrayscaleTransformation()
424
)
425
.into(imageView);
426
```
427
428
### RequestOptions with Transformations
429
430
Apply transformations through RequestOptions for reusability:
431
432
```java
433
RequestOptions thumbnailOptions = new RequestOptions()
434
.transform(
435
new MultiTransformation<Bitmap>(
436
new CenterCrop(),
437
new RoundedCorners(8)
438
)
439
)
440
.override(200, 200);
441
442
RequestOptions profileImageOptions = new RequestOptions()
443
.circleCrop()
444
.placeholder(R.drawable.default_avatar)
445
.error(R.drawable.avatar_error);
446
447
// Apply to multiple requests
448
Glide.with(context)
449
.load(thumbnailUrl)
450
.apply(thumbnailOptions)
451
.into(thumbnailView);
452
453
Glide.with(context)
454
.load(profileUrl)
455
.apply(profileImageOptions)
456
.into(profileView);
457
```
458
459
## Advanced Transformation Scenarios
460
461
### Conditional Transformations
462
463
Apply different transformations based on conditions:
464
465
```java
466
public class ConditionalTransformationActivity extends AppCompatActivity {
467
468
public void loadImageWithConditionalTransform(String imageUrl, boolean isProfile) {
469
Transformation<Bitmap> transformation;
470
if (isProfile) {
471
transformation = new MultiTransformation<Bitmap>(
472
new CenterCrop(),
473
new CircleCrop()
474
);
475
} else {
476
transformation = new MultiTransformation<Bitmap>(
477
new CenterCrop(),
478
new RoundedCorners(12)
479
);
480
}
481
482
Glide.with(this)
483
.load(imageUrl)
484
.transform(transformation)
485
.into(imageView);
486
}
487
}
488
```
489
490
### Transformation Caching
491
492
Optimize performance with proper cache key implementation:
493
494
```java
495
public class ColorFilterTransformation extends BitmapTransformation {
496
private final ColorMatrix colorMatrix;
497
private final String id;
498
499
public ColorFilterTransformation(ColorMatrix colorMatrix) {
500
this.colorMatrix = colorMatrix;
501
this.id = "color_filter_" + System.currentTimeMillis();
502
}
503
504
@Override
505
protected Bitmap transform(
506
BitmapPool pool,
507
Bitmap toTransform,
508
int outWidth,
509
int outHeight
510
) {
511
Bitmap bitmap = pool.get(toTransform.getWidth(), toTransform.getHeight(), toTransform.getConfig());
512
513
Canvas canvas = new Canvas(bitmap);
514
Paint paint = new Paint();
515
paint.setColorFilter(new ColorMatrixColorFilter(colorMatrix));
516
canvas.drawBitmap(toTransform, 0f, 0f, paint);
517
518
return bitmap;
519
}
520
521
@Override
522
public void updateDiskCacheKey(MessageDigest messageDigest) {
523
messageDigest.update(id.getBytes(StandardCharsets.UTF_8));
524
}
525
526
@Override
527
public boolean equals(Object other) {
528
return other instanceof ColorFilterTransformation &&
529
((ColorFilterTransformation) other).colorMatrix.equals(colorMatrix);
530
}
531
532
@Override
533
public int hashCode() {
534
return Objects.hash(id, colorMatrix);
535
}
536
}
537
```
538
539
### Performance Optimization
540
541
Optimize transformations for memory and performance:
542
543
```java
544
public class OptimizedRoundedCornersTransformation extends BitmapTransformation {
545
private final int radius;
546
547
// Cache paint and path objects to avoid allocation
548
private final Paint paint;
549
private final Path path;
550
551
public OptimizedRoundedCornersTransformation(int radius) {
552
this.radius = radius;
553
this.paint = new Paint(Paint.ANTI_ALIAS_FLAG);
554
this.paint.setShader(null);
555
this.path = new Path();
556
}
557
558
@Override
559
protected Bitmap transform(
560
BitmapPool pool,
561
Bitmap toTransform,
562
int outWidth,
563
int outHeight
564
) {
565
int width = toTransform.getWidth();
566
int height = toTransform.getHeight();
567
568
Bitmap bitmap = pool.get(width, height, Bitmap.Config.ARGB_8888);
569
bitmap.setHasAlpha(true);
570
571
Canvas canvas = new Canvas(bitmap);
572
573
// Reuse path object
574
path.reset();
575
path.addRoundRect(
576
new RectF(0f, 0f, (float) width, (float) height),
577
(float) radius,
578
(float) radius,
579
Path.Direction.CW
580
);
581
582
canvas.clipPath(path);
583
canvas.drawBitmap(toTransform, 0f, 0f, paint);
584
585
return bitmap;
586
}
587
588
@Override
589
public void updateDiskCacheKey(MessageDigest messageDigest) {
590
messageDigest.update(("optimized_rounded_corners_" + radius).getBytes());
591
}
592
593
@Override
594
public boolean equals(Object other) {
595
return other instanceof OptimizedRoundedCornersTransformation &&
596
((OptimizedRoundedCornersTransformation) other).radius == radius;
597
}
598
599
@Override
600
public int hashCode() {
601
return Objects.hash("optimized_rounded_corners", radius);
602
}
603
}
604
```
605
606
## Best Practices
607
608
### Transformation Guidelines
609
610
1. **Memory Management**: Always use the provided `BitmapPool` to recycle bitmaps
611
2. **Cache Keys**: Implement proper `updateDiskCacheKey()` for cache invalidation
612
3. **Equality**: Override `equals()` and `hashCode()` for proper comparison
613
4. **Immutability**: Keep transformations immutable and thread-safe
614
5. **Performance**: Cache expensive objects like Paint and Path instances
615
616
### Common Patterns
617
618
```java
619
// Reusable transformation options
620
public class TransformationPresets {
621
public static final RequestOptions PROFILE_IMAGE = new RequestOptions()
622
.circleCrop()
623
.placeholder(R.drawable.default_avatar)
624
.override(100, 100);
625
626
public static final RequestOptions THUMBNAIL = new RequestOptions()
627
.centerCrop()
628
.transform(new RoundedCorners(8))
629
.override(200, 200);
630
631
public static final RequestOptions BANNER = new RequestOptions()
632
.centerCrop()
633
.transform(new RoundedCorners(16));
634
}
635
636
// Apply transformations conditionally
637
public void loadWithStyle(String url, ImageStyle style) {
638
RequestOptions options;
639
switch (style) {
640
case PROFILE:
641
options = TransformationPresets.PROFILE_IMAGE;
642
break;
643
case THUMBNAIL:
644
options = TransformationPresets.THUMBNAIL;
645
break;
646
case BANNER:
647
options = TransformationPresets.BANNER;
648
break;
649
default:
650
options = new RequestOptions();
651
}
652
653
Glide.with(context)
654
.load(url)
655
.apply(options)
656
.into(imageView);
657
}
658
```
659
660
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.