前言
通過(guò)前面Glide系列文章的閱讀,相信大家對(duì)Glide的核心流程及部分關(guān)鍵模塊已經(jīng)有了較為深入的了解医舆,本節(jié)我們繼續(xù)深入介紹Glide中的重要模塊嘉汰。在平時(shí)的開(kāi)發(fā)需求中皿曲,有時(shí)需要對(duì)原圖片進(jìn)行一定的處理后再顯示出來(lái),以產(chǎn)生更加豐富的展示效果粤铭,比如對(duì)圖片進(jìn)行裁剪挖胃,高斯模糊,圓角處理梆惯,美化處理等等酱鸭,如何添加這些個(gè)性化的圖片需求,Glide框架提供了相關(guān)的接口加袋,可以輕松接入我們需要的圖片變換功能凛辣。
流程回顧
在講這部分前,先思考一下职烧,如果我們需要對(duì)圖片進(jìn)行顯示效果的處理扁誓,首先應(yīng)該拿到原圖片,對(duì)圖片進(jìn)行相應(yīng)的處理操作后將結(jié)果返回給后續(xù)流程蚀之,因此圖片變換的處理時(shí)機(jī)應(yīng)在對(duì)數(shù)據(jù)流解碼之后蝗敢,回顧一下前面章節(jié)Glide圖片加載的部分流程,如下圖所示
由流程圖中可以看到足删,DecodeJob 在發(fā)起網(wǎng)絡(luò)請(qǐng)求獲取到數(shù)據(jù)流之后寿谴,會(huì)對(duì)數(shù)據(jù)流進(jìn)行解碼處理得到bitmap數(shù)據(jù),然后調(diào)用到transformEncodeAndTranscode方法失受,這個(gè)方法中先對(duì)圖像進(jìn)行變換處理讶泰,使用到圖像變換器transformation中的transform方法咏瑟,在這里面完成對(duì)圖像相應(yīng)的處理流程,看下相關(guān)源碼痪署。
private Resource<Z> transformEncodeAndTranscode(Resource<T> decoded) {
long startTime = LogTime.getLogTime();
Resource<T> transformed = transform(decoded); // 調(diào)用變換方法码泞,對(duì)圖像進(jìn)行處理
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;
}
基本使用
那這個(gè)圖像變換器transformation是如何設(shè)置的呢,設(shè)置方法非常簡(jiǎn)單如下代碼所示狼犯,只需要調(diào)用transform方法傳入所需要的圖像變換器即可余寥,可以根據(jù)需要傳入一個(gè)或多個(gè)圖像變換器:
Glide.with(this)
.load(url)
.transform(...) // 設(shè)置圖像變換器
.into(imageView);
參考前面對(duì)Glide核心流程的源碼分析,調(diào)用load方法之后會(huì)返回一個(gè)DrawableTypeRequest類型的對(duì)象悯森,transform最終調(diào)用到其父類GenericRequestBuilder 中的transform方法宋舷,用于設(shè)置圖像變換器參數(shù),并將其封裝到GenericRequest中瓢姻, 供圖像解碼之后的流程使用祝蝠,如下部分源碼所示:
public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> transform(
Transformation<ResourceType>... transformations) {
isTransformationSet = true;
if (transformations.length == 1) {
transformation = transformations[0]; // 保存設(shè)置的圖像變換參數(shù)
} 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);
}
自定義圖像變換
可以看到圖像變換器的設(shè)置方法是非常簡(jiǎn)單的,圖像變換最關(guān)鍵的是處理算法的實(shí)現(xiàn)汹来,如何來(lái)實(shí)現(xiàn)一個(gè)具體的圖像變換功能呢续膳,Glide中給我們提供了幾個(gè)現(xiàn)成的圖片變換功能,我們以Glide中自帶的圖形變換功能 CenterCrop作為例子來(lái)看如何實(shí)現(xiàn)一個(gè)圖像變換器收班,并應(yīng)用到圖像加載中坟岔。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); // 獲取可復(fù)用的bitmap對(duì)象
Bitmap transformed = TransformationUtils.centerCrop(toReuse, toTransform, outWidth, outHeight); // 對(duì)原始bitmap進(jìn)行圖像變換處理
if (toReuse != null && toReuse != transformed && !pool.put(toReuse)) {
toReuse.recycle();
}
return transformed;
}
@Override
public String getId() {
return "CenterCrop.com.bumptech.glide.load.resource.bitmap"; // 圖像變換的唯一標(biāo)識(shí)
}
}
centercrop是一種圖像裁剪算法,等比例縮放原圖直到填滿ImageView為止摔桦,對(duì)多出來(lái)的部分進(jìn)行裁剪社付。ImageView 完全填充,圖像可能會(huì)被裁減掉一部分邻耕。Glide 中的CenterCrop 繼承自 BitmapTransformation 類 (靜態(tài)圖像的變換類型都是繼承BitmapTransformation)鸥咖。 主要實(shí)現(xiàn)了transform 方法,在transform方法中完成對(duì)圖像裁剪的計(jì)算和處理兄世。另外還實(shí)現(xiàn)了getId方法啼辣,用來(lái)區(qū)分不同的變換類型。我們繼續(xù)看transform方法御滩,transform方法中共傳入四個(gè)參數(shù)鸥拧,分別是用于bitmap復(fù)用的bitmapool,圖像變換前的原圖 toTransform, 指定的變換后的圖像寬高(可以通過(guò)override方法來(lái)設(shè)置)。在centercrop變換中削解,首先從bitmappool中取出一個(gè)可復(fù)用的bitmap富弦,用于保存變換后的bitmap,(這里穿插一句氛驮,為了防止頻繁創(chuàng)建bitmap對(duì)象而產(chǎn)生大量的內(nèi)存消耗腕柜,Glide中使用 bitmappool來(lái)對(duì)bitmap進(jìn)行復(fù)用,在平時(shí)對(duì)bitmap的使用中,從內(nèi)存優(yōu)化的角度我們可以借鑒這一做法)盏缤,然后將這些參數(shù)傳入TransformationUtils.centerCrop 方法砰蠢,在這里面根據(jù)設(shè)置的尺寸及圖像原始寬高進(jìn)行計(jì)算,完成的圖像裁切功能蛾找,如下源碼所示:
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();
// 根據(jù)原圖尺寸及所需要展示的尺寸進(jìn)行裁剪位置計(jì)算
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;
}
圖像變換開(kāi)源庫(kù)
由此可見(jiàn)赵誓,實(shí)現(xiàn)一個(gè)圖像變換器打毛,只需要繼承BitmapTransformation 類 (靜態(tài)圖像的變換類型都是繼承BitmapTransformation)。 實(shí)現(xiàn)transform 方法和getid方法俩功。圖片變換的需求多種多樣幻枉,如果我們想要豐富的圖像展示效果,也不必全部自己來(lái)研究圖像處理算法實(shí)現(xiàn)诡蜓。目前已經(jīng)有非常多Glide圖片變換的開(kāi)源庫(kù)可以直接使用熬甫,比較全面的是glide-transformations這個(gè)庫(kù),實(shí)現(xiàn)了非常豐富的圖片變換效果蔓罚,例如裁剪變換椿肩、顏色變換、模糊變換等等豺谈,glide-transformations的GitHub地址是 https://github.com/wasabeef/glide-transformations 郑象。這可以看一下部分效果:
這個(gè)庫(kù)的使用也非常簡(jiǎn)單,在app/build.gradle文件當(dāng)中添加如下依賴:
dependencies {
compile 'jp.wasabeef:glide-transformations:2.0.2'
}
然后就可以開(kāi)心的玩耍了茬末,例如對(duì)圖像進(jìn)行模糊處理只需如下代碼即可:
Glide.with(this)
.load(url)
.transform(new BlurTransformation(this,20))
.into(imageView);
使用圖像顏色濾鏡效果:
Glide.with(this)
.load(url)
.transform(new ColorFilterTransformation(this, 0x7900CCCC))
.into(imageView);
至此對(duì)Glide圖像變換這一部分的內(nèi)容就講解完了厂榛,對(duì)自定義圖像變換模塊以及如何使用圖像變換功能進(jìn)行了詳細(xì)的介紹。后續(xù)我們會(huì)繼續(xù)深入介紹Glide關(guān)鍵模塊知識(shí)丽惭,歡迎繼續(xù)關(guān)注击奶。