1. 背景
在使用Glide4.X 的时候,经常会使用到图片变换的情况,都是网上搜索一番,Ctrl + C + Ctrl + V ,没有系统地去看过这一块东西,网上的资料也很零散,有时候遇到一些较复杂的情况,得搜索好久才能得到自己想要的结果。出现这个痛点后,现准备针对Transformation 罗列记录一下。
本文Glide版本为4.13.2
implementation 'com.github.bumptech.glide:glide:4.13.2'
annotationProcessor 'com.github.bumptech.glide:compiler:4.13.2'
文中的布局是一个固定宽高300*300 的ImageView
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/image_view"
android:layout_width="300dp"
android:layout_height="300dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
正常显示photo1 效果如下 
2. Transformation是什么
Transformation(转换器),这个类可以说是 Glide 压缩裁剪图片的核心类,因为该类功能就是依据要求输出的宽高对原始资源进行压缩裁剪之类的转换
public interface Transformation<T> extends Key {
Resource<T> transform(@NonNull Context context, @NonNull Resource<T> resource,
int outWidth, int outHeight);
}
3. Glide自带的Transformations
我们使用Android Studio 自带的Hierarchy 工具,可以查看到,实现Transformations 接口的类总共有这些 
Hierarchy 工具的具体使用,详见我的另一篇博客 : Android Studio 使用 自带的Hierarchy查看类/方法/调用的层级关系
3.1 BitmapTransformation
BitmapTransformation 有很多子类,这里是我们关注的重点
3.1.1 CenterCrop、fitCenter和CenterInside
其中,Glide中的CenterCrop 、fitCenter 、CenterInside 和ImageView的scale type 有对应关系,对照关系如下
Glide | ImageView的scaleType |
---|
CenterCrop | centerCrop | fitCenter | fitCenter | CenterInside | centerInside 和 fitXY |
关于 ImageView scaleType 可以查看这篇文章 Android ImageView 的scaleType 属性图解
从代码中也可以看出这种对照关系 RequestBuilder#into()
@NonNull
public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
Util.assertMainThread();
Preconditions.checkNotNull(view);
BaseRequestOptions<?> requestOptions = this;
if (!requestOptions.isTransformationSet()
&& requestOptions.isTransformationAllowed()
&& view.getScaleType() != null) {
switch (view.getScaleType()) {
case CENTER_CROP:
requestOptions = requestOptions.clone().optionalCenterCrop();
break;
case CENTER_INSIDE:
requestOptions = requestOptions.clone().optionalCenterInside();
break;
case FIT_CENTER:
case FIT_START:
case FIT_END:
requestOptions = requestOptions.clone().optionalFitCenter();
break;
case FIT_XY:
requestOptions = requestOptions.clone().optionalCenterInside();
break;
case CENTER:
case MATRIX:
default:
}
}
3.1.2 CircleCrop
这个就是对图片裁剪为圆形
Glide.with(this)
.load(R.drawable.photo1)
.circleCrop()
.into(imageView)
效果如下 
3.1.3 Rotate
这个就是对图片进行旋转操作
Glide.with(this)
.load(R.drawable.photo1)
.transform(Rotate(90))
.into(imageView)

3.1.4 RoundedCorners
这个是对图片进行圆角操作
Glide.with(this)
.load(R.drawable.photo1)
.transform(RoundedCorners(ConvertUtils.dp2px(30F)))
.into(imageView)
效果如下 
3.1.5 GranularRoundedCorners
这个是当上下左右四个圆角值不一样的时候,对每个圆角的值进行定义
val radius30 = ConvertUtils.dp2px(30F).toFloat()
val radius5 = ConvertUtils.dp2px(5F).toFloat()
Glide.with(this)
.load(R.drawable.photo1)
.transform(GranularRoundedCorners(radius30, radius5, radius30, radius5))
.into(imageView)
效果如下 
3.2 MultiTransformation 多重变换
默认情况下,每个 transform() 调用,或任何特定转换方法fitCenter(), centerCrop(), bitmapTransform() 的调用都会替换掉之前的变换。 如果想在单次加载中应用多个变换,需要使用使用 MultiTransformation 类。
Glide.with(this)
.load(R.drawable.photo1)
.transform(MultiTransformation(CenterCrop(),Rotate(90)))
.into(imageView)
效果如下 
3.3 其他自带的Transformation
3.3.1. UnitTransformation
不做任何处理,直接返回
@NonNull
@Override
public Resource<T> transform(
@NonNull Context context, @NonNull Resource<T> resource, int outWidth, int outHeight) {
return resource;
}
3.3.2 DrawableTransformation
将Bitmap转化为Drawable,在源码里有用到,我们一般不会去调用。
3.3.3 BitmapDrawableTransformation
注解上说已弃用,建议使用DrawableTransformation
4. Transformation扩展 : glide-transformations
Github上有一个Glide的Transformation 库,glide-transformations,提供了一些额外的Transformation
需要添加如下依赖
implementation 'jp.wasabeef:glide-transformations:4.3.0'
implementation 'jp.co.cyberagent.android:gpuimage:2.1.0'
4.1 Mask
Glide.with(context)
.load(R.drawable.photo1)
.apply(overrideOf(266.px, 252.px))
.apply(bitmapTransform(MultiTransformation<Bitmap>(CenterCrop(),
MaskTransformation(R.drawable.mask_starfish))))
.into(holder.image)

