前言
通过前面Glide系列文章的阅读,相信大家对Glide的核心流程及部分关键模块已经有了较为深入的了解,本节我们继续深入介绍Glide中的重要模块。在平时的开发需求中,有时需要对原图片进行一定的处理后再显示出来,以产生更加丰富的展示效果,比如对图片进行裁剪,高斯模糊,圆角处理,美化处理等等,如何添加这些个性化的图片需求,Glide框架提供了相关的接口,可以轻松接入我们需要的图片变换功能。
流程回顾
在讲这部分前,先思考一下,如果我们需要对图片进行显示效果的处理,首先应该拿到原图片,对图片进行相应的处理操作后将结果返回给后续流程,因此图片变换的处理时机应在对数据流解码之后,回顾一下前面章节Glide图片加载的部分流程,如下图所示

由流程图中可以看到,DecodeJob 在发起网络请求获取到数据流之后,会对数据流进行解码处理得到bitmap数据,然后调用到transformEncodeAndTranscode方法,这个方法中先对图像进行变换处理,使用到图像变换器transformation中的transform方法,在这里面完成对图像相应的处理流程,看下相关源码。
private Resource<Z> transformEncodeAndTranscode(Resource<T> decoded) {
long startTime = LogTime.getLogTime();
Resource<T> transformed = transform(decoded); // 调用变换方法,对图像进行处理
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Transformed resource from source", startTime);
}
writeTransformedToCache(transformed);
startTime = LogTime.getLogTime();
Resource<Z> result = transcode(transformed);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Transcoded transformed from source", startTime);
}
return result;
}
基本使用
那这个图像变换器transformation是如何设置的呢,设置方法非常简单如下代码所示,只需要调用transform方法传入所需要的图像变换器即可,可以根据需要传入一个或多个图像变换器:
Glide.with(this)
.load(url)
.transform(...) // 设置图像变换器
.into(imageView);
参考前面对Glide核心流程的源码分析,调用load方法之后会返回一个DrawableTypeRequest类型的对象,transform最终调用到其父类GenericRequestBuilder 中的transform方法,用于设置图像变换器参数,并将其封装到GenericRequest中, 供图像解码之后的流程使用,如下部分源码所示:
public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> transform(
Transformation<ResourceType>... transformations) {
isTransformationSet = true;
if (transformations.length == 1) {
transformation = transformations[0]; // 保存设置的图像变换参数
} else {
transformation = new MultiTransformation<ResourceType>(transformations);
}
return this;
}
private Request obtainRequest(Target<TranscodeType> target, float sizeMultiplier, Priority priority,
RequestCoordinator requestCoordinator) {
return GenericRequest.obtain(
loadProvider,
model,
signature,
context,
priority,
target,
sizeMultiplier,
placeholderDrawable,
placeholderId,
errorPlaceholder,
errorId,
fallbackDrawable,
fallbackResource,
requestListener,
requestCoordinator,
glide.getEngine(),
transformation,
transcodeClass,
isCacheable,
animationFactory,
overrideWidth,
overrideHeight,
diskCacheStrategy);
}
自定义图像变换
可以看到图像变换器的设置方法是非常简单的,图像变换最关键的是处理算法的实现,如何来实现一个具体的图像变换功能呢,Glide中给我们提供了几个现成的图片变换功能,我们以Glide中自带的图形变换功能 CenterCrop作为例子来看如何实现一个图像变换器,并应用到图像加载中。CenterCrop的源码如下所示:
public class CenterCrop extends BitmapTransformation {
public CenterCrop(Context context) {
super(context);
}
public CenterCrop(BitmapPool bitmapPool) {
super(bitmapPool);
}
@SuppressWarnings("PMD.CompareObjectsWithEquals")
@Override
protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {
final Bitmap toReuse = pool.get(outWidth, outHeight, toTransform.getConfig() != null
? toTransform.getConfig() : Bitmap.Config.ARGB_8888); // 获取可复用的bitmap对象
Bitmap transformed = TransformationUtils.centerCrop(toReuse, toTransform, outWidth, outHeight); // 对原始bitmap进行图像变换处理
if (toReuse != null && toReuse != transformed && !pool.put(toReuse)) {
toReuse.recycle();
}
return transformed;
}
@Override
public String getId() {
return "CenterCrop.com.bumptech.glide.load.resource.bitmap"; // 图像变换的唯一标识
}
}
centercrop是一种图像裁剪算法,等比例缩放原图直到填满ImageView为止,对多出来的部分进行裁剪。ImageView 完全填充,图像可能会被裁减掉一部分。Glide 中的CenterCrop 继承自 BitmapTransformation 类 (静态图像的变换类型都是继承BitmapTransformation)。 主要实现了transform 方法,在transform方法中完成对图像裁剪的计算和处理。另外还实现了getId方法,用来区分不同的变换类型。我们继续看transform方法,transform方法中共传入四个参数,分别是用于bitmap复用的bitmapool,图像变换前的原图 toTransform, 指定的变换后的图像宽高(可以通过override方法来设置)。在centercrop变换中,首先从bitmappool中取出一个可复用的bitmap,用于保存变换后的bitmap,(这里穿插一句,为了防止频繁创建bitmap对象而产生大量的内存消耗,Glide中使用 bitmappool来对bitmap进行复用,在平时对bitmap的使用中,从内存优化的角度我们可以借鉴这一做法),然后将这些参数传入TransformationUtils.centerCrop 方法,在这里面根据设置的尺寸及图像原始宽高进行计算,完成的图像裁切功能,如下源码所示:
public static Bitmap centerCrop(Bitmap recycled, Bitmap toCrop, int width, int height) {
if (toCrop == null) {
return null;
} else if (toCrop.getWidth() == width && toCrop.getHeight() == height) {
return toCrop;
}
final float scale;
float dx = 0, dy = 0;
Matrix m = new Matrix();
// 根据原图尺寸及所需要展示的尺寸进行裁剪位置计算
if (toCrop.getWidth() * height > width * toCrop.getHeight()) {
scale = (float) height / (float) toCrop.getHeight();
dx = (width - toCrop.getWidth() * scale) * 0.5f;
} else {
scale = (float) width / (float) toCrop.getWidth();
dy = (height - toCrop.getHeight() * scale) * 0.5f;
}
m.setScale(scale, scale);
m.postTranslate((int) (dx + 0.5f), (int) (dy + 0.5f));
final Bitmap result;
if (recycled != null) {
result = recycled;
} else {
result = Bitmap.createBitmap(width, height, getSafeConfig(toCrop));
}
TransformationUtils.setAlpha(toCrop, result);
Canvas canvas = new Canvas(result);
Paint paint = new Paint(PAINT_FLAGS);
canvas.drawBitmap(toCrop, m, paint);
return result;
}
图像变换开源库
由此可见,实现一个图像变换器,只需要继承BitmapTransformation 类 (静态图像的变换类型都是继承BitmapTransformation)。 实现transform 方法和getid方法。图片变换的需求多种多样,如果我们想要丰富的图像展示效果,也不必全部自己来研究图像处理算法实现。目前已经有非常多Glide图片变换的开源库可以直接使用,比较全面的是glide-transformations这个库,实现了非常丰富的图片变换效果,例如裁剪变换、颜色变换、模糊变换等等,glide-transformations的GitHub地址是 https://github.com/wasabeef/glide-transformations 。这可以看一下部分效果:

这个库的使用也非常简单,在app/build.gradle文件当中添加如下依赖:
dependencies {
compile 'jp.wasabeef:glide-transformations:2.0.2'
}
然后就可以开心的玩耍了,例如对图像进行模糊处理只需如下代码即可:
Glide.with(this)
.load(url)
.transform(new BlurTransformation(this,20))
.into(imageView);
使用图像颜色滤镜效果:
Glide.with(this)
.load(url)
.transform(new ColorFilterTransformation(this, 0x7900CCCC))
.into(imageView);
至此对Glide图像变换这一部分的内容就讲解完了,对自定义图像变换模块以及如何使用图像变换功能进行了详细的介绍。后续我们会继续深入介绍Glide关键模块知识,欢迎继续关注。
网友评论