Glide提供了多种默认的图形变换,如centerCrop(中心剪裁,同imageview的scaletype)等,可以通过在链式语法中加入transform(BitmapTransmation)来设置图片的变换。centerCrop实际上就是调用transform(new CenterCrop)。那先来看看这个centerCrop,直接继承自BitmapTransmation,核心方法就一个:
@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 transformed = TransformationUtils.centerCrop(toReuse, toTransform, outWidth, outHeight);
if (toReuse != null && toReuse != transformed && !pool.put(toReuse)) {
toReuse.recycle();
}
return transformed;
}
首先从Bitmap缓存池中取出一个目标宽高的可用的Bitmap(为了节省创建bitmap的开销,可能为null),然后交由TransformationUtils去完成图片变换,最后看这个bitmap能否回收。
看看这个执行变换的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;
}
// From ImageView/Bitmap.createScaledBitmap.
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));
}
// We don't add or remove alpha, so keep the alpha setting of the Bitmap we were given.
TransformationUtils.setAlpha(toCrop, result);
Canvas canvas = new Canvas(result);
Paint paint = new Paint(PAINT_FLAGS);
canvas.drawBitmap(toCrop, m, paint);
return result;
}
主要借助了Matrix设置缩放比和原图中可用部分的起始坐标,然后drawBitmap把原图画到结果bitmap的画布上。
首先判断原图和目标图的宽高比,如果原图比较胖则取result.height/beforeHeight作为缩放比,接下来再计算原图中起始点的坐标就可以了。
我们想要的效果是
照葫芦画瓢,我们也来自定义一个CircleTrans继承BitmapTransmation,getId方法随便返回一个字符串作为本转换的唯一标识即可,主要是对transform的实现:
@Override
protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {
//从缓存池中取出一个bitmap
final Bitmap toReuse = pool.get(outWidth, outHeight, Bitmap.Config.ARGB_8888);
final Bitmap result;
if (toReuse != null) {
result = toReuse;
} else {
result = Bitmap.createBitmap(outWidth, outHeight, Bitmap.Config.ARGB_8888);
}
//目标圆的半径
float radious=Math.min(outHeight,outWidth)/2;
//计算缩放比和原图中的起始坐标
final float scale;
float dx=0,dy=0;
if (toTransform.getWidth()>toTransform.getHeight()){
scale=(float) outHeight/(float) toTransform.getHeight();
dx=(toTransform.getWidth()-toTransform.getHeight())*0.5f;
} else {
scale=(float) outWidth/(float) toTransform.getWidth();
dy=(toTransform.getHeight()-toTransform.getWidth())*0.5f;
}
Matrix matrix=new Matrix();
matrix.setScale(scale,scale);
matrix.postTranslate((int)(dx+0.5f),(int)(dy+0.5f));
Canvas canvas = new Canvas(result);
Paint paint = new Paint();
//后面参数表示边缘复制
BitmapShader shader = new BitmapShader(toTransform, BitmapShader.TileMode.CLAMP,
BitmapShader.TileMode.CLAMP);
shader.setLocalMatrix(matrix);
paint.setShader(shader);
paint.setAntiAlias(true);//抗锯齿
//绘制,可以看到主要还是对画笔的设置,将原图按矩阵缩放并设置起始点后交给画笔。
canvas.drawCircle(outWidth/2, outHeight/2, radious, paint);
//判断能否回收Bitmap
if (toReuse != null && !pool.put(toReuse)) {
toReuse.recycle();
}
return result;
}
写的应该是比较清楚了,借助矩阵将原图缩放并设置起始位置,这时他在我们眼里相当于一个边长为min(outWidth,outHeight)的正方形,然后交给画笔作为圆形画到目标bitmap的画布上就可以了。
使用:
Glide.with(this)
.load(path)
.transform(new CircleTrans(this))
.into(iv);
效果很理想(宽match_parent,高200dp):