4.2 NinePatchMask
Glide.with(context)
.load(R.drawable.photo1)
.apply(overrideOf(300.px, 200.px))
.apply(bitmapTransform(MultiTransformation<Bitmap>(CenterCrop(),
MaskTransformation(R.drawable.mask_chat_right))))
.into(holder.image)

4.3 RoundedCorners
Glide.with(context)
.load(R.drawable.photo1)
.apply(bitmapTransform(RoundedCornersTransformation(120, 0,
RoundedCornersTransformation.CornerType.DIAGONAL_FROM_TOP_LEFT)))
.into(holder.image)

4.4 CropTop
Glide.with(context)
.load(R.drawable.photo1)
.apply(bitmapTransform(CropTransformation(300.px, 100.px, CropType.TOP)))
.into(holder.image)

4.5 CropCenter
Glide.with(context)
.load(R.drawable.photo1)
.apply(bitmapTransform(CropTransformation(300.px, 100.px, CropType.CENTER)))
.into(holder.image)

4.6 CropBottom
Glide.with(context)
.load(R.drawable.photo1)
.apply(bitmapTransform(CropTransformation(300.px, 100.px, CropType.BOTTOM)))
.into(holder.image)

4.7 CropSquare
Glide.with(context)
.load(R.drawable.photo1)
.apply(bitmapTransform(CropSquareTransformation()))
.into(holder.image)

4.8 CropCircle
Glide.with(context)
.load(R.drawable.photo1)
.apply(bitmapTransform(CropCircleTransformation()))
.into(holder.image)

4.9 CropCircleWithBorder
Glide.with(context)
.load(R.drawable.photo1)
.apply(bitmapTransform(
CropCircleWithBorderTransformation(Utils.toDp(4), Color.rgb(0, 145, 86))))
.into(holder.image)

4.10 Grayscale
Glide.with(context)
.load(R.drawable.photo1)
.apply(bitmapTransform(GrayscaleTransformation()))
.into(holder.image)

4.11 BlurLight
Glide.with(context)
.load(R.drawable.photo1)
.apply(bitmapTransform(BlurTransformation(25)))
.into(holder.image)

4.12 BlurDeep
Glide.with(context)
.load(R.drawable.photo1)
.apply(bitmapTransform(BlurTransformation(25, 8)))
.into(holder.image)

4.13 Toon
Glide.with(context)
.load(R.drawable.photo1)
.apply(bitmapTransform(ToonFilterTransformation()))
.into(holder.image)

4.14 Sepia
Glide.with(context)
.load(R.drawable.photo1)
.apply(bitmapTransform(SepiaFilterTransformation()))
.into(holder.image)

4.15 Contrast
Glide.with(context)
.load(R.drawable.check)
.apply(bitmapTransform(ContrastFilterTransformation(2.0f)))
.into(holder.image)

4.16 Invert
Glide.with(context)
.load(R.drawable.photo1)
.apply(bitmapTransform(ContrastFilterTransformation(2.0f)))
.into(holder.image)

4.17 Pixel
Glide.with(context)
.load(R.drawable.photo1)
.apply(bitmapTransform(PixelationFilterTransformation(20f)))
.into(holder.image)

4.18 Sketch
Glide.with(context)
.load(R.drawable.photo1)
.apply(bitmapTransform(SketchFilterTransformation()))
.into(holder.image)

4.19 Swirl
Glide.with(context)
.load(R.drawable.photo1)
.apply(bitmapTransform(
SwirlFilterTransformation(0.5f, 1.0f, PointF(0.5f, 0.5f))).dontAnimate())
.into(holder.image)

4.20 Brightness
Glide.with(context)
.load(R.drawable.photo1)
.apply(bitmapTransform(BrightnessFilterTransformation(0.5f)).dontAnimate())
.into(holder.image)

4.21 Kuawahara
Glide.with(context)
.load(R.drawable.photo1)
.apply(bitmapTransform(KuwaharaFilterTransformation(25)).dontAnimate())
.into(holder.image)

4.22 Vignette
Glide.with(context)
.load(R.drawable.photo1)
.apply(bitmapTransform(VignetteFilterTransformation(PointF(0.5f, 0.5f),
floatArrayOf(0.0f, 0.0f, 0.0f), 0f, 0.75f)).dontAnimate())
.into(holder.image)

5. 自定义Transformation
如果常用的Transformation 满足不了我们的需要,也可以自定义Transformation 如果只需要变换 Bitmap,最好是从继承 BitmapTransformation 开始。BitmapTransformation 为我们处理了一些基础的东西,例如,如果变换返回了一个新修改的 Bitmap ,BitmapTransformation 将负责提取和回收原始的 Bitmap。 比如,我们自己去实现一个旋转图片的Transformation
class RotateTransformation(private val angle: Float) : BitmapTransformation() {
override fun updateDiskCacheKey(messageDigest: MessageDigest) {
}
override fun transform(
pool: BitmapPool,
toTransform: Bitmap,
outWidth: Int,
outHeight: Int
): Bitmap {
val matrix = Matrix()
matrix.postRotate(angle)
return Bitmap.createBitmap(
toTransform,
0,
0,
toTransform.width,
toTransform.height,
matrix,
true
)
}
}
进行使用
Glide.with(this)
.load(R.mipmap.photo1)
.apply(bitmapTransform(RotateTransformation(90F)))
.into(imageView)
效果如下 
6. 其他
参考 Glide V4 : 变换 Glide 的 transformation
|