or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

caching-strategies.mderror-handling-debugging.mdindex.mdmodules-configuration.mdrequest-configuration.mdrequest-management.mdtargets-loading.mdtransformations.mdtransitions-animations.md

transformations.mddocs/

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